diff --git a/.editorconfig b/.editorconfig index 0bbaa114..c645b573 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,21 +1,31 @@ - -[*.proto] -indent_style=tab -indent_size=tab -tab_width=4 - -[*.{asax,ascx,aspx,axaml,cs,cshtml,css,htm,html,js,jsx,master,paml,razor,skin,ts,tsx,vb,xaml,xamlx,xoml}] -indent_style=space -indent_size=4 -tab_width=4 - -[*.{appxmanifest,axml,build,config,csproj,dbml,discomap,dtd,json,jsproj,lsproj,njsproj,nuspec,proj,props,resjson,resw,resx,StyleCop,targets,tasks,vbproj,xml,xsd}] -indent_style=space -indent_size=2 -tab_width=2 +# Standard properties +charset = utf-8 +end_of_line = lf +insert_final_newline = true +csharp_indent_labels = one_less_than_current +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_braces = true:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +csharp_style_throw_expression = true:suggestion +csharp_style_prefer_null_check_over_type_check = true:suggestion +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_prefer_local_over_anonymous_function = true:suggestion +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_range_operator = true:suggestion +csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion +csharp_style_prefer_tuple_swap = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_prefer_top_level_statements = true:silent [*] - # Microsoft .NET properties csharp_indent_braces=false csharp_indent_switch_labels=true @@ -3567,30 +3577,6 @@ resharper_xaml_x_key_attribute_disallowed_highlighting=error resharper_xml_doc_comment_syntax_problem_highlighting=warning resharper_xunit_xunit_test_with_console_output_highlighting=warning -# Standard properties -end_of_line= crlf -csharp_indent_labels = one_less_than_current -csharp_prefer_simple_using_statement = true:suggestion -csharp_prefer_braces = true:silent -csharp_style_prefer_method_group_conversion = true:silent -csharp_style_expression_bodied_methods = false:silent -csharp_style_expression_bodied_constructors = false:silent -csharp_style_expression_bodied_operators = false:silent -csharp_style_expression_bodied_properties = true:silent -csharp_style_expression_bodied_indexers = true:silent -csharp_style_expression_bodied_accessors = true:silent -csharp_style_expression_bodied_lambdas = true:silent -csharp_style_expression_bodied_local_functions = false:silent -csharp_style_throw_expression = true:suggestion -csharp_style_prefer_null_check_over_type_check = true:suggestion -csharp_prefer_simple_default_expression = true:suggestion -csharp_style_prefer_local_over_anonymous_function = true:suggestion -csharp_style_prefer_index_operator = true:suggestion -csharp_style_prefer_range_operator = true:suggestion -csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion -csharp_style_prefer_tuple_swap = true:suggestion -csharp_style_inlined_variable_declaration = true:suggestion - [*.{cshtml,htm,html,proto,razor}] indent_style=tab indent_size=tab @@ -3601,6 +3587,21 @@ indent_style=space indent_size=4 tab_width=4 +[ "*.proto" ] +indent_style=tab +indent_size=tab +tab_width=4 + +[*.{asax,ascx,aspx,axaml,cs,cshtml,css,htm,html,js,jsx,master,paml,razor,skin,ts,tsx,vb,xaml,xamlx,xoml}] +indent_style=space +indent_size=4 +tab_width=4 + +[*.{appxmanifest,axml,build,config,csproj,dbml,discomap,dtd,json,jsproj,lsproj,njsproj,nuspec,proj,props,resjson,resw,resx,StyleCop,targets,tasks,vbproj,xml,xsd}] +indent_style=space +indent_size=2 +tab_width=2 + [*.{appxmanifest,asax,ascx,aspx,axaml,axml,build,c,c++,cc,cginc,compute,config,cp,cpp,cs,cshtml,csproj,css,cu,cuh,cxx,dbml,discomap,dtd,h,hh,hlsl,hlsli,hlslinc,hpp,htm,html,hxx,inc,inl,ino,ipp,js,json,jsproj,jsx,lsproj,master,mpp,mq4,mq5,mqh,njsproj,nuspec,paml,proj,props,proto,razor,resjson,resw,resx,skin,StyleCop,targets,tasks,tpp,ts,tsx,usf,ush,vb,vbproj,xaml,xamlx,xml,xoml,xsd}] indent_style=space indent_size= 4 @@ -3621,3 +3622,4 @@ dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion dotnet_style_prefer_compound_assignment = true:suggestion dotnet_style_prefer_simplified_interpolation = true:suggestion dotnet_style_namespace_match_folder = true:suggestion +insert_final_newline = true diff --git a/Penumbra.Api b/Penumbra.Api index 316f3da4..22846625 160000 --- a/Penumbra.Api +++ b/Penumbra.Api @@ -1 +1 @@ -Subproject commit 316f3da4a3ce246afe5b98c1568d73fcd7b6b22d +Subproject commit 22846625192884c6e9f5ec4429fb579875b519e9 diff --git a/Penumbra.GameData b/Penumbra.GameData index 0507b1f0..f004e069 160000 --- a/Penumbra.GameData +++ b/Penumbra.GameData @@ -1 +1 @@ -Subproject commit 0507b1f093f5382e03242e5da991752361b70c6e +Subproject commit f004e069824a1588244e06080b32bab170f78077 diff --git a/Penumbra.String b/Penumbra.String index 0e0c1e1e..620a7edf 160000 --- a/Penumbra.String +++ b/Penumbra.String @@ -1 +1 @@ -Subproject commit 0e0c1e1ee116c259abd00e1d5c3450ad40f92a98 +Subproject commit 620a7edf009b92288257ce7d64fffb8fba44d8b5 diff --git a/Penumbra/Api/PenumbraApi.cs b/Penumbra/Api/PenumbraApi.cs index 1dead7e5..73a87fab 100644 --- a/Penumbra/Api/PenumbraApi.cs +++ b/Penumbra/Api/PenumbraApi.cs @@ -633,7 +633,8 @@ public class PenumbraApi : IDisposable, IPenumbraApi _modManager.AddMod(dir); if (_config.UseFileSystemCompression) - new FileCompactor(Penumbra.Log).StartMassCompact(dir.EnumerateFiles("*.*", SearchOption.AllDirectories), CompressionAlgorithm.Xpress8K); + new FileCompactor(Penumbra.Log).StartMassCompact(dir.EnumerateFiles("*.*", SearchOption.AllDirectories), + CompressionAlgorithm.Xpress8K); return PenumbraApiEc.Success; } diff --git a/Penumbra/Api/TempModManager.cs b/Penumbra/Api/TempModManager.cs index 35aa1217..efbfd7f9 100644 --- a/Penumbra/Api/TempModManager.cs +++ b/Penumbra/Api/TempModManager.cs @@ -25,7 +25,7 @@ public class TempModManager : IDisposable public TempModManager(CommunicatorService communicator) { - _communicator = communicator; + _communicator = communicator; _communicator.CollectionChange.Subscribe(OnCollectionChange, CollectionChange.Priority.TempModManager); } @@ -43,7 +43,7 @@ public class TempModManager : IDisposable public RedirectResult Register(string tag, ModCollection? collection, Dictionary dict, HashSet manips, int priority) { - var mod = GetOrCreateMod(tag, collection, priority, out var created); + var mod = GetOrCreateMod(tag, collection, priority, out var created); Penumbra.Log.Verbose($"{(created ? "Created" : "Changed")} temporary Mod {mod.Name}."); mod.SetAll(dict, manips); ApplyModChange(mod, collection, created, false); @@ -56,7 +56,7 @@ public class TempModManager : IDisposable var list = collection == null ? _modsForAllCollections : _mods.TryGetValue(collection, out var l) ? l : null; if (list == null) return RedirectResult.NotRegistered; - + var removed = list.RemoveAll(m => { if (m.Name != tag || priority != null && m.Priority != priority.Value) diff --git a/Penumbra/Collections/Cache/CollectionCache.cs b/Penumbra/Collections/Cache/CollectionCache.cs index 6f3d59e9..80539d96 100644 --- a/Penumbra/Collections/Cache/CollectionCache.cs +++ b/Penumbra/Collections/Cache/CollectionCache.cs @@ -6,6 +6,7 @@ using Penumbra.Api.Enums; using Penumbra.Communication; using Penumbra.String.Classes; using Penumbra.Mods.Manager; +using Penumbra.Mods.Subclasses; namespace Penumbra.Collections.Cache; @@ -270,14 +271,14 @@ public class CollectionCache : IDisposable foreach (var manip in subMod.Manipulations) AddManipulation(manip, parentMod); } - - /// Invoke only if not in a full recalculation. + + /// Invoke only if not in a full recalculation. private void InvokeResolvedFileChange(ModCollection collection, ResolvedFileChanged.Type type, Utf8GamePath key, FullPath value, FullPath old, IMod? mod) { if (Calculating == -1) _manager.ResolvedFileChanged.Invoke(collection, type, key, value, old, mod); - } + } // Add a specific file redirection, handling potential conflicts. // For different mods, higher mod priority takes precedence before option group priority, @@ -292,7 +293,7 @@ public class CollectionCache : IDisposable { if (ResolvedFiles.TryAdd(path, new ModPath(mod, file))) { - ModData.AddPath(mod, path); + ModData.AddPath(mod, path); InvokeResolvedFileChange(_collection, ResolvedFileChanged.Type.Added, path, file, FullPath.Empty, mod); return; } diff --git a/Penumbra/Collections/Cache/CollectionCacheManager.cs b/Penumbra/Collections/Cache/CollectionCacheManager.cs index 3a94bc89..5daecaa9 100644 --- a/Penumbra/Collections/Cache/CollectionCacheManager.cs +++ b/Penumbra/Collections/Cache/CollectionCacheManager.cs @@ -1,4 +1,3 @@ -using System.Collections.Concurrent; using Dalamud.Game; using OtterGui.Classes; using Penumbra.Api; diff --git a/Penumbra/Collections/Cache/EqdpCache.cs b/Penumbra/Collections/Cache/EqdpCache.cs index a5232dbb..3937fa72 100644 --- a/Penumbra/Collections/Cache/EqdpCache.cs +++ b/Penumbra/Collections/Cache/EqdpCache.cs @@ -45,7 +45,7 @@ public readonly struct EqdpCache : IDisposable foreach (var file in _eqdpFiles.OfType()) { var relevant = CharacterUtility.RelevantIndices[file.Index.Value]; - file.Reset(_eqdpManipulations.Where(m => m.FileIndex() == relevant).Select(m => (SetId) m.SetId)); + file.Reset(_eqdpManipulations.Where(m => m.FileIndex() == relevant).Select(m => (SetId)m.SetId)); } _eqdpManipulations.Clear(); diff --git a/Penumbra/Collections/Cache/EqpCache.cs b/Penumbra/Collections/Cache/EqpCache.cs index 9d63479a..972ee5a5 100644 --- a/Penumbra/Collections/Cache/EqpCache.cs +++ b/Penumbra/Collections/Cache/EqpCache.cs @@ -9,20 +9,20 @@ namespace Penumbra.Collections.Cache; public struct EqpCache : IDisposable { - private ExpandedEqpFile? _eqpFile = null; - private readonly List< EqpManipulation > _eqpManipulations = new(); - - public EqpCache() - {} + private ExpandedEqpFile? _eqpFile = null; + private readonly List _eqpManipulations = new(); - public void SetFiles(MetaFileManager manager) - => manager.SetFile( _eqpFile, MetaIndex.Eqp ); + public EqpCache() + { } + + public void SetFiles(MetaFileManager manager) + => manager.SetFile(_eqpFile, MetaIndex.Eqp); public static void ResetFiles(MetaFileManager manager) - => manager.SetFile( null, MetaIndex.Eqp ); + => manager.SetFile(null, MetaIndex.Eqp); public MetaList.MetaReverter TemporarilySetFiles(MetaFileManager manager) - => manager.TemporarilySetFile( _eqpFile, MetaIndex.Eqp ); + => manager.TemporarilySetFile(_eqpFile, MetaIndex.Eqp); public void Reset() { @@ -31,25 +31,24 @@ public struct EqpCache : IDisposable _eqpFile.Reset(_eqpManipulations.Select(m => m.SetId)); _eqpManipulations.Clear(); - } - - public bool ApplyMod( MetaFileManager manager, EqpManipulation manip ) - { - _eqpManipulations.AddOrReplace( manip ); - _eqpFile ??= new ExpandedEqpFile(manager); - return manip.Apply( _eqpFile ); } - public bool RevertMod( MetaFileManager manager, EqpManipulation manip ) + public bool ApplyMod(MetaFileManager manager, EqpManipulation manip) { - var idx = _eqpManipulations.FindIndex( manip.Equals ); + _eqpManipulations.AddOrReplace(manip); + _eqpFile ??= new ExpandedEqpFile(manager); + return manip.Apply(_eqpFile); + } + + public bool RevertMod(MetaFileManager manager, EqpManipulation manip) + { + var idx = _eqpManipulations.FindIndex(manip.Equals); if (idx < 0) return false; - var def = ExpandedEqpFile.GetDefault( manager, manip.SetId ); - manip = new EqpManipulation( def, manip.Slot, manip.SetId ); - return manip.Apply( _eqpFile! ); - + var def = ExpandedEqpFile.GetDefault(manager, manip.SetId); + manip = new EqpManipulation(def, manip.Slot, manip.SetId); + return manip.Apply(_eqpFile!); } public void Dispose() @@ -58,4 +57,4 @@ public struct EqpCache : IDisposable _eqpFile = null; _eqpManipulations.Clear(); } -} \ No newline at end of file +} diff --git a/Penumbra/Collections/Cache/GmpCache.cs b/Penumbra/Collections/Cache/GmpCache.cs index 3287eb2d..0a713867 100644 --- a/Penumbra/Collections/Cache/GmpCache.cs +++ b/Penumbra/Collections/Cache/GmpCache.cs @@ -9,42 +9,42 @@ namespace Penumbra.Collections.Cache; public struct GmpCache : IDisposable { - private ExpandedGmpFile? _gmpFile = null; - private readonly List< GmpManipulation > _gmpManipulations = new(); - + private ExpandedGmpFile? _gmpFile = null; + private readonly List _gmpManipulations = new(); + public GmpCache() - {} + { } public void SetFiles(MetaFileManager manager) - => manager.SetFile( _gmpFile, MetaIndex.Gmp ); + => manager.SetFile(_gmpFile, MetaIndex.Gmp); public MetaList.MetaReverter TemporarilySetFiles(MetaFileManager manager) - => manager.TemporarilySetFile( _gmpFile, MetaIndex.Gmp ); + => manager.TemporarilySetFile(_gmpFile, MetaIndex.Gmp); public void Reset() { - if( _gmpFile == null ) + if (_gmpFile == null) return; - _gmpFile.Reset( _gmpManipulations.Select( m => m.SetId ) ); + _gmpFile.Reset(_gmpManipulations.Select(m => m.SetId)); _gmpManipulations.Clear(); } - public bool ApplyMod( MetaFileManager manager, GmpManipulation manip ) + public bool ApplyMod(MetaFileManager manager, GmpManipulation manip) { - _gmpManipulations.AddOrReplace( manip ); + _gmpManipulations.AddOrReplace(manip); _gmpFile ??= new ExpandedGmpFile(manager); - return manip.Apply( _gmpFile ); + return manip.Apply(_gmpFile); } - public bool RevertMod( MetaFileManager manager, GmpManipulation manip ) + public bool RevertMod(MetaFileManager manager, GmpManipulation manip) { if (!_gmpManipulations.Remove(manip)) return false; - var def = ExpandedGmpFile.GetDefault( manager, manip.SetId ); - manip = new GmpManipulation( def, manip.SetId ); - return manip.Apply( _gmpFile! ); + var def = ExpandedGmpFile.GetDefault(manager, manip.SetId); + manip = new GmpManipulation(def, manip.SetId); + return manip.Apply(_gmpFile!); } public void Dispose() @@ -53,4 +53,4 @@ public struct GmpCache : IDisposable _gmpFile = null; _gmpManipulations.Clear(); } -} \ No newline at end of file +} diff --git a/Penumbra/Collections/Cache/ImcCache.cs b/Penumbra/Collections/Cache/ImcCache.cs index e226b409..05756e12 100644 --- a/Penumbra/Collections/Cache/ImcCache.cs +++ b/Penumbra/Collections/Cache/ImcCache.cs @@ -44,9 +44,9 @@ public readonly struct ImcCache : IDisposable if (idx < 0) { idx = _imcManipulations.Count; - _imcManipulations.Add((manip, null!)); - } - + _imcManipulations.Add((manip, null!)); + } + var path = manip.GamePath(); try { @@ -79,13 +79,13 @@ public readonly struct ImcCache : IDisposable public bool RevertMod(MetaFileManager manager, ModCollection collection, ImcManipulation m) { if (!m.Validate()) - return false; - + return false; + var idx = _imcManipulations.FindIndex(p => p.Item1.Equals(m)); if (idx < 0) return false; - var (_, file) = _imcManipulations[idx]; + var (_, file) = _imcManipulations[idx]; _imcManipulations.RemoveAt(idx); if (_imcManipulations.All(p => !ReferenceEquals(p.Item2, file))) @@ -94,8 +94,8 @@ public readonly struct ImcCache : IDisposable collection._cache!.ForceFile(file.Path, FullPath.Empty); file.Dispose(); return true; - } - + } + var def = ImcFile.GetDefault(manager, file.Path, m.EquipSlot, m.Variant.Id, out _); var manip = m.Copy(def); if (!manip.Apply(file)) diff --git a/Penumbra/Collections/Cache/MetaCache.cs b/Penumbra/Collections/Cache/MetaCache.cs index fa60993a..d2dd48f8 100644 --- a/Penumbra/Collections/Cache/MetaCache.cs +++ b/Penumbra/Collections/Cache/MetaCache.cs @@ -136,7 +136,7 @@ public class MetaCache : IDisposable, IEnumerable false, }; } - + /// Set a single file. public void SetFile(MetaIndex metaIndex) { @@ -162,7 +162,7 @@ public class MetaCache : IDisposable, IEnumerable Set the currently relevant IMC files for the collection cache. public void SetImcFiles(bool fromFullCompute) => _imcCache.SetFiles(_collection, fromFullCompute); @@ -171,7 +171,7 @@ public class MetaCache : IDisposable, IEnumerable _eqpCache.TemporarilySetFiles(_manager); public MetaList.MetaReverter TemporarilySetEqdpFile(GenderRace genderRace, bool accessory) - => _eqdpCache.TemporarilySetFiles(_manager, genderRace, accessory); + => _eqdpCache.TemporarilySetFiles(_manager, genderRace, accessory); public MetaList.MetaReverter TemporarilySetGmpFile() => _gmpCache.TemporarilySetFiles(_manager); @@ -180,7 +180,7 @@ public class MetaCache : IDisposable, IEnumerable _cmpCache.TemporarilySetFiles(_manager); public MetaList.MetaReverter TemporarilySetEstFile(EstManipulation.EstType type) - => _estCache.TemporarilySetFiles(_manager, type); + => _estCache.TemporarilySetFiles(_manager, type); /// Try to obtain a manipulated IMC file. diff --git a/Penumbra/Collections/Manager/ActiveCollectionMigration.cs b/Penumbra/Collections/Manager/ActiveCollectionMigration.cs index 5fcfd2f9..5872dea1 100644 --- a/Penumbra/Collections/Manager/ActiveCollectionMigration.cs +++ b/Penumbra/Collections/Manager/ActiveCollectionMigration.cs @@ -16,18 +16,18 @@ public static class ActiveCollectionMigration foreach (var (type, _, _) in CollectionTypeExtensions.Special.Where(t => t.Item2.StartsWith("Male "))) { var oldName = type.ToString()[4..]; - var value = jObject[oldName]; + var value = jObject[oldName]; if (value == null) continue; jObject.Remove(oldName); - jObject.Add("Male" + oldName, value); + jObject.Add("Male" + oldName, value); jObject.Add("Female" + oldName, value); } using var stream = File.Open(fileNames.ActiveCollectionsFile, FileMode.Truncate); using var writer = new StreamWriter(stream); - using var j = new JsonTextWriter(writer); + using var j = new JsonTextWriter(writer); j.Formatting = Formatting.Indented; jObject.WriteTo(j); } @@ -41,13 +41,14 @@ public static class ActiveCollectionMigration // Load character collections. If a player name comes up multiple times, the last one is applied. var characters = jObject["Characters"]?.ToObject>() ?? new Dictionary(); - var dict = new Dictionary(characters.Count); + var dict = new Dictionary(characters.Count); foreach (var (player, collectionName) in characters) { if (!storage.ByName(collectionName, out var collection)) { Penumbra.Chat.NotificationMessage( - $"Last choice of <{player}>'s Collection {collectionName} is not available, reset to {ModCollection.Empty.Name}.", "Load Failure", + $"Last choice of <{player}>'s Collection {collectionName} is not available, reset to {ModCollection.Empty.Name}.", + "Load Failure", NotificationType.Warning); dict.Add(player, ModCollection.Empty); } diff --git a/Penumbra/Collections/Manager/ActiveCollections.cs b/Penumbra/Collections/Manager/ActiveCollections.cs index 58eb7517..bae95885 100644 --- a/Penumbra/Collections/Manager/ActiveCollections.cs +++ b/Penumbra/Collections/Manager/ActiveCollections.cs @@ -442,6 +442,7 @@ public class ActiveCollections : ISavable, IDisposable var m = ByType(CollectionTypeExtensions.FromParts(race, Gender.Male, false)); if (m != null && m != yourself) return string.Empty; + var f = ByType(CollectionTypeExtensions.FromParts(race, Gender.Female, false)); if (f != null && f != yourself) return string.Empty; @@ -450,26 +451,28 @@ public class ActiveCollections : ISavable, IDisposable } var racialString = racial ? " and Racial Assignments" : string.Empty; - var @base = ByType(CollectionType.Default); - var male = ByType(CollectionType.MalePlayerCharacter); - var female = ByType(CollectionType.FemalePlayerCharacter); + var @base = ByType(CollectionType.Default); + var male = ByType(CollectionType.MalePlayerCharacter); + var female = ByType(CollectionType.FemalePlayerCharacter); if (male == yourself && female == yourself) return $"Assignment is redundant due to overwriting Male Players and Female Players{racialString} with an identical collection.\nYou can remove it."; - + if (male == null) { if (female == null && @base == yourself) - return $"Assignment is redundant due to overwriting Base{racialString} with an identical collection.\nYou can remove it."; + return + $"Assignment is redundant due to overwriting Base{racialString} with an identical collection.\nYou can remove it."; if (female == yourself && @base == yourself) return $"Assignment is redundant due to overwriting Base and Female Players{racialString} with an identical collection.\nYou can remove it."; } else if (male == yourself && female == null && @base == yourself) { - return $"Assignment is redundant due to overwriting Base and Male Players{racialString} with an identical collection.\nYou can remove it."; + return + $"Assignment is redundant due to overwriting Base and Male Players{racialString} with an identical collection.\nYou can remove it."; } - + break; // Check individual assignments. We can only be sure of redundancy for world-overlap or ownership overlap. case CollectionType.Individual: diff --git a/Penumbra/Collections/Manager/CollectionEditor.cs b/Penumbra/Collections/Manager/CollectionEditor.cs index 3d0ef60e..f0b4d509 100644 --- a/Penumbra/Collections/Manager/CollectionEditor.cs +++ b/Penumbra/Collections/Manager/CollectionEditor.cs @@ -2,6 +2,7 @@ using OtterGui; using Penumbra.Api.Enums; using Penumbra.Mods; using Penumbra.Mods.Manager; +using Penumbra.Mods.Subclasses; using Penumbra.Services; namespace Penumbra.Collections.Manager; diff --git a/Penumbra/Collections/Manager/CollectionStorage.cs b/Penumbra/Collections/Manager/CollectionStorage.cs index c172aeff..eb230e9e 100644 --- a/Penumbra/Collections/Manager/CollectionStorage.cs +++ b/Penumbra/Collections/Manager/CollectionStorage.cs @@ -5,6 +5,7 @@ using OtterGui.Filesystem; using Penumbra.Communication; using Penumbra.Mods; using Penumbra.Mods.Manager; +using Penumbra.Mods.Subclasses; using Penumbra.Services; namespace Penumbra.Collections.Manager; @@ -246,7 +247,7 @@ public class CollectionStorage : IReadOnlyList, IDisposable private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory, DirectoryInfo? newDirectory) { - switch (type) + switch (type) { case ModPathChangeType.Added: foreach (var collection in this) diff --git a/Penumbra/Collections/Manager/CollectionType.cs b/Penumbra/Collections/Manager/CollectionType.cs index 8e2d1aed..8c51fd90 100644 --- a/Penumbra/Collections/Manager/CollectionType.cs +++ b/Penumbra/Collections/Manager/CollectionType.cs @@ -427,13 +427,13 @@ public static class CollectionTypeExtensions public static string ToDescription(this CollectionType collectionType) => collectionType switch { - CollectionType.Default => "World, Music, Furniture, baseline for characters and monsters not specialized.", - CollectionType.Interface => "User Interface, Icons, Maps, Styles.", - CollectionType.Yourself => "Your characters, regardless of name, race or gender. Applies in the login screen.", - CollectionType.MalePlayerCharacter => "Baseline for male player characters.", - CollectionType.FemalePlayerCharacter => "Baseline for female player characters.", - CollectionType.MaleNonPlayerCharacter => "Baseline for humanoid male non-player characters.", + CollectionType.Default => "World, Music, Furniture, baseline for characters and monsters not specialized.", + CollectionType.Interface => "User Interface, Icons, Maps, Styles.", + CollectionType.Yourself => "Your characters, regardless of name, race or gender. Applies in the login screen.", + CollectionType.MalePlayerCharacter => "Baseline for male player characters.", + CollectionType.FemalePlayerCharacter => "Baseline for female player characters.", + CollectionType.MaleNonPlayerCharacter => "Baseline for humanoid male non-player characters.", CollectionType.FemaleNonPlayerCharacter => "Baseline for humanoid female non-player characters.", - _ => string.Empty, + _ => string.Empty, }; } diff --git a/Penumbra/Collections/Manager/IndividualCollections.Access.cs b/Penumbra/Collections/Manager/IndividualCollections.Access.cs index ac4acb8e..489e2f72 100644 --- a/Penumbra/Collections/Manager/IndividualCollections.Access.cs +++ b/Penumbra/Collections/Manager/IndividualCollections.Access.cs @@ -47,7 +47,8 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa return true; // Handle generic NPC - var npcIdentifier = _actorService.AwaitedService.CreateIndividualUnchecked(IdentifierType.Npc, ByteString.Empty, ushort.MaxValue, + var npcIdentifier = _actorService.AwaitedService.CreateIndividualUnchecked(IdentifierType.Npc, ByteString.Empty, + ushort.MaxValue, identifier.Kind, identifier.DataId); if (npcIdentifier.IsValid && _individuals.TryGetValue(npcIdentifier, out collection)) return true; @@ -56,7 +57,8 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa if (!_config.UseOwnerNameForCharacterCollection) return false; - identifier = _actorService.AwaitedService.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName, identifier.HomeWorld.Id, + identifier = _actorService.AwaitedService.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName, + identifier.HomeWorld.Id, ObjectKind.None, uint.MaxValue); return CheckWorlds(identifier, out collection); } @@ -142,7 +144,8 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa if (_individuals.TryGetValue(identifier, out collection)) return true; - identifier = _actorService.AwaitedService.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, ushort.MaxValue, identifier.Kind, + identifier = _actorService.AwaitedService.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, ushort.MaxValue, + identifier.Kind, identifier.DataId); if (identifier.IsValid && _individuals.TryGetValue(identifier, out collection)) return true; diff --git a/Penumbra/Collections/Manager/IndividualCollections.Files.cs b/Penumbra/Collections/Manager/IndividualCollections.Files.cs index da403337..21a0c730 100644 --- a/Penumbra/Collections/Manager/IndividualCollections.Files.cs +++ b/Penumbra/Collections/Manager/IndividualCollections.Files.cs @@ -27,6 +27,7 @@ public partial class IndividualCollections { if (_actorService.Valid) return ReadJObjectInternal(obj, storage); + void Func() { if (ReadJObjectInternal(obj, storage)) @@ -35,9 +36,10 @@ public partial class IndividualCollections Loaded.Invoke(); _actorService.FinishedCreation -= Func; } + _actorService.FinishedCreation += Func; return false; - } + } private bool ReadJObjectInternal(JArray? obj, CollectionStorage storage) { @@ -85,6 +87,7 @@ public partial class IndividualCollections NotificationType.Error); } } + return changes; } diff --git a/Penumbra/Collections/Manager/IndividualCollections.cs b/Penumbra/Collections/Manager/IndividualCollections.cs index e7547153..ed3c3d4b 100644 --- a/Penumbra/Collections/Manager/IndividualCollections.cs +++ b/Penumbra/Collections/Manager/IndividualCollections.cs @@ -132,7 +132,8 @@ public sealed partial class IndividualCollections _ => throw new NotImplementedException(), }; return table.Where(kvp => kvp.Value == name) - .Select(kvp => manager.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, identifier.HomeWorld.Id, identifier.Kind, + .Select(kvp => manager.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, identifier.HomeWorld.Id, + identifier.Kind, kvp.Key)).ToArray(); } diff --git a/Penumbra/Collections/Manager/ModCollectionMigration.cs b/Penumbra/Collections/Manager/ModCollectionMigration.cs index 56135182..025df9ef 100644 --- a/Penumbra/Collections/Manager/ModCollectionMigration.cs +++ b/Penumbra/Collections/Manager/ModCollectionMigration.cs @@ -1,5 +1,6 @@ using Penumbra.Mods; using Penumbra.Mods.Manager; +using Penumbra.Mods.Subclasses; using Penumbra.Services; using Penumbra.Util; diff --git a/Penumbra/Collections/ModCollection.Cache.Access.cs b/Penumbra/Collections/ModCollection.Cache.Access.cs index ae68a370..d788d0bd 100644 --- a/Penumbra/Collections/ModCollection.Cache.Access.cs +++ b/Penumbra/Collections/ModCollection.Cache.Access.cs @@ -92,7 +92,7 @@ public partial class ModCollection // Used for short periods of changed files. public MetaList.MetaReverter TemporarilySetEqdpFile(CharacterUtility utility, GenderRace genderRace, bool accessory) => _cache?.Meta.TemporarilySetEqdpFile(genderRace, accessory) - ?? utility.TemporarilyResetResource(Interop.Structs.CharacterUtilityData.EqdpIdx(genderRace, accessory)); + ?? utility.TemporarilyResetResource(CharacterUtilityData.EqdpIdx(genderRace, accessory)); public MetaList.MetaReverter TemporarilySetEqpFile(CharacterUtility utility) => _cache?.Meta.TemporarilySetEqpFile() @@ -109,4 +109,4 @@ public partial class ModCollection public MetaList.MetaReverter TemporarilySetEstFile(CharacterUtility utility, EstManipulation.EstType type) => _cache?.Meta.TemporarilySetEstFile(type) ?? utility.TemporarilyResetResource((MetaIndex)type); -} \ No newline at end of file +} diff --git a/Penumbra/Collections/ModCollection.cs b/Penumbra/Collections/ModCollection.cs index cb4aecc6..a9f565c6 100644 --- a/Penumbra/Collections/ModCollection.cs +++ b/Penumbra/Collections/ModCollection.cs @@ -1,6 +1,7 @@ using Penumbra.Mods; using Penumbra.Mods.Manager; using Penumbra.Collections.Manager; +using Penumbra.Mods.Subclasses; using Penumbra.Services; namespace Penumbra.Collections; @@ -44,10 +45,10 @@ public partial class ModCollection /// This is used for material and imc changes. /// public int ChangeCounter { get; private set; } - - /// Increment the number of changes in the effective file list. + + /// Increment the number of changes in the effective file list. public int IncrementCounter() - => ++ChangeCounter; + => ++ChangeCounter; /// /// If a ModSetting is null, it can be inherited from other collections. @@ -57,7 +58,7 @@ public partial class ModCollection /// Settings for deleted mods will be kept via the mods identifier (directory name). public readonly IReadOnlyDictionary UnusedSettings; - + /// Inheritances stored before they can be applied. public IReadOnlyList? InheritanceByName; @@ -118,7 +119,7 @@ public partial class ModCollection /// Constructor for reading from files. public static ModCollection CreateFromData(SaveService saver, ModStorage mods, string name, int version, int index, Dictionary allSettings, IReadOnlyList inheritances) - { + { Debug.Assert(index > 0, "Collection read with non-positive index."); var ret = new ModCollection(name, index, 0, version, new List(), new List(), allSettings) { @@ -130,7 +131,7 @@ public partial class ModCollection } /// Constructor for temporary collections. - public static ModCollection CreateTemporary(string name, int index, int changeCounter) + public static ModCollection CreateTemporary(string name, int index, int changeCounter) { Debug.Assert(index < 0, "Temporary collection created with non-negative index."); var ret = new ModCollection(name, index, changeCounter, CurrentVersion, new List(), new List(), @@ -142,9 +143,10 @@ public partial class ModCollection public static ModCollection CreateEmpty(string name, int index, int modCount) { Debug.Assert(index >= 0, "Empty collection created with negative index."); - return new ModCollection(name, index, 0, CurrentVersion, Enumerable.Repeat((ModSettings?) null, modCount).ToList(), new List(), + return new ModCollection(name, index, 0, CurrentVersion, Enumerable.Repeat((ModSettings?)null, modCount).ToList(), + new List(), new Dictionary()); - } + } /// Add settings for a new appended mod, by checking if the mod had settings from a previous deletion. internal bool AddMod(Mod mod) diff --git a/Penumbra/Collections/ModCollectionSave.cs b/Penumbra/Collections/ModCollectionSave.cs index 05a8d9b0..4cc7706e 100644 --- a/Penumbra/Collections/ModCollectionSave.cs +++ b/Penumbra/Collections/ModCollectionSave.cs @@ -3,6 +3,7 @@ using Penumbra.Mods; using Penumbra.Services; using Newtonsoft.Json; using Penumbra.Mods.Manager; +using Penumbra.Mods.Subclasses; using Penumbra.Util; namespace Penumbra.Collections; @@ -53,7 +54,7 @@ internal readonly struct ModCollectionSave : ISavable } list.AddRange(_modCollection.UnusedSettings.Select(kvp => (kvp.Key, kvp.Value))); - list.Sort((a, b) => string.Compare(a.Item1, b.Item1, StringComparison.OrdinalIgnoreCase)); + list.Sort((a, b) => string.Compare(a.Item1, b.Item1, StringComparison.OrdinalIgnoreCase)); foreach (var (modDir, settings) in list) { @@ -64,7 +65,7 @@ internal readonly struct ModCollectionSave : ISavable j.WriteEndObject(); // Inherit by collection name. - j.WritePropertyName("Inheritance"); + j.WritePropertyName("Inheritance"); x.Serialize(j, _modCollection.InheritanceByName ?? _modCollection.DirectlyInheritsFrom.Select(c => c.Name)); j.WriteEndObject(); } diff --git a/Penumbra/Collections/ResolveData.cs b/Penumbra/Collections/ResolveData.cs index 0c7bc967..0f3a1155 100644 --- a/Penumbra/Collections/ResolveData.cs +++ b/Penumbra/Collections/ResolveData.cs @@ -14,8 +14,8 @@ public readonly struct ResolveData public bool Valid => _modCollection != null; - public ResolveData() - : this(null!, nint.Zero) + public ResolveData() + : this(null!, nint.Zero) { } public ResolveData(ModCollection collection, nint gameObject) diff --git a/Penumbra/CommandHandler.cs b/Penumbra/CommandHandler.cs index d1830617..920e9cef 100644 --- a/Penumbra/CommandHandler.cs +++ b/Penumbra/CommandHandler.cs @@ -207,7 +207,8 @@ public class CommandHandler : IDisposable private bool SetUiMinimumSize(string _) { if (_config.MinimumSize.X == Configuration.Constants.MinimumSizeX && _config.MinimumSize.Y == Configuration.Constants.MinimumSizeY) - return false; + return false; + _config.MinimumSize.X = Configuration.Constants.MinimumSizeX; _config.MinimumSize.Y = Configuration.Constants.MinimumSizeY; _config.Save(); diff --git a/Penumbra/Communication/CollectionChange.cs b/Penumbra/Communication/CollectionChange.cs index b815c48e..b713cc72 100644 --- a/Penumbra/Communication/CollectionChange.cs +++ b/Penumbra/Communication/CollectionChange.cs @@ -45,7 +45,6 @@ public sealed class CollectionChange : EventWrapper ModFileSystemSelector = 0, - } public CollectionChange() diff --git a/Penumbra/Communication/ModDataChanged.cs b/Penumbra/Communication/ModDataChanged.cs index cca546e0..9ec60aa3 100644 --- a/Penumbra/Communication/ModDataChanged.cs +++ b/Penumbra/Communication/ModDataChanged.cs @@ -21,7 +21,7 @@ public sealed class ModDataChanged : EventWrapper ModCacheManager = 0, - /// + /// ModFileSystem = 0, } diff --git a/Penumbra/Communication/ModDiscoveryFinished.cs b/Penumbra/Communication/ModDiscoveryFinished.cs index 8f5d31d5..04c13e95 100644 --- a/Penumbra/Communication/ModDiscoveryFinished.cs +++ b/Penumbra/Communication/ModDiscoveryFinished.cs @@ -1,4 +1,5 @@ using OtterGui.Classes; +using Penumbra.Mods.Manager; namespace Penumbra.Communication; @@ -19,7 +20,7 @@ public sealed class ModDiscoveryFinished : EventWrapper ModCacheManager = 0, - /// + /// ModFileSystem = 0, } diff --git a/Penumbra/Communication/ModDiscoveryStarted.cs b/Penumbra/Communication/ModDiscoveryStarted.cs index a2ff8633..cf45528d 100644 --- a/Penumbra/Communication/ModDiscoveryStarted.cs +++ b/Penumbra/Communication/ModDiscoveryStarted.cs @@ -16,6 +16,7 @@ public sealed class ModDiscoveryStarted : EventWrapper ModFileSystemSelector = 200, } + public ModDiscoveryStarted() : base(nameof(ModDiscoveryStarted)) { } diff --git a/Penumbra/Communication/ModPathChanged.cs b/Penumbra/Communication/ModPathChanged.cs index 99ec9109..83c3b5a5 100644 --- a/Penumbra/Communication/ModPathChanged.cs +++ b/Penumbra/Communication/ModPathChanged.cs @@ -30,7 +30,7 @@ public sealed class ModPathChanged : EventWrapper ModExportManager = 0, - /// + /// ModFileSystem = 0, /// @@ -48,6 +48,7 @@ public sealed class ModPathChanged : EventWrapper CollectionCacheManagerRemoval = 100, } + public ModPathChanged() : base(nameof(ModPathChanged)) { } diff --git a/Penumbra/Configuration.cs b/Penumbra/Configuration.cs index 72f8bb95..63d58a16 100644 --- a/Penumbra/Configuration.cs +++ b/Penumbra/Configuration.cs @@ -6,13 +6,14 @@ using OtterGui.Classes; using OtterGui.Filesystem; using OtterGui.Widgets; using Penumbra.Api.Enums; -using Penumbra.GameData.Enums; using Penumbra.Import.Structs; using Penumbra.Interop.Services; using Penumbra.Mods; +using Penumbra.Mods.Manager; using Penumbra.Services; using Penumbra.UI; using Penumbra.UI.Classes; +using Penumbra.UI.ResourceWatcher; using Penumbra.UI.Tabs; using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs; diff --git a/Penumbra/GlobalUsings.cs b/Penumbra/GlobalUsings.cs index 0f6538bb..b1e6218c 100644 --- a/Penumbra/GlobalUsings.cs +++ b/Penumbra/GlobalUsings.cs @@ -2,13 +2,15 @@ global using System; global using System.Collections; +global using System.Collections.Concurrent; global using System.Collections.Generic; global using System.Diagnostics; global using System.IO; global using System.Linq; global using System.Numerics; +global using System.Reflection; global using System.Runtime.CompilerServices; global using System.Runtime.InteropServices; global using System.Security.Cryptography; global using System.Threading; -global using System.Threading.Tasks; \ No newline at end of file +global using System.Threading.Tasks; diff --git a/Penumbra/Import/Structs/ImporterState.cs b/Penumbra/Import/Structs/ImporterState.cs index 9ab2ab9a..8c0ddb4e 100644 --- a/Penumbra/Import/Structs/ImporterState.cs +++ b/Penumbra/Import/Structs/ImporterState.cs @@ -7,4 +7,4 @@ public enum ImporterState ExtractingModFiles, DeduplicatingFiles, Done, -} \ No newline at end of file +} diff --git a/Penumbra/Import/Structs/StreamDisposer.cs b/Penumbra/Import/Structs/StreamDisposer.cs index 7a755c40..84719331 100644 --- a/Penumbra/Import/Structs/StreamDisposer.cs +++ b/Penumbra/Import/Structs/StreamDisposer.cs @@ -20,4 +20,4 @@ public class StreamDisposer : PenumbraSqPackStream, IDisposable File.Delete(filePath); } -} \ No newline at end of file +} diff --git a/Penumbra/Import/TexToolsImporter.Archives.cs b/Penumbra/Import/TexToolsImporter.Archives.cs index a41b9f24..3b67ac50 100644 --- a/Penumbra/Import/TexToolsImporter.Archives.cs +++ b/Penumbra/Import/TexToolsImporter.Archives.cs @@ -15,19 +15,19 @@ namespace Penumbra.Import; public partial class TexToolsImporter { - /// + /// /// Extract regular compressed archives that are folders containing penumbra-formatted mods. /// The mod has to either contain a meta.json at top level, or one folder deep. /// If the meta.json is one folder deep, all other files have to be in the same folder. /// The extracted folder gets its name either from that one top-level folder or from the mod name. - /// All data is extracted without manipulation of the files or metadata. - /// - private DirectoryInfo HandleRegularArchive( FileInfo modPackFile ) + /// All data is extracted without manipulation of the files or metadata. + /// + private DirectoryInfo HandleRegularArchive(FileInfo modPackFile) { using var zfs = modPackFile.OpenRead(); - using var archive = ArchiveFactory.Open( zfs ); + using var archive = ArchiveFactory.Open(zfs); - var baseName = FindArchiveModMeta( archive, out var leadDir ); + var baseName = FindArchiveModMeta(archive, out var leadDir); var name = string.Empty; _currentOptionIdx = 0; _currentNumOptions = 1; @@ -42,9 +42,9 @@ public partial class TexToolsImporter SevenZipArchive s => s.Entries.Count, _ => archive.Entries.Count(), }; - Penumbra.Log.Information( $" -> Importing {archive.Type} Archive." ); + Penumbra.Log.Information($" -> Importing {archive.Type} Archive."); - _currentModDirectory = ModCreator.CreateModFolder( _baseDirectory, Path.GetRandomFileName() ); + _currentModDirectory = ModCreator.CreateModFolder(_baseDirectory, Path.GetRandomFileName()); var options = new ExtractionOptions() { ExtractFullPath = true, @@ -55,40 +55,38 @@ public partial class TexToolsImporter _currentFileIdx = 0; var reader = archive.ExtractAllEntries(); - while( reader.MoveToNextEntry() ) + while (reader.MoveToNextEntry()) { _token.ThrowIfCancellationRequested(); - if( reader.Entry.IsDirectory ) + if (reader.Entry.IsDirectory) { --_currentNumFiles; continue; } - Penumbra.Log.Information( $" -> Extracting {reader.Entry.Key}" ); + Penumbra.Log.Information($" -> Extracting {reader.Entry.Key}"); // Check that the mod has a valid name in the meta.json file. - if( Path.GetFileName( reader.Entry.Key ) == "meta.json" ) + if (Path.GetFileName(reader.Entry.Key) == "meta.json") { using var s = new MemoryStream(); using var e = reader.OpenEntryStream(); - e.CopyTo( s ); - s.Seek( 0, SeekOrigin.Begin ); - using var t = new StreamReader( s ); - using var j = new JsonTextReader( t ); - var obj = JObject.Load( j ); - name = obj[ nameof( Mod.Name ) ]?.Value< string >()?.RemoveInvalidPathSymbols() ?? string.Empty; - if( name.Length == 0 ) - { - throw new Exception( "Invalid mod archive: mod meta has no name." ); - } + e.CopyTo(s); + s.Seek(0, SeekOrigin.Begin); + using var t = new StreamReader(s); + using var j = new JsonTextReader(t); + var obj = JObject.Load(j); + name = obj[nameof(Mod.Name)]?.Value()?.RemoveInvalidPathSymbols() ?? string.Empty; + if (name.Length == 0) + throw new Exception("Invalid mod archive: mod meta has no name."); - using var f = File.OpenWrite( Path.Combine( _currentModDirectory.FullName, reader.Entry.Key ) ); - s.Seek( 0, SeekOrigin.Begin ); - s.WriteTo( f ); + using var f = File.OpenWrite(Path.Combine(_currentModDirectory.FullName, reader.Entry.Key)); + s.Seek(0, SeekOrigin.Begin); + s.WriteTo(f); } else { - reader.WriteEntryToDirectory( _currentModDirectory.FullName, options ); + reader.WriteEntryToDirectory(_currentModDirectory.FullName, options); } ++_currentFileIdx; @@ -97,60 +95,59 @@ public partial class TexToolsImporter _token.ThrowIfCancellationRequested(); var oldName = _currentModDirectory.FullName; // Use either the top-level directory as the mods base name, or the (fixed for path) name in the json. - if( leadDir ) + if (leadDir) { - _currentModDirectory = ModCreator.CreateModFolder( _baseDirectory, baseName, false ); - Directory.Move( Path.Combine( oldName, baseName ), _currentModDirectory.FullName ); - Directory.Delete( oldName ); + _currentModDirectory = ModCreator.CreateModFolder(_baseDirectory, baseName, false); + Directory.Move(Path.Combine(oldName, baseName), _currentModDirectory.FullName); + Directory.Delete(oldName); } else { - _currentModDirectory = ModCreator.CreateModFolder( _baseDirectory, name, false ); - Directory.Move( oldName, _currentModDirectory.FullName ); + _currentModDirectory = ModCreator.CreateModFolder(_baseDirectory, name, false); + Directory.Move(oldName, _currentModDirectory.FullName); } _currentModDirectory.Refresh(); - _modManager.Creator.SplitMultiGroups( _currentModDirectory ); + _modManager.Creator.SplitMultiGroups(_currentModDirectory); return _currentModDirectory; } // Search the archive for the meta.json file which needs to exist. - private static string FindArchiveModMeta( IArchive archive, out bool leadDir ) + private static string FindArchiveModMeta(IArchive archive, out bool leadDir) { - var entry = archive.Entries.FirstOrDefault( e => !e.IsDirectory && Path.GetFileName( e.Key ) == "meta.json" ); + var entry = archive.Entries.FirstOrDefault(e => !e.IsDirectory && Path.GetFileName(e.Key) == "meta.json"); // None found. - if( entry == null ) - { - throw new Exception( "Invalid mod archive: No meta.json contained." ); - } + if (entry == null) + throw new Exception("Invalid mod archive: No meta.json contained."); var ret = string.Empty; leadDir = false; // If the file is not at top-level. - if( entry.Key != "meta.json" ) + if (entry.Key != "meta.json") { leadDir = true; - var directory = Path.GetDirectoryName( entry.Key ); + var directory = Path.GetDirectoryName(entry.Key); // Should not happen. - if( directory.IsNullOrEmpty() ) - { - throw new Exception( "Invalid mod archive: Unknown error fetching meta.json." ); - } + if (directory.IsNullOrEmpty()) + throw new Exception("Invalid mod archive: Unknown error fetching meta.json."); ret = directory; // Check that all other files are also contained in the top-level directory. - if( ret.IndexOfAny( new[] { '/', '\\' } ) >= 0 - || !archive.Entries.All( e => e.Key.StartsWith( ret ) && ( e.Key.Length == ret.Length || e.Key[ ret.Length ] is '/' or '\\' ) ) ) - { + if (ret.IndexOfAny(new[] + { + '/', + '\\', + }) + >= 0 + || !archive.Entries.All(e => e.Key.StartsWith(ret) && (e.Key.Length == ret.Length || e.Key[ret.Length] is '/' or '\\'))) throw new Exception( - "Invalid mod archive: meta.json in wrong location. It needs to be either at root or one directory deep, in which all other files must be nested too." ); - } + "Invalid mod archive: meta.json in wrong location. It needs to be either at root or one directory deep, in which all other files must be nested too."); } return ret; } -} \ No newline at end of file +} diff --git a/Penumbra/Import/TexToolsImporter.Gui.cs b/Penumbra/Import/TexToolsImporter.Gui.cs index 0c3e084d..e150d10d 100644 --- a/Penumbra/Import/TexToolsImporter.Gui.cs +++ b/Penumbra/Import/TexToolsImporter.Gui.cs @@ -1,7 +1,7 @@ using ImGuiNET; using OtterGui; using OtterGui.Raii; -using Penumbra.Import.Structs; +using Penumbra.Import.Structs; using Penumbra.UI.Classes; namespace Penumbra.Import; @@ -20,89 +20,79 @@ public partial class TexToolsImporter private string _currentOptionName = string.Empty; private string _currentFileName = string.Empty; - public void DrawProgressInfo( Vector2 size ) + public void DrawProgressInfo(Vector2 size) { - if( _modPackCount == 0 ) + if (_modPackCount == 0) { - ImGuiUtil.Center( "Nothing to extract." ); + ImGuiUtil.Center("Nothing to extract."); } - else if( _modPackCount == _currentModPackIdx ) + else if (_modPackCount == _currentModPackIdx) { DrawEndState(); } else { ImGui.NewLine(); - var percentage = _modPackCount / ( float )_currentModPackIdx; - ImGui.ProgressBar( percentage, size, $"Mod {_currentModPackIdx + 1} / {_modPackCount}" ); + var percentage = _modPackCount / (float)_currentModPackIdx; + ImGui.ProgressBar(percentage, size, $"Mod {_currentModPackIdx + 1} / {_modPackCount}"); ImGui.NewLine(); - if( State == ImporterState.DeduplicatingFiles ) - { - ImGui.TextUnformatted( $"Deduplicating {_currentModName}..." ); - } + if (State == ImporterState.DeduplicatingFiles) + ImGui.TextUnformatted($"Deduplicating {_currentModName}..."); else - { - ImGui.TextUnformatted( $"Extracting {_currentModName}..." ); - } + ImGui.TextUnformatted($"Extracting {_currentModName}..."); - if( _currentNumOptions > 1 ) + if (_currentNumOptions > 1) { ImGui.NewLine(); ImGui.NewLine(); - percentage = _currentNumOptions == 0 ? 1f : _currentOptionIdx / ( float )_currentNumOptions; - ImGui.ProgressBar( percentage, size, $"Option {_currentOptionIdx + 1} / {_currentNumOptions}" ); + percentage = _currentNumOptions == 0 ? 1f : _currentOptionIdx / (float)_currentNumOptions; + ImGui.ProgressBar(percentage, size, $"Option {_currentOptionIdx + 1} / {_currentNumOptions}"); ImGui.NewLine(); - if( State != ImporterState.DeduplicatingFiles ) - { + if (State != ImporterState.DeduplicatingFiles) ImGui.TextUnformatted( - $"Extracting option {( _currentGroupName.Length == 0 ? string.Empty : $"{_currentGroupName} - " )}{_currentOptionName}..." ); - } + $"Extracting option {(_currentGroupName.Length == 0 ? string.Empty : $"{_currentGroupName} - ")}{_currentOptionName}..."); } ImGui.NewLine(); ImGui.NewLine(); - percentage = _currentNumFiles == 0 ? 1f : _currentFileIdx / ( float )_currentNumFiles; - ImGui.ProgressBar( percentage, size, $"File {_currentFileIdx + 1} / {_currentNumFiles}" ); + percentage = _currentNumFiles == 0 ? 1f : _currentFileIdx / (float)_currentNumFiles; + ImGui.ProgressBar(percentage, size, $"File {_currentFileIdx + 1} / {_currentNumFiles}"); ImGui.NewLine(); - if( State != ImporterState.DeduplicatingFiles ) - { - ImGui.TextUnformatted( $"Extracting file {_currentFileName}..." ); - } + if (State != ImporterState.DeduplicatingFiles) + ImGui.TextUnformatted($"Extracting file {_currentFileName}..."); } } private void DrawEndState() { - var success = ExtractedMods.Count( t => t.Error == null ); + var success = ExtractedMods.Count(t => t.Error == null); - ImGui.TextUnformatted( $"Successfully extracted {success} / {ExtractedMods.Count} files." ); + ImGui.TextUnformatted($"Successfully extracted {success} / {ExtractedMods.Count} files."); ImGui.NewLine(); - using var table = ImRaii.Table( "##files", 2 ); - if( !table ) - { + using var table = ImRaii.Table("##files", 2); + if (!table) return; - } - foreach( var (file, dir, ex) in ExtractedMods ) + foreach (var (file, dir, ex) in ExtractedMods) { ImGui.TableNextColumn(); - ImGui.TextUnformatted( file.Name ); + ImGui.TextUnformatted(file.Name); ImGui.TableNextColumn(); - if( ex == null ) + if (ex == null) { - using var color = ImRaii.PushColor( ImGuiCol.Text, ColorId.FolderExpanded.Value() ); - ImGui.TextUnformatted( dir?.FullName[ ( _baseDirectory.FullName.Length + 1 ).. ] ?? "Unknown Directory" ); + using var color = ImRaii.PushColor(ImGuiCol.Text, ColorId.FolderExpanded.Value()); + ImGui.TextUnformatted(dir?.FullName[(_baseDirectory.FullName.Length + 1)..] ?? "Unknown Directory"); } else { - using var color = ImRaii.PushColor( ImGuiCol.Text, ColorId.ConflictingMod.Value() ); - ImGui.TextUnformatted( ex.Message ); - ImGuiUtil.HoverTooltip( ex.ToString() ); + using var color = ImRaii.PushColor(ImGuiCol.Text, ColorId.ConflictingMod.Value()); + ImGui.TextUnformatted(ex.Message); + ImGuiUtil.HoverTooltip(ex.ToString()); } } } - public bool DrawCancelButton( Vector2 size ) - => ImGuiUtil.DrawDisabledButton( "Cancel", size, string.Empty, _token.IsCancellationRequested ); -} \ No newline at end of file + public bool DrawCancelButton(Vector2 size) + => ImGuiUtil.DrawDisabledButton("Cancel", size, string.Empty, _token.IsCancellationRequested); +} diff --git a/Penumbra/Import/TexToolsMeta.Deserialization.cs b/Penumbra/Import/TexToolsMeta.Deserialization.cs index eea1d811..64eff8ba 100644 --- a/Penumbra/Import/TexToolsMeta.Deserialization.cs +++ b/Penumbra/Import/TexToolsMeta.Deserialization.cs @@ -116,7 +116,7 @@ public partial class TexToolsMeta var partIdx = ImcFile.PartIndex(manip.EquipSlot); // Gets turned to unknown for things without equip, and unknown turns to 0. foreach (var value in values) { - if (_keepDefault || !value.Equals(def.GetEntry(partIdx, (Variant) i))) + if (_keepDefault || !value.Equals(def.GetEntry(partIdx, (Variant)i))) { var imc = new ImcManipulation(manip.ObjectType, manip.BodySlot, manip.PrimaryId, manip.SecondaryId, i, manip.EquipSlot, value); diff --git a/Penumbra/Import/TexToolsMeta.Rgsp.cs b/Penumbra/Import/TexToolsMeta.Rgsp.cs index 0fd94fb4..51faa175 100644 --- a/Penumbra/Import/TexToolsMeta.Rgsp.cs +++ b/Penumbra/Import/TexToolsMeta.Rgsp.cs @@ -8,72 +8,70 @@ namespace Penumbra.Import; public partial class TexToolsMeta { // Parse a single rgsp file. - public static TexToolsMeta FromRgspFile( MetaFileManager manager, string filePath, byte[] data, bool keepDefault ) + public static TexToolsMeta FromRgspFile(MetaFileManager manager, string filePath, byte[] data, bool keepDefault) { - if( data.Length != 45 && data.Length != 42 ) + if (data.Length != 45 && data.Length != 42) { - Penumbra.Log.Error( "Error while parsing .rgsp file:\n\tInvalid number of bytes." ); + Penumbra.Log.Error("Error while parsing .rgsp file:\n\tInvalid number of bytes."); return Invalid; } - using var s = new MemoryStream( data ); - using var br = new BinaryReader( s ); + using var s = new MemoryStream(data); + using var br = new BinaryReader(s); // The first value is a flag that signifies version. // If it is byte.max, the following two bytes are the version, // otherwise it is version 1 and signifies the sub race instead. var flag = br.ReadByte(); - var version = flag != 255 ? ( uint )1 : br.ReadUInt16(); + var version = flag != 255 ? (uint)1 : br.ReadUInt16(); - var ret = new TexToolsMeta( manager, filePath, version ); + var ret = new TexToolsMeta(manager, filePath, version); // SubRace is offset by one due to Unknown. - var subRace = ( SubRace )( version == 1 ? flag + 1 : br.ReadByte() + 1 ); - if( !Enum.IsDefined( typeof( SubRace ), subRace ) || subRace == SubRace.Unknown ) + var subRace = (SubRace)(version == 1 ? flag + 1 : br.ReadByte() + 1); + if (!Enum.IsDefined(typeof(SubRace), subRace) || subRace == SubRace.Unknown) { - Penumbra.Log.Error( $"Error while parsing .rgsp file:\n\t{subRace} is not a valid SubRace." ); + Penumbra.Log.Error($"Error while parsing .rgsp file:\n\t{subRace} is not a valid SubRace."); return Invalid; } // Next byte is Gender. 1 is Female, 0 is Male. var gender = br.ReadByte(); - if( gender != 1 && gender != 0 ) + if (gender != 1 && gender != 0) { - Penumbra.Log.Error( $"Error while parsing .rgsp file:\n\t{gender} is neither Male nor Female." ); + Penumbra.Log.Error($"Error while parsing .rgsp file:\n\t{gender} is neither Male nor Female."); return Invalid; } // Add the given values to the manipulations if they are not default. - void Add( RspAttribute attribute, float value ) + void Add(RspAttribute attribute, float value) { - var def = CmpFile.GetDefault( manager, subRace, attribute ); - if( keepDefault || value != def ) - { - ret.MetaManipulations.Add( new RspManipulation( subRace, attribute, value ) ); - } + var def = CmpFile.GetDefault(manager, subRace, attribute); + if (keepDefault || value != def) + ret.MetaManipulations.Add(new RspManipulation(subRace, attribute, value)); } - if( gender == 1 ) + if (gender == 1) { - Add( RspAttribute.FemaleMinSize, br.ReadSingle() ); - Add( RspAttribute.FemaleMaxSize, br.ReadSingle() ); - Add( RspAttribute.FemaleMinTail, br.ReadSingle() ); - Add( RspAttribute.FemaleMaxTail, br.ReadSingle() ); + Add(RspAttribute.FemaleMinSize, br.ReadSingle()); + Add(RspAttribute.FemaleMaxSize, br.ReadSingle()); + Add(RspAttribute.FemaleMinTail, br.ReadSingle()); + Add(RspAttribute.FemaleMaxTail, br.ReadSingle()); - Add( RspAttribute.BustMinX, br.ReadSingle() ); - Add( RspAttribute.BustMinY, br.ReadSingle() ); - Add( RspAttribute.BustMinZ, br.ReadSingle() ); - Add( RspAttribute.BustMaxX, br.ReadSingle() ); - Add( RspAttribute.BustMaxY, br.ReadSingle() ); - Add( RspAttribute.BustMaxZ, br.ReadSingle() ); + Add(RspAttribute.BustMinX, br.ReadSingle()); + Add(RspAttribute.BustMinY, br.ReadSingle()); + Add(RspAttribute.BustMinZ, br.ReadSingle()); + Add(RspAttribute.BustMaxX, br.ReadSingle()); + Add(RspAttribute.BustMaxY, br.ReadSingle()); + Add(RspAttribute.BustMaxZ, br.ReadSingle()); } else { - Add( RspAttribute.MaleMinSize, br.ReadSingle() ); - Add( RspAttribute.MaleMaxSize, br.ReadSingle() ); - Add( RspAttribute.MaleMinTail, br.ReadSingle() ); - Add( RspAttribute.MaleMaxTail, br.ReadSingle() ); + Add(RspAttribute.MaleMinSize, br.ReadSingle()); + Add(RspAttribute.MaleMaxSize, br.ReadSingle()); + Add(RspAttribute.MaleMinTail, br.ReadSingle()); + Add(RspAttribute.MaleMaxTail, br.ReadSingle()); } return ret; } -} \ No newline at end of file +} diff --git a/Penumbra/Import/TexToolsMeta.cs b/Penumbra/Import/TexToolsMeta.cs index b44f99a8..a188975c 100644 --- a/Penumbra/Import/TexToolsMeta.cs +++ b/Penumbra/Import/TexToolsMeta.cs @@ -17,70 +17,68 @@ namespace Penumbra.Import; /// TexTools may also generate files that contain non-existing changes, e.g. *.imc files for weapon offhands, which will be ignored. /// TexTools also provides .rgsp files, that contain changes to the racial scaling parameters in the human.cmp file. public partial class TexToolsMeta -{ +{ /// An empty TexToolsMeta. public static readonly TexToolsMeta Invalid = new(null!, string.Empty, 0); // The info class determines the files or table locations the changes need to apply to from the filename. - public readonly uint Version; - public readonly string FilePath; - public readonly List< MetaManipulation > MetaManipulations = new(); - private readonly bool _keepDefault = false; - - private readonly MetaFileManager _metaFileManager; + public readonly uint Version; + public readonly string FilePath; + public readonly List MetaManipulations = new(); + private readonly bool _keepDefault = false; - public TexToolsMeta( MetaFileManager metaFileManager, IGamePathParser parser, byte[] data, bool keepDefault ) - { + private readonly MetaFileManager _metaFileManager; + + public TexToolsMeta(MetaFileManager metaFileManager, IGamePathParser parser, byte[] data, bool keepDefault) + { _metaFileManager = metaFileManager; - _keepDefault = keepDefault; + _keepDefault = keepDefault; try { - using var reader = new BinaryReader( new MemoryStream( data ) ); + using var reader = new BinaryReader(new MemoryStream(data)); Version = reader.ReadUInt32(); - FilePath = ReadNullTerminated( reader ); - var metaInfo = new MetaFileInfo( parser, FilePath ); + FilePath = ReadNullTerminated(reader); + var metaInfo = new MetaFileInfo(parser, FilePath); var numHeaders = reader.ReadUInt32(); var headerSize = reader.ReadUInt32(); var headerStart = reader.ReadUInt32(); - reader.BaseStream.Seek( headerStart, SeekOrigin.Begin ); + reader.BaseStream.Seek(headerStart, SeekOrigin.Begin); - List< (MetaManipulation.Type type, uint offset, int size) > entries = new(); - for( var i = 0; i < numHeaders; ++i ) + List<(MetaManipulation.Type type, uint offset, int size)> entries = new(); + for (var i = 0; i < numHeaders; ++i) { var currentOffset = reader.BaseStream.Position; - var type = ( MetaManipulation.Type )reader.ReadUInt32(); + var type = (MetaManipulation.Type)reader.ReadUInt32(); var offset = reader.ReadUInt32(); var size = reader.ReadInt32(); - entries.Add( ( type, offset, size ) ); - reader.BaseStream.Seek( currentOffset + headerSize, SeekOrigin.Begin ); + entries.Add((type, offset, size)); + reader.BaseStream.Seek(currentOffset + headerSize, SeekOrigin.Begin); } - byte[]? ReadEntry( MetaManipulation.Type type ) + byte[]? ReadEntry(MetaManipulation.Type type) { - var idx = entries.FindIndex( t => t.type == type ); - if( idx < 0 ) - { + var idx = entries.FindIndex(t => t.type == type); + if (idx < 0) return null; - } - reader.BaseStream.Seek( entries[ idx ].offset, SeekOrigin.Begin ); - return reader.ReadBytes( entries[ idx ].size ); + reader.BaseStream.Seek(entries[idx].offset, SeekOrigin.Begin); + return reader.ReadBytes(entries[idx].size); } - DeserializeEqpEntry( metaInfo, ReadEntry( MetaManipulation.Type.Eqp ) ); - DeserializeGmpEntry( metaInfo, ReadEntry( MetaManipulation.Type.Gmp ) ); - DeserializeEqdpEntries( metaInfo, ReadEntry( MetaManipulation.Type.Eqdp ) ); - DeserializeEstEntries( metaInfo, ReadEntry( MetaManipulation.Type.Est ) ); - DeserializeImcEntries( metaInfo, ReadEntry( MetaManipulation.Type.Imc ) ); + DeserializeEqpEntry(metaInfo, ReadEntry(MetaManipulation.Type.Eqp)); + DeserializeGmpEntry(metaInfo, ReadEntry(MetaManipulation.Type.Gmp)); + DeserializeEqdpEntries(metaInfo, ReadEntry(MetaManipulation.Type.Eqdp)); + DeserializeEstEntries(metaInfo, ReadEntry(MetaManipulation.Type.Est)); + DeserializeImcEntries(metaInfo, ReadEntry(MetaManipulation.Type.Imc)); } - catch( Exception e ) + catch (Exception e) { FilePath = ""; - Penumbra.Log.Error( $"Error while parsing .meta file:\n{e}" ); + Penumbra.Log.Error($"Error while parsing .meta file:\n{e}"); } } - private TexToolsMeta( MetaFileManager metaFileManager, string filePath, uint version ) + private TexToolsMeta(MetaFileManager metaFileManager, string filePath, uint version) { _metaFileManager = metaFileManager; FilePath = filePath; @@ -88,14 +86,12 @@ public partial class TexToolsMeta } // Read a null terminated string from a binary reader. - private static string ReadNullTerminated( BinaryReader reader ) + private static string ReadNullTerminated(BinaryReader reader) { var builder = new StringBuilder(); - for( var c = reader.ReadChar(); c != 0; c = reader.ReadChar() ) - { - builder.Append( c ); - } + for (var c = reader.ReadChar(); c != 0; c = reader.ReadChar()) + builder.Append(c); return builder.ToString(); } -} \ No newline at end of file +} diff --git a/Penumbra/Import/Textures/RgbaPixelData.cs b/Penumbra/Import/Textures/RgbaPixelData.cs index 32540f16..7c28b72b 100644 --- a/Penumbra/Import/Textures/RgbaPixelData.cs +++ b/Penumbra/Import/Textures/RgbaPixelData.cs @@ -13,8 +13,7 @@ public readonly record struct RgbaPixelData(int Width, int Height, byte[] PixelD public RgbaPixelData((int Width, int Height) size, byte[] pixelData) : this(size.Width, size.Height, pixelData) - { - } + { } public Image ToImage() => Image.LoadPixelData(PixelData, Width, Height); diff --git a/Penumbra/Import/Textures/TexFileParser.cs b/Penumbra/Import/Textures/TexFileParser.cs index 7f324601..15d45be6 100644 --- a/Penumbra/Import/Textures/TexFileParser.cs +++ b/Penumbra/Import/Textures/TexFileParser.cs @@ -79,8 +79,8 @@ public static class TexFileParser w.Write(header.Width); w.Write(header.Height); w.Write(header.Depth); - w.Write((byte) header.MipLevels); - w.Write((byte) 0); // TODO Lumina Update + w.Write((byte)header.MipLevels); + w.Write((byte)0); // TODO Lumina Update unsafe { w.Write(header.LodOffset[0]); diff --git a/Penumbra/Import/Textures/TextureDrawer.cs b/Penumbra/Import/Textures/TextureDrawer.cs index b94fdbf8..a5692c23 100644 --- a/Penumbra/Import/Textures/TextureDrawer.cs +++ b/Penumbra/Import/Textures/TextureDrawer.cs @@ -103,7 +103,7 @@ public static class TextureDrawer public sealed class PathSelectCombo : FilterComboCache<(string, bool)> { - private int _skipPrefix = 0; + private int _skipPrefix = 0; public PathSelectCombo(TextureManager textures, ModEditor editor) : base(() => CreateFiles(textures, editor)) diff --git a/Penumbra/Import/Textures/TextureManager.cs b/Penumbra/Import/Textures/TextureManager.cs index 90dfa3d0..31c3275e 100644 --- a/Penumbra/Import/Textures/TextureManager.cs +++ b/Penumbra/Import/Textures/TextureManager.cs @@ -1,4 +1,3 @@ -using System.Collections.Concurrent; using Dalamud.Interface; using Dalamud.Plugin.Services; using ImGuiScene; diff --git a/Penumbra/Interop/MaterialPreview/LiveColorTablePreviewer.cs b/Penumbra/Interop/MaterialPreview/LiveColorTablePreviewer.cs index f83b1531..e89f0d10 100644 --- a/Penumbra/Interop/MaterialPreview/LiveColorTablePreviewer.cs +++ b/Penumbra/Interop/MaterialPreview/LiveColorTablePreviewer.cs @@ -80,7 +80,8 @@ public sealed unsafe class LiveColorTablePreviewer : LiveMaterialPreviewerBase textureSize[0] = TextureWidth; textureSize[1] = TextureHeight; - using var texture = new SafeTextureHandle(Structs.TextureUtility.Create2D(Device.Instance(), textureSize, 1, 0x2460, 0x80000804, 7), false); + using var texture = + new SafeTextureHandle(Structs.TextureUtility.Create2D(Device.Instance(), textureSize, 1, 0x2460, 0x80000804, 7), false); if (texture.IsInvalid) return; diff --git a/Penumbra/Interop/PathResolving/AnimationHookService.cs b/Penumbra/Interop/PathResolving/AnimationHookService.cs index cc679bfd..51612819 100644 --- a/Penumbra/Interop/PathResolving/AnimationHookService.cs +++ b/Penumbra/Interop/PathResolving/AnimationHookService.cs @@ -17,7 +17,7 @@ namespace Penumbra.Interop.PathResolving; public unsafe class AnimationHookService : IDisposable { private readonly PerformanceTracker _performance; - private readonly IObjectTable _objects; + private readonly IObjectTable _objects; private readonly CollectionResolver _collectionResolver; private readonly DrawObjectState _drawObjectState; private readonly CollectionResolver _resolver; @@ -34,7 +34,7 @@ public unsafe class AnimationHookService : IDisposable _collectionResolver = collectionResolver; _drawObjectState = drawObjectState; _resolver = resolver; - _conditions = conditions; + _conditions = conditions; SignatureHelper.Initialise(this); @@ -122,7 +122,7 @@ public unsafe class AnimationHookService : IDisposable var last = _characterSoundData.Value; _characterSoundData.Value = _collectionResolver.IdentifyCollection((GameObject*)character, true); var ret = _loadCharacterSoundHook.Original(character, unk1, unk2, unk3, unk4, unk5, unk6, unk7); - _characterSoundData.Value = last; + _characterSoundData.Value = last; return ret; } @@ -140,15 +140,15 @@ public unsafe class AnimationHookService : IDisposable using var performance = _performance.Measure(PerformanceType.TimelineResources); // Do not check timeline loading in cutscenes. if (_conditions[ConditionFlag.OccupiedInCutSceneEvent] || _conditions[ConditionFlag.WatchingCutscene78]) - return _loadTimelineResourcesHook.Original(timeline); + return _loadTimelineResourcesHook.Original(timeline); - var last = _animationLoadData.Value; + var last = _animationLoadData.Value; _animationLoadData.Value = GetDataFromTimeline(timeline); var ret = _loadTimelineResourcesHook.Original(timeline); _animationLoadData.Value = last; return ret; } - + /// /// Probably used when the base idle animation gets loaded. /// Make it aware of the correct collection to load the correct pap files. @@ -297,12 +297,12 @@ public unsafe class AnimationHookService : IDisposable try { if (timeline != IntPtr.Zero) - { + { var getGameObjectIdx = ((delegate* unmanaged**)timeline)[0][Offsets.GetGameObjectIdxVfunc]; var idx = getGameObjectIdx(timeline); if (idx >= 0 && idx < _objects.Length) { - var obj = (GameObject*)_objects.GetObjectAddress(idx); + var obj = (GameObject*)_objects.GetObjectAddress(idx); return obj != null ? _collectionResolver.IdentifyCollection(obj, true) : ResolveData.Invalid; } } @@ -378,17 +378,17 @@ public unsafe class AnimationHookService : IDisposable if (a6 == nint.Zero) return _apricotListenerSoundPlayHook!.Original(a1, a2, a3, a4, a5, a6); - var last = _animationLoadData.Value; - // a6 is some instance of Apricot.IInstanceListenner, in some cases we can obtain the associated caster via vfunc 1. + var last = _animationLoadData.Value; + // a6 is some instance of Apricot.IInstanceListenner, in some cases we can obtain the associated caster via vfunc 1. var gameObject = (*(delegate* unmanaged**)a6)[1](a6); if (gameObject != null) { _animationLoadData.Value = _collectionResolver.IdentifyCollection(gameObject, true); } else - { - // for VfxListenner we can obtain the associated draw object as its first member, - // if the object has different type, drawObject will contain other values or garbage, + { + // for VfxListenner we can obtain the associated draw object as its first member, + // if the object has different type, drawObject will contain other values or garbage, // but only be used in a dictionary pointer lookup, so this does not hurt. var drawObject = ((DrawObject**)a6)[1]; if (drawObject != null) diff --git a/Penumbra/Interop/PathResolving/CollectionResolver.cs b/Penumbra/Interop/PathResolving/CollectionResolver.cs index 3f73643b..ecd4eb2e 100644 --- a/Penumbra/Interop/PathResolving/CollectionResolver.cs +++ b/Penumbra/Interop/PathResolving/CollectionResolver.cs @@ -20,7 +20,7 @@ public unsafe class CollectionResolver private readonly HumanModelList _humanModels; private readonly IClientState _clientState; - private readonly IGameGui _gameGui; + private readonly IGameGui _gameGui; private readonly ActorService _actors; private readonly CutsceneService _cutscenes; diff --git a/Penumbra/Interop/PathResolving/DrawObjectState.cs b/Penumbra/Interop/PathResolving/DrawObjectState.cs index 512d370a..be1484db 100644 --- a/Penumbra/Interop/PathResolving/DrawObjectState.cs +++ b/Penumbra/Interop/PathResolving/DrawObjectState.cs @@ -10,7 +10,7 @@ namespace Penumbra.Interop.PathResolving; public class DrawObjectState : IDisposable, IReadOnlyDictionary { - private readonly IObjectTable _objects; + private readonly IObjectTable _objects; private readonly GameEventManager _gameEvents; private readonly Dictionary _drawObjectToGameObject = new(); @@ -71,8 +71,8 @@ public class DrawObjectState : IDisposable, IReadOnlyDictionaryDrawObject, gameObject, false, false); + _lastGameObject.Value!.Dequeue(); + IterateDrawObjectTree((Object*)((GameObject*)gameObject)->DrawObject, gameObject, false, false); } private void OnCharacterBaseDestructor(nint characterBase) diff --git a/Penumbra/Interop/PathResolving/IdentifiedCollectionCache.cs b/Penumbra/Interop/PathResolving/IdentifiedCollectionCache.cs index 546ffd92..0b456b3c 100644 --- a/Penumbra/Interop/PathResolving/IdentifiedCollectionCache.cs +++ b/Penumbra/Interop/PathResolving/IdentifiedCollectionCache.cs @@ -25,8 +25,8 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable<(nint A _events = events; _communicator.CollectionChange.Subscribe(CollectionChangeClear, CollectionChange.Priority.IdentifiedCollectionCache); - _clientState.TerritoryChanged += TerritoryClear; - _events.CharacterDestructor += OnCharacterDestruct; + _clientState.TerritoryChanged += TerritoryClear; + _events.CharacterDestructor += OnCharacterDestruct; } public ResolveData Set(ModCollection collection, ActorIdentifier identifier, GameObject* data) @@ -61,8 +61,8 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable<(nint A public void Dispose() { _communicator.CollectionChange.Unsubscribe(CollectionChangeClear); - _clientState.TerritoryChanged -= TerritoryClear; - _events.CharacterDestructor -= OnCharacterDestruct; + _clientState.TerritoryChanged -= TerritoryClear; + _events.CharacterDestructor -= OnCharacterDestruct; } public IEnumerator<(nint Address, ActorIdentifier Identifier, ModCollection Collection)> GetEnumerator() diff --git a/Penumbra/Interop/PathResolving/PathResolver.cs b/Penumbra/Interop/PathResolving/PathResolver.cs index 2176ebba..4494dc77 100644 --- a/Penumbra/Interop/PathResolving/PathResolver.cs +++ b/Penumbra/Interop/PathResolving/PathResolver.cs @@ -1,5 +1,6 @@ using System.Diagnostics.CodeAnalysis; using FFXIVClientStructs.FFXIV.Client.System.Resource; +using Penumbra.Api.Enums; using Penumbra.Collections; using Penumbra.Collections.Manager; using Penumbra.GameData.Enums; diff --git a/Penumbra/Interop/PathResolving/SubfileHelper.cs b/Penumbra/Interop/PathResolving/SubfileHelper.cs index b1bc806d..00b06963 100644 --- a/Penumbra/Interop/PathResolving/SubfileHelper.cs +++ b/Penumbra/Interop/PathResolving/SubfileHelper.cs @@ -1,4 +1,3 @@ -using System.Collections.Concurrent; using Dalamud.Hooking; using Dalamud.Utility.Signatures; using Penumbra.Collections; diff --git a/Penumbra/Interop/ResourceLoading/FileReadService.cs b/Penumbra/Interop/ResourceLoading/FileReadService.cs index 6ca0efb4..9dc89ab2 100644 --- a/Penumbra/Interop/ResourceLoading/FileReadService.cs +++ b/Penumbra/Interop/ResourceLoading/FileReadService.cs @@ -81,6 +81,6 @@ public unsafe class FileReadService : IDisposable /// private nint GetResourceManager() => !_lastFileThreadResourceManager.IsValueCreated || _lastFileThreadResourceManager.Value == IntPtr.Zero - ? (nint) _resourceManager.ResourceManager + ? (nint)_resourceManager.ResourceManager : _lastFileThreadResourceManager.Value; } diff --git a/Penumbra/Interop/ResourceTree/ResourceNode.cs b/Penumbra/Interop/ResourceTree/ResourceNode.cs index cae89c09..c3327a9e 100644 --- a/Penumbra/Interop/ResourceTree/ResourceNode.cs +++ b/Penumbra/Interop/ResourceTree/ResourceNode.cs @@ -37,7 +37,8 @@ public class ResourceNode Children = new List(); } - public ResourceNode(UIData uiData, ResourceType type, nint objectAddress, nint resourceHandle, Utf8GamePath[] possibleGamePaths, FullPath fullPath, + public ResourceNode(UIData uiData, ResourceType type, nint objectAddress, nint resourceHandle, Utf8GamePath[] possibleGamePaths, + FullPath fullPath, ulong length, bool @internal) { Name = uiData.Name; @@ -69,7 +70,7 @@ public class ResourceNode } public ResourceNode WithUIData(string? name, ChangedItemIcon icon) - => string.Equals(Name, name, StringComparison.Ordinal) && Icon == icon ? this : new ResourceNode(new(name, icon), this); + => string.Equals(Name, name, StringComparison.Ordinal) && Icon == icon ? this : new ResourceNode(new UIData(name, icon), this); public ResourceNode WithUIData(UIData uiData) => string.Equals(Name, uiData.Name, StringComparison.Ordinal) && Icon == uiData.Icon ? this : new ResourceNode(uiData, this); @@ -77,6 +78,6 @@ public class ResourceNode public readonly record struct UIData(string? Name, ChangedItemIcon Icon) { public readonly UIData PrependName(string prefix) - => Name == null ? this : new(prefix + Name, Icon); + => Name == null ? this : new UIData(prefix + Name, Icon); } } diff --git a/Penumbra/Interop/ResourceTree/ResourceTree.cs b/Penumbra/Interop/ResourceTree/ResourceTree.cs index d2276291..a8ad9d4f 100644 --- a/Penumbra/Interop/ResourceTree/ResourceTree.cs +++ b/Penumbra/Interop/ResourceTree/ResourceTree.cs @@ -1,6 +1,6 @@ using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Game.Object; -using FFXIVClientStructs.FFXIV.Client.Graphics.Render; +using FFXIVClientStructs.FFXIV.Client.Graphics.Render; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using Penumbra.GameData.Enums; using Penumbra.GameData.Structs; @@ -16,7 +16,7 @@ public class ResourceTree public readonly nint DrawObjectAddress; public readonly bool PlayerRelated; public readonly string CollectionName; - public readonly List Nodes; + public readonly List Nodes; public readonly HashSet FlatNodes; public int ModelId; @@ -26,11 +26,11 @@ public class ResourceTree public ResourceTree(string name, nint gameObjectAddress, nint drawObjectAddress, bool playerRelated, string collectionName) { Name = name; - GameObjectAddress = gameObjectAddress; + GameObjectAddress = gameObjectAddress; DrawObjectAddress = drawObjectAddress; PlayerRelated = playerRelated; CollectionName = collectionName; - Nodes = new List(); + Nodes = new List(); FlatNodes = new HashSet(); } @@ -42,7 +42,7 @@ public class ResourceTree // var customize = new ReadOnlySpan( character->CustomizeData, 26 ); ModelId = character->CharacterData.ModelCharaId; CustomizeData = character->DrawData.CustomizeData; - RaceCode = model->GetModelType() == CharacterBase.ModelType.Human ? (GenderRace) ((Human*)model)->RaceSexId : GenderRace.Unknown; + RaceCode = model->GetModelType() == CharacterBase.ModelType.Human ? (GenderRace)((Human*)model)->RaceSexId : GenderRace.Unknown; for (var i = 0; i < model->SlotCount; ++i) { @@ -60,8 +60,8 @@ public class ResourceTree var mdlNode = context.CreateNodeFromRenderModel(mdl); if (mdlNode != null) Nodes.Add(globalContext.WithUiData ? mdlNode.WithUIData(mdlNode.Name ?? $"Model #{i}", mdlNode.Icon) : mdlNode); - } - + } + AddSkeleton(Nodes, globalContext.CreateContext(EquipSlot.Unknown, default), model->Skeleton); if (character->GameObject.GetObjectKind() == (byte)ObjectKind.Pc) @@ -100,8 +100,8 @@ public class ResourceTree subObjectNodes.Add(globalContext.WithUiData ? mdlNode.WithUIData(mdlNode.Name ?? $"{subObjectNamePrefix} #{subObjectIndex}, Model #{i}", mdlNode.Icon) : mdlNode); - } - + } + AddSkeleton(subObjectNodes, subObjectContext, subObject->Skeleton, $"{subObjectNamePrefix} #{subObjectIndex}, "); subObject = (CharacterBase*)subObject->DrawObject.Object.NextSiblingObject; @@ -119,19 +119,21 @@ public class ResourceTree var legacyDecalNode = context.CreateNodeFromTex((TextureResourceHandle*)human->LegacyBodyDecal); if (legacyDecalNode != null) - Nodes.Add(globalContext.WithUiData ? legacyDecalNode.WithUIData(legacyDecalNode.Name ?? "Legacy Body Decal", legacyDecalNode.Icon) : legacyDecalNode); - } - - private unsafe void AddSkeleton(List nodes, ResolveContext context, Skeleton* skeleton, string prefix = "") - { - if (skeleton == null) - return; - - for (var i = 0; i < skeleton->PartialSkeletonCount; ++i) - { - var sklbNode = context.CreateNodeFromPartialSkeleton(&skeleton->PartialSkeletons[i]); - if (sklbNode != null) - nodes.Add(context.WithUiData ? sklbNode.WithUIData($"{prefix}Skeleton #{i}", sklbNode.Icon) : sklbNode); - } + Nodes.Add(globalContext.WithUiData + ? legacyDecalNode.WithUIData(legacyDecalNode.Name ?? "Legacy Body Decal", legacyDecalNode.Icon) + : legacyDecalNode); + } + + private unsafe void AddSkeleton(List nodes, ResolveContext context, Skeleton* skeleton, string prefix = "") + { + if (skeleton == null) + return; + + for (var i = 0; i < skeleton->PartialSkeletonCount; ++i) + { + var sklbNode = context.CreateNodeFromPartialSkeleton(&skeleton->PartialSkeletons[i]); + if (sklbNode != null) + nodes.Add(context.WithUiData ? sklbNode.WithUIData($"{prefix}Skeleton #{i}", sklbNode.Icon) : sklbNode); + } } } diff --git a/Penumbra/Interop/SafeHandles/SafeResourceHandle.cs b/Penumbra/Interop/SafeHandles/SafeResourceHandle.cs index 8dd1fb4a..1f788a39 100644 --- a/Penumbra/Interop/SafeHandles/SafeResourceHandle.cs +++ b/Penumbra/Interop/SafeHandles/SafeResourceHandle.cs @@ -4,21 +4,25 @@ namespace Penumbra.Interop.SafeHandles; public unsafe class SafeResourceHandle : SafeHandle { - public ResourceHandle* ResourceHandle => (ResourceHandle*)handle; + public ResourceHandle* ResourceHandle + => (ResourceHandle*)handle; - public override bool IsInvalid => handle == 0; + public override bool IsInvalid + => handle == 0; - public SafeResourceHandle(ResourceHandle* handle, bool incRef, bool ownsHandle = true) : base(0, ownsHandle) + public SafeResourceHandle(ResourceHandle* handle, bool incRef, bool ownsHandle = true) + : base(0, ownsHandle) { if (incRef && !ownsHandle) throw new ArgumentException("Non-owning SafeResourceHandle with IncRef is unsupported"); + if (incRef && handle != null) handle->IncRef(); SetHandle((nint)handle); } public static SafeResourceHandle CreateInvalid() - => new(null, incRef: false); + => new(null, false); protected override bool ReleaseHandle() { diff --git a/Penumbra/Interop/SafeHandles/SafeTextureHandle.cs b/Penumbra/Interop/SafeHandles/SafeTextureHandle.cs index 88c97c54..dee28797 100644 --- a/Penumbra/Interop/SafeHandles/SafeTextureHandle.cs +++ b/Penumbra/Interop/SafeHandles/SafeTextureHandle.cs @@ -5,14 +5,18 @@ namespace Penumbra.Interop.SafeHandles; public unsafe class SafeTextureHandle : SafeHandle { - public Texture* Texture => (Texture*)handle; + public Texture* Texture + => (Texture*)handle; - public override bool IsInvalid => handle == 0; + public override bool IsInvalid + => handle == 0; - public SafeTextureHandle(Texture* handle, bool incRef, bool ownsHandle = true) : base(0, ownsHandle) + public SafeTextureHandle(Texture* handle, bool incRef, bool ownsHandle = true) + : base(0, ownsHandle) { if (incRef && !ownsHandle) throw new ArgumentException("Non-owning SafeTextureHandle with IncRef is unsupported"); + if (incRef && handle != null) TextureUtility.IncRef(handle); SetHandle((nint)handle); @@ -27,16 +31,17 @@ public unsafe class SafeTextureHandle : SafeHandle } public static SafeTextureHandle CreateInvalid() - => new(null, incRef: false); + => new(null, false); protected override bool ReleaseHandle() { nint handle; lock (this) { - handle = this.handle; + handle = this.handle; this.handle = 0; } + if (handle != 0) TextureUtility.DecRef((Texture*)handle); diff --git a/Penumbra/Interop/Services/DecalReverter.cs b/Penumbra/Interop/Services/DecalReverter.cs index 21fa87a1..18c88766 100644 --- a/Penumbra/Interop/Services/DecalReverter.cs +++ b/Penumbra/Interop/Services/DecalReverter.cs @@ -14,7 +14,7 @@ public sealed unsafe class DecalReverter : IDisposable public static readonly Utf8GamePath TransparentPath = Utf8GamePath.FromSpan("chara/common/texture/transparent.tex"u8, out var p) ? p : Utf8GamePath.Empty; - private readonly CharacterUtility _utility; + private readonly CharacterUtility _utility; private readonly Structs.TextureResourceHandle* _decal; private readonly Structs.TextureResourceHandle* _transparent; @@ -22,10 +22,10 @@ public sealed unsafe class DecalReverter : IDisposable { _utility = utility; var ptr = _utility.Address; - _decal = null; + _decal = null; _transparent = null; if (!config.EnableMods) - return; + return; if (doDecal) { diff --git a/Penumbra/Interop/Services/GameEventManager.cs b/Penumbra/Interop/Services/GameEventManager.cs index ca333ed4..2e8a23f0 100644 --- a/Penumbra/Interop/Services/GameEventManager.cs +++ b/Penumbra/Interop/Services/GameEventManager.cs @@ -152,7 +152,7 @@ public unsafe class GameEventManager : IDisposable { try { - ((CreatingCharacterBaseEvent)subscriber).Invoke((nint) (&a), b, c); + ((CreatingCharacterBaseEvent)subscriber).Invoke((nint)(&a), b, c); } catch (Exception ex) { @@ -265,11 +265,13 @@ public unsafe class GameEventManager : IDisposable private readonly Hook? _testHook = null; private delegate void TestDelegate(nint a1, int a2); + private void TestDetour(nint a1, int a2) { Penumbra.Log.Information($"Test: {a1:X} {a2}"); _testHook!.Original(a1, a2); } + private void EnableDebugHook() => _testHook?.Enable(); diff --git a/Penumbra/Interop/Services/RedrawService.cs b/Penumbra/Interop/Services/RedrawService.cs index 0b9c6c38..65d5b0c0 100644 --- a/Penumbra/Interop/Services/RedrawService.cs +++ b/Penumbra/Interop/Services/RedrawService.cs @@ -100,10 +100,10 @@ public unsafe partial class RedrawService public sealed unsafe partial class RedrawService : IDisposable { - private readonly Framework _framework; + private readonly Framework _framework; private readonly IObjectTable _objects; private readonly ITargetManager _targets; - private readonly Condition _conditions; + private readonly Condition _conditions; private readonly List _queue = new(100); private readonly List _afterGPoseQueue = new(GPoseSlots); @@ -207,7 +207,7 @@ public sealed unsafe partial class RedrawService : IDisposable return; _targets.Target = actor; - _target = -1; + _target = -1; } private void HandleRedraw() diff --git a/Penumbra/Interop/Services/ResidentResourceManager.cs b/Penumbra/Interop/Services/ResidentResourceManager.cs index cd20b889..ff7f95a5 100644 --- a/Penumbra/Interop/Services/ResidentResourceManager.cs +++ b/Penumbra/Interop/Services/ResidentResourceManager.cs @@ -1,6 +1,6 @@ using Dalamud.Utility.Signatures; using Penumbra.GameData; - + namespace Penumbra.Interop.Services; public unsafe class ResidentResourceManager @@ -36,4 +36,4 @@ public unsafe class ResidentResourceManager LoadPlayerResources.Invoke(Address); } } -} \ No newline at end of file +} diff --git a/Penumbra/Interop/Structs/CharacterUtilityData.cs b/Penumbra/Interop/Structs/CharacterUtilityData.cs index 87d9566c..08857292 100644 --- a/Penumbra/Interop/Structs/CharacterUtilityData.cs +++ b/Penumbra/Interop/Structs/CharacterUtilityData.cs @@ -2,23 +2,23 @@ using Penumbra.GameData.Enums; namespace Penumbra.Interop.Structs; -[StructLayout( LayoutKind.Explicit )] +[StructLayout(LayoutKind.Explicit)] public unsafe struct CharacterUtilityData { public const int IndexTransparentTex = 72; public const int IndexDecalTex = 73; public const int IndexSkinShpk = 76; - public static readonly MetaIndex[] EqdpIndices = Enum.GetNames< MetaIndex >() - .Zip( Enum.GetValues< MetaIndex >() ) - .Where( n => n.First.StartsWith( "Eqdp" ) ) - .Select( n => n.Second ).ToArray(); + public static readonly MetaIndex[] EqdpIndices = Enum.GetNames() + .Zip(Enum.GetValues()) + .Where(n => n.First.StartsWith("Eqdp")) + .Select(n => n.Second).ToArray(); public const int TotalNumResources = 87; /// Obtain the index for the eqdp file corresponding to the given race code and accessory. - public static MetaIndex EqdpIdx( GenderRace raceCode, bool accessory ) - => +( int )raceCode switch + public static MetaIndex EqdpIdx(GenderRace raceCode, bool accessory) + => +(int)raceCode switch { 0101 => accessory ? MetaIndex.Eqdp0101Acc : MetaIndex.Eqdp0101, 0201 => accessory ? MetaIndex.Eqdp0201Acc : MetaIndex.Eqdp0201, @@ -48,53 +48,53 @@ public unsafe struct CharacterUtilityData 1404 => accessory ? MetaIndex.Eqdp1404Acc : MetaIndex.Eqdp1404, 9104 => accessory ? MetaIndex.Eqdp9104Acc : MetaIndex.Eqdp9104, 9204 => accessory ? MetaIndex.Eqdp9204Acc : MetaIndex.Eqdp9204, - _ => ( MetaIndex )( -1 ), + _ => (MetaIndex)(-1), }; - [FieldOffset( 0 )] + [FieldOffset(0)] public void* VTable; - [FieldOffset( 8 )] + [FieldOffset(8)] public fixed ulong Resources[TotalNumResources]; - [FieldOffset( 8 + ( int )MetaIndex.Eqp * 8 )] + [FieldOffset(8 + (int)MetaIndex.Eqp * 8)] public ResourceHandle* EqpResource; - [FieldOffset( 8 + ( int )MetaIndex.Gmp * 8 )] + [FieldOffset(8 + (int)MetaIndex.Gmp * 8)] public ResourceHandle* GmpResource; - public ResourceHandle* Resource( int idx ) - => ( ResourceHandle* )Resources[ idx ]; + public ResourceHandle* Resource(int idx) + => (ResourceHandle*)Resources[idx]; - public ResourceHandle* Resource( MetaIndex idx ) - => Resource( ( int )idx ); + public ResourceHandle* Resource(MetaIndex idx) + => Resource((int)idx); - public ResourceHandle* EqdpResource( GenderRace raceCode, bool accessory ) - => Resource( ( int )EqdpIdx( raceCode, accessory ) ); + public ResourceHandle* EqdpResource(GenderRace raceCode, bool accessory) + => Resource((int)EqdpIdx(raceCode, accessory)); - [FieldOffset( 8 + ( int )MetaIndex.HumanCmp * 8 )] + [FieldOffset(8 + (int)MetaIndex.HumanCmp * 8)] public ResourceHandle* HumanCmpResource; - [FieldOffset( 8 + ( int )MetaIndex.FaceEst * 8 )] + [FieldOffset(8 + (int)MetaIndex.FaceEst * 8)] public ResourceHandle* FaceEstResource; - [FieldOffset( 8 + ( int )MetaIndex.HairEst * 8 )] + [FieldOffset(8 + (int)MetaIndex.HairEst * 8)] public ResourceHandle* HairEstResource; - [FieldOffset( 8 + ( int )MetaIndex.BodyEst * 8 )] + [FieldOffset(8 + (int)MetaIndex.BodyEst * 8)] public ResourceHandle* BodyEstResource; - [FieldOffset( 8 + ( int )MetaIndex.HeadEst * 8 )] + [FieldOffset(8 + (int)MetaIndex.HeadEst * 8)] public ResourceHandle* HeadEstResource; - [FieldOffset( 8 + IndexTransparentTex * 8 )] + [FieldOffset(8 + IndexTransparentTex * 8)] public TextureResourceHandle* TransparentTexResource; - [FieldOffset( 8 + IndexDecalTex * 8 )] + [FieldOffset(8 + IndexDecalTex * 8)] public TextureResourceHandle* DecalTexResource; - [FieldOffset( 8 + IndexSkinShpk * 8 )] + [FieldOffset(8 + IndexSkinShpk * 8)] public ResourceHandle* SkinShpkResource; // not included resources have no known use case. -} \ No newline at end of file +} diff --git a/Penumbra/Interop/Structs/ClipScheduler.cs b/Penumbra/Interop/Structs/ClipScheduler.cs index c8fd082d..3211c4f9 100644 --- a/Penumbra/Interop/Structs/ClipScheduler.cs +++ b/Penumbra/Interop/Structs/ClipScheduler.cs @@ -1,11 +1,11 @@ namespace Penumbra.Interop.Structs; -[StructLayout( LayoutKind.Explicit )] +[StructLayout(LayoutKind.Explicit)] public unsafe struct ClipScheduler { - [FieldOffset( 0 )] + [FieldOffset(0)] public IntPtr* VTable; - [FieldOffset( 0x38 )] + [FieldOffset(0x38)] public IntPtr SchedulerTimeline; -} \ No newline at end of file +} diff --git a/Penumbra/Interop/Structs/DrawState.cs b/Penumbra/Interop/Structs/DrawState.cs index d0dfc22b..200e7952 100644 --- a/Penumbra/Interop/Structs/DrawState.cs +++ b/Penumbra/Interop/Structs/DrawState.cs @@ -9,4 +9,4 @@ public enum DrawState : uint MaybeCulled = 0x00_00_04_00, MaybeHiddenMinion = 0x00_00_80_00, MaybeHiddenSummon = 0x00_80_00_00, -} \ No newline at end of file +} diff --git a/Penumbra/Interop/Structs/FileMode.cs b/Penumbra/Interop/Structs/FileMode.cs index 1c1914b2..4e48b3c1 100644 --- a/Penumbra/Interop/Structs/FileMode.cs +++ b/Penumbra/Interop/Structs/FileMode.cs @@ -8,4 +8,4 @@ public enum FileMode : byte // Probably debug options only. LoadIndexResource = 0xA, // load index/index2 LoadSqPackResource = 0xB, -} \ No newline at end of file +} diff --git a/Penumbra/Interop/Structs/HumanExt.cs b/Penumbra/Interop/Structs/HumanExt.cs index 5eafa1f3..274b4fb2 100644 --- a/Penumbra/Interop/Structs/HumanExt.cs +++ b/Penumbra/Interop/Structs/HumanExt.cs @@ -2,18 +2,18 @@ using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; namespace Penumbra.Interop.Structs; -[StructLayout( LayoutKind.Explicit )] +[StructLayout(LayoutKind.Explicit)] public unsafe struct HumanExt { - [FieldOffset( 0x0 )] + [FieldOffset(0x0)] public Human Human; - [FieldOffset( 0x0 )] + [FieldOffset(0x0)] public CharacterBaseExt CharacterBase; - [FieldOffset( 0x9E8 )] + [FieldOffset(0x9E8)] public ResourceHandle* Decal; - [FieldOffset( 0x9F0 )] + [FieldOffset(0x9F0)] public ResourceHandle* LegacyBodyDecal; -} \ No newline at end of file +} diff --git a/Penumbra/Interop/Structs/Material.cs b/Penumbra/Interop/Structs/Material.cs index 2bca832d..0165a8ff 100644 --- a/Penumbra/Interop/Structs/Material.cs +++ b/Penumbra/Interop/Structs/Material.cs @@ -2,45 +2,46 @@ using FFXIVClientStructs.FFXIV.Client.Graphics.Render; namespace Penumbra.Interop.Structs; -[StructLayout( LayoutKind.Explicit, Size = 0x40 )] +[StructLayout(LayoutKind.Explicit, Size = 0x40)] public unsafe struct Material { - [FieldOffset( 0x10 )] + [FieldOffset(0x10)] public MtrlResource* ResourceHandle; - [FieldOffset( 0x18 )] + [FieldOffset(0x18)] public uint ShaderPackageFlags; - [FieldOffset( 0x20 )] + [FieldOffset(0x20)] public uint* ShaderKeys; public int ShaderKeyCount => (int)((uint*)Textures - ShaderKeys); - [FieldOffset( 0x28 )] + [FieldOffset(0x28)] public ConstantBuffer* MaterialParameter; - [FieldOffset( 0x30 )] + [FieldOffset(0x30)] public TextureEntry* Textures; - [FieldOffset( 0x38 )] + [FieldOffset(0x38)] public ushort TextureCount; - public Texture* Texture( int index ) => Textures[index].ResourceHandle->KernelTexture; + public Texture* Texture(int index) + => Textures[index].ResourceHandle->KernelTexture; - [StructLayout( LayoutKind.Explicit, Size = 0x18 )] + [StructLayout(LayoutKind.Explicit, Size = 0x18)] public struct TextureEntry { - [FieldOffset( 0x00 )] + [FieldOffset(0x00)] public uint Id; - [FieldOffset( 0x08 )] + [FieldOffset(0x08)] public TextureResourceHandle* ResourceHandle; - [FieldOffset( 0x10 )] + [FieldOffset(0x10)] public uint SamplerFlags; } public ReadOnlySpan TextureSpan - => new(Textures, TextureCount); -} \ No newline at end of file + => new(Textures, TextureCount); +} diff --git a/Penumbra/Interop/Structs/MtrlResource.cs b/Penumbra/Interop/Structs/MtrlResource.cs index 55c7f8d8..c3b86e14 100644 --- a/Penumbra/Interop/Structs/MtrlResource.cs +++ b/Penumbra/Interop/Structs/MtrlResource.cs @@ -1,45 +1,45 @@ namespace Penumbra.Interop.Structs; -[StructLayout( LayoutKind.Explicit )] +[StructLayout(LayoutKind.Explicit)] public unsafe struct MtrlResource { - [FieldOffset( 0x00 )] + [FieldOffset(0x00)] public ResourceHandle Handle; - [FieldOffset( 0xC8 )] + [FieldOffset(0xC8)] public ShaderPackageResourceHandle* ShpkResourceHandle; - [FieldOffset( 0xD0 )] + [FieldOffset(0xD0)] public TextureEntry* TexSpace; // Contains the offsets for the tex files inside the string list. - [FieldOffset( 0xE0 )] + [FieldOffset(0xE0)] public byte* StringList; - [FieldOffset( 0xF8 )] + [FieldOffset(0xF8)] public ushort ShpkOffset; - [FieldOffset( 0xFA )] + [FieldOffset(0xFA)] public byte NumTex; public byte* ShpkString => StringList + ShpkOffset; - public byte* TexString( int idx ) + public byte* TexString(int idx) => StringList + TexSpace[idx].PathOffset; - public bool TexIsDX11( int idx ) + public bool TexIsDX11(int idx) => TexSpace[idx].Flags >= 0x8000; [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct TextureEntry { - [FieldOffset( 0x00 )] + [FieldOffset(0x00)] public TextureResourceHandle* ResourceHandle; - [FieldOffset( 0x08 )] + [FieldOffset(0x08)] public ushort PathOffset; - [FieldOffset( 0x0A )] + [FieldOffset(0x0A)] public ushort Flags; } -} \ No newline at end of file +} diff --git a/Penumbra/Interop/Structs/RenderModel.cs b/Penumbra/Interop/Structs/RenderModel.cs index 25e928be..f9cb2d56 100644 --- a/Penumbra/Interop/Structs/RenderModel.cs +++ b/Penumbra/Interop/Structs/RenderModel.cs @@ -2,39 +2,39 @@ using FFXIVClientStructs.FFXIV.Client.Graphics.Render; namespace Penumbra.Interop.Structs; -[StructLayout( LayoutKind.Explicit )] +[StructLayout(LayoutKind.Explicit)] public unsafe struct RenderModel { - [FieldOffset( 0x18 )] + [FieldOffset(0x18)] public RenderModel* PreviousModel; - [FieldOffset( 0x20 )] + [FieldOffset(0x20)] public RenderModel* NextModel; - [FieldOffset( 0x30 )] + [FieldOffset(0x30)] public ResourceHandle* ResourceHandle; - [FieldOffset( 0x40 )] + [FieldOffset(0x40)] public Skeleton* Skeleton; - [FieldOffset( 0x58 )] + [FieldOffset(0x58)] public void** BoneList; - [FieldOffset( 0x60 )] + [FieldOffset(0x60)] public int BoneListCount; - [FieldOffset( 0x70 )] + [FieldOffset(0x70)] private void* UnkDXBuffer1; - [FieldOffset( 0x78 )] + [FieldOffset(0x78)] private void* UnkDXBuffer2; - [FieldOffset( 0x80 )] + [FieldOffset(0x80)] private void* UnkDXBuffer3; - [FieldOffset( 0x98 )] + [FieldOffset(0x98)] public void** Materials; - [FieldOffset( 0xA0 )] + [FieldOffset(0xA0)] public int MaterialCount; -} \ No newline at end of file +} diff --git a/Penumbra/Interop/Structs/ResidentResourceManager.cs b/Penumbra/Interop/Structs/ResidentResourceManager.cs index 08461b03..131f2884 100644 --- a/Penumbra/Interop/Structs/ResidentResourceManager.cs +++ b/Penumbra/Interop/Structs/ResidentResourceManager.cs @@ -3,15 +3,15 @@ namespace Penumbra.Interop.Structs; [StructLayout(LayoutKind.Explicit)] public unsafe struct ResidentResourceManager { - [FieldOffset( 0x00 )] + [FieldOffset(0x00)] public void** VTable; - [FieldOffset( 0x08 )] + [FieldOffset(0x08)] public void** ResourceListVTable; - [FieldOffset( 0x14 )] + [FieldOffset(0x14)] public uint NumResources; - [FieldOffset( 0x18 )] + [FieldOffset(0x18)] public ResourceHandle** ResourceList; -} \ No newline at end of file +} diff --git a/Penumbra/Interop/Structs/ResourceHandle.cs b/Penumbra/Interop/Structs/ResourceHandle.cs index b23cf62f..dba113f3 100644 --- a/Penumbra/Interop/Structs/ResourceHandle.cs +++ b/Penumbra/Interop/Structs/ResourceHandle.cs @@ -8,45 +8,45 @@ using Penumbra.String.Classes; namespace Penumbra.Interop.Structs; -[StructLayout( LayoutKind.Explicit )] +[StructLayout(LayoutKind.Explicit)] public unsafe struct TextureResourceHandle { - [FieldOffset( 0x0 )] + [FieldOffset(0x0)] public ResourceHandle Handle; - [FieldOffset( 0x38 )] + [FieldOffset(0x38)] public IntPtr Unk; - [FieldOffset( 0x118 )] + [FieldOffset(0x118)] public Texture* KernelTexture; - [FieldOffset( 0x20 )] + [FieldOffset(0x20)] public IntPtr NewKernelTexture; } [StructLayout(LayoutKind.Explicit)] public unsafe struct ShaderPackageResourceHandle { - [FieldOffset( 0x0 )] + [FieldOffset(0x0)] public ResourceHandle Handle; - [FieldOffset( 0xB0 )] + [FieldOffset(0xB0)] public ShaderPackage* ShaderPackage; } -[StructLayout( LayoutKind.Explicit )] +[StructLayout(LayoutKind.Explicit)] public unsafe struct ResourceHandle { - [StructLayout( LayoutKind.Explicit )] + [StructLayout(LayoutKind.Explicit)] public struct DataIndirection { - [FieldOffset( 0x00 )] + [FieldOffset(0x00)] public void** VTable; - [FieldOffset( 0x10 )] + [FieldOffset(0x10)] public byte* DataPtr; - [FieldOffset( 0x28 )] + [FieldOffset(0x28)] public ulong DataLength; } @@ -54,87 +54,83 @@ public unsafe struct ResourceHandle public byte* FileNamePtr() { - if( FileNameLength > SsoSize ) - { + if (FileNameLength > SsoSize) return FileNameData; - } - fixed( byte** name = &FileNameData ) + fixed (byte** name = &FileNameData) { - return ( byte* )name; + return (byte*)name; } } public ByteString FileName() - => ByteString.FromByteStringUnsafe( FileNamePtr(), FileNameLength, true ); + => ByteString.FromByteStringUnsafe(FileNamePtr(), FileNameLength, true); - public ReadOnlySpan< byte > FileNameAsSpan() - => new( FileNamePtr(), FileNameLength ); + public ReadOnlySpan FileNameAsSpan() + => new(FileNamePtr(), FileNameLength); - public bool GamePath( out Utf8GamePath path ) - => Utf8GamePath.FromSpan( FileNameAsSpan(), out path ); + public bool GamePath(out Utf8GamePath path) + => Utf8GamePath.FromSpan(FileNameAsSpan(), out path); - [FieldOffset( 0x00 )] + [FieldOffset(0x00)] public void** VTable; - [FieldOffset( 0x08 )] + [FieldOffset(0x08)] public ResourceCategory Category; - [FieldOffset( 0x0C )] + [FieldOffset(0x0C)] public ResourceType FileType; - [FieldOffset( 0x10 )] + [FieldOffset(0x10)] public uint Id; - [FieldOffset( 0x28 )] + [FieldOffset(0x28)] public uint FileSize; - [FieldOffset( 0x2C )] + [FieldOffset(0x2C)] public uint FileSize2; - [FieldOffset( 0x34 )] + [FieldOffset(0x34)] public uint FileSize3; - [FieldOffset( 0x48 )] + [FieldOffset(0x48)] public byte* FileNameData; - [FieldOffset( 0x58 )] + [FieldOffset(0x58)] public int FileNameLength; - [FieldOffset( 0xAC )] + [FieldOffset(0xAC)] public uint RefCount; // May return null. - public static byte* GetData( ResourceHandle* handle ) - => ( ( delegate* unmanaged< ResourceHandle*, byte* > )handle->VTable[ Offsets.ResourceHandleGetDataVfunc ] )( handle ); + public static byte* GetData(ResourceHandle* handle) + => ((delegate* unmanaged< ResourceHandle*, byte* >)handle->VTable[Offsets.ResourceHandleGetDataVfunc])(handle); - public static ulong GetLength( ResourceHandle* handle ) - => ( ( delegate* unmanaged< ResourceHandle*, ulong > )handle->VTable[ Offsets.ResourceHandleGetLengthVfunc ] )( handle ); + public static ulong GetLength(ResourceHandle* handle) + => ((delegate* unmanaged< ResourceHandle*, ulong >)handle->VTable[Offsets.ResourceHandleGetLengthVfunc])(handle); // Only use these if you know what you are doing. // Those are actually only sure to be accessible for DefaultResourceHandles. - [FieldOffset( 0xB0 )] + [FieldOffset(0xB0)] public DataIndirection* Data; - [FieldOffset( 0xB8 )] + [FieldOffset(0xB8)] public uint DataLength; public (IntPtr Data, int Length) GetData() => Data != null - ? ( ( IntPtr )Data->DataPtr, ( int )Data->DataLength ) - : ( IntPtr.Zero, 0 ); + ? ((IntPtr)Data->DataPtr, (int)Data->DataLength) + : (IntPtr.Zero, 0); - public bool SetData( IntPtr data, int length ) + public bool SetData(IntPtr data, int length) { - if( Data == null ) - { + if (Data == null) return false; - } - Data->DataPtr = length != 0 ? ( byte* )data : null; - Data->DataLength = ( ulong )length; - DataLength = ( uint )length; + Data->DataPtr = length != 0 ? (byte*)data : null; + Data->DataLength = (ulong)length; + DataLength = (uint)length; return true; } -} \ No newline at end of file +} diff --git a/Penumbra/Interop/Structs/SeFileDescriptor.cs b/Penumbra/Interop/Structs/SeFileDescriptor.cs index d4ca3afa..67730799 100644 --- a/Penumbra/Interop/Structs/SeFileDescriptor.cs +++ b/Penumbra/Interop/Structs/SeFileDescriptor.cs @@ -1,18 +1,17 @@ namespace Penumbra.Interop.Structs; -[StructLayout( LayoutKind.Explicit )] +[StructLayout(LayoutKind.Explicit)] public unsafe struct SeFileDescriptor { - [FieldOffset( 0x00 )] + [FieldOffset(0x00)] public FileMode FileMode; - [FieldOffset( 0x30 )] - public void* FileDescriptor; // + [FieldOffset(0x30)] + public void* FileDescriptor; - [FieldOffset( 0x50 )] - public ResourceHandle* ResourceHandle; // + [FieldOffset(0x50)] + public ResourceHandle* ResourceHandle; - - [FieldOffset( 0x70 )] - public char Utf16FileName; // -} \ No newline at end of file + [FieldOffset(0x70)] + public char Utf16FileName; +} diff --git a/Penumbra/Interop/Structs/TextureUtility.cs b/Penumbra/Interop/Structs/TextureUtility.cs index ec9c4b71..a81480fb 100644 --- a/Penumbra/Interop/Structs/TextureUtility.cs +++ b/Penumbra/Interop/Structs/TextureUtility.cs @@ -4,12 +4,13 @@ using FFXIVClientStructs.FFXIV.Client.Graphics.Render; namespace Penumbra.Interop.Structs; -public unsafe static class TextureUtility +public static unsafe class TextureUtility { private static readonly Functions Funcs = new(); public static Texture* Create2D(Device* device, int* size, byte mipLevel, uint textureFormat, uint flags, uint unk) - => ((delegate* unmanaged)Funcs.TextureCreate2D)(device, size, mipLevel, textureFormat, flags, unk); + => ((delegate* unmanaged)Funcs.TextureCreate2D)(device, size, mipLevel, textureFormat, + flags, unk); public static bool InitializeContents(Texture* texture, void* contents) => ((delegate* unmanaged)Funcs.TextureInitializeContents)(texture, contents); diff --git a/Penumbra/Interop/Structs/VfxParams.cs b/Penumbra/Interop/Structs/VfxParams.cs index 76dbd3ed..c3ae1751 100644 --- a/Penumbra/Interop/Structs/VfxParams.cs +++ b/Penumbra/Interop/Structs/VfxParams.cs @@ -1,17 +1,17 @@ namespace Penumbra.Interop.Structs; -[StructLayout( LayoutKind.Explicit )] +[StructLayout(LayoutKind.Explicit)] public unsafe struct VfxParams { - [FieldOffset( 0x118 )] + [FieldOffset(0x118)] public uint GameObjectId; - [FieldOffset( 0x11C )] + [FieldOffset(0x11C)] public byte GameObjectType; - [FieldOffset( 0xD0 )] + [FieldOffset(0xD0)] public ushort TargetCount; - [FieldOffset( 0x120 )] + [FieldOffset(0x120)] public fixed ulong Target[16]; -} \ No newline at end of file +} diff --git a/Penumbra/Meta/Manipulations/EqdpManipulation.cs b/Penumbra/Meta/Manipulations/EqdpManipulation.cs index 1e0756f2..df7ed2e4 100644 --- a/Penumbra/Meta/Manipulations/EqdpManipulation.cs +++ b/Penumbra/Meta/Manipulations/EqdpManipulation.cs @@ -101,8 +101,8 @@ public readonly struct EqdpManipulation : IMetaManipulation if (FileIndex() == (MetaIndex)(-1)) return false; - - // No check for set id. + + // No check for set id. return true; } } diff --git a/Penumbra/Meta/Manipulations/EqpManipulation.cs b/Penumbra/Meta/Manipulations/EqpManipulation.cs index 8e1a2ded..4373e8e9 100644 --- a/Penumbra/Meta/Manipulations/EqpManipulation.cs +++ b/Penumbra/Meta/Manipulations/EqpManipulation.cs @@ -9,73 +9,71 @@ using SharpCompress.Common; namespace Penumbra.Meta.Manipulations; -[StructLayout( LayoutKind.Sequential, Pack = 1 )] -public readonly struct EqpManipulation : IMetaManipulation< EqpManipulation > +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public readonly struct EqpManipulation : IMetaManipulation { - [JsonConverter( typeof( ForceNumericFlagEnumConverter ) )] + [JsonConverter(typeof(ForceNumericFlagEnumConverter))] public EqpEntry Entry { get; private init; } public SetId SetId { get; private init; } - [JsonConverter( typeof( StringEnumConverter ) )] + [JsonConverter(typeof(StringEnumConverter))] public EquipSlot Slot { get; private init; } [JsonConstructor] - public EqpManipulation( EqpEntry entry, EquipSlot slot, SetId setId ) + public EqpManipulation(EqpEntry entry, EquipSlot slot, SetId setId) { Slot = slot; SetId = setId; - Entry = Eqp.Mask( slot ) & entry; + Entry = Eqp.Mask(slot) & entry; } - public EqpManipulation Copy( EqpEntry entry ) + public EqpManipulation Copy(EqpEntry entry) => new(entry, Slot, SetId); public override string ToString() => $"Eqp - {SetId} - {Slot}"; - public bool Equals( EqpManipulation other ) - => Slot == other.Slot + public bool Equals(EqpManipulation other) + => Slot == other.Slot && SetId == other.SetId; - public override bool Equals( object? obj ) - => obj is EqpManipulation other && Equals( other ); + public override bool Equals(object? obj) + => obj is EqpManipulation other && Equals(other); public override int GetHashCode() - => HashCode.Combine( ( int )Slot, SetId ); + => HashCode.Combine((int)Slot, SetId); - public int CompareTo( EqpManipulation other ) + public int CompareTo(EqpManipulation other) { - var set = SetId.Id.CompareTo( other.SetId.Id ); - return set != 0 ? set : Slot.CompareTo( other.Slot ); + var set = SetId.Id.CompareTo(other.SetId.Id); + return set != 0 ? set : Slot.CompareTo(other.Slot); } public MetaIndex FileIndex() => MetaIndex.Eqp; - public bool Apply( ExpandedEqpFile file ) + public bool Apply(ExpandedEqpFile file) { - var entry = file[ SetId ]; - var mask = Eqp.Mask( Slot ); - if( ( entry & mask ) == Entry ) - { + var entry = file[SetId]; + var mask = Eqp.Mask(Slot); + if ((entry & mask) == Entry) return false; - } - file[ SetId ] = ( entry & ~mask ) | Entry; + file[SetId] = (entry & ~mask) | Entry; return true; } public bool Validate() - { + { var mask = Eqp.Mask(Slot); if (mask == 0) return false; if ((Entry & mask) != Entry) return false; - - // No check for set id. + + // No check for set id. return true; } -} \ No newline at end of file +} diff --git a/Penumbra/Meta/Manipulations/EstManipulation.cs b/Penumbra/Meta/Manipulations/EstManipulation.cs index da834b35..455c39ff 100644 --- a/Penumbra/Meta/Manipulations/EstManipulation.cs +++ b/Penumbra/Meta/Manipulations/EstManipulation.cs @@ -7,8 +7,8 @@ using Penumbra.Meta.Files; namespace Penumbra.Meta.Manipulations; -[StructLayout( LayoutKind.Sequential, Pack = 1 )] -public readonly struct EstManipulation : IMetaManipulation< EstManipulation > +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public readonly struct EstManipulation : IMetaManipulation { public enum EstType : byte { @@ -18,7 +18,7 @@ public readonly struct EstManipulation : IMetaManipulation< EstManipulation > Head = MetaIndex.HeadEst, } - public static string ToName( EstType type ) + public static string ToName(EstType type) => type switch { EstType.Hair => "hair", @@ -30,19 +30,19 @@ public readonly struct EstManipulation : IMetaManipulation< EstManipulation > public ushort Entry { get; private init; } // SkeletonIdx. - [JsonConverter( typeof( StringEnumConverter ) )] + [JsonConverter(typeof(StringEnumConverter))] public Gender Gender { get; private init; } - [JsonConverter( typeof( StringEnumConverter ) )] + [JsonConverter(typeof(StringEnumConverter))] public ModelRace Race { get; private init; } public SetId SetId { get; private init; } - [JsonConverter( typeof( StringEnumConverter ) )] + [JsonConverter(typeof(StringEnumConverter))] public EstType Slot { get; private init; } [JsonConstructor] - public EstManipulation( Gender gender, ModelRace race, EstType slot, SetId setId, ushort entry ) + public EstManipulation(Gender gender, ModelRace race, EstType slot, SetId setId, ushort entry) { Entry = entry; Gender = gender; @@ -51,49 +51,45 @@ public readonly struct EstManipulation : IMetaManipulation< EstManipulation > Slot = slot; } - public EstManipulation Copy( ushort entry ) + public EstManipulation Copy(ushort entry) => new(Gender, Race, Slot, SetId, entry); public override string ToString() => $"Est - {SetId} - {Slot} - {Race.ToName()} {Gender.ToName()}"; - public bool Equals( EstManipulation other ) + public bool Equals(EstManipulation other) => Gender == other.Gender - && Race == other.Race + && Race == other.Race && SetId == other.SetId - && Slot == other.Slot; + && Slot == other.Slot; - public override bool Equals( object? obj ) - => obj is EstManipulation other && Equals( other ); + public override bool Equals(object? obj) + => obj is EstManipulation other && Equals(other); public override int GetHashCode() - => HashCode.Combine( ( int )Gender, ( int )Race, SetId, ( int )Slot ); + => HashCode.Combine((int)Gender, (int)Race, SetId, (int)Slot); - public int CompareTo( EstManipulation other ) + public int CompareTo(EstManipulation other) { - var r = Race.CompareTo( other.Race ); - if( r != 0 ) - { + var r = Race.CompareTo(other.Race); + if (r != 0) return r; - } - var g = Gender.CompareTo( other.Gender ); - if( g != 0 ) - { + var g = Gender.CompareTo(other.Gender); + if (g != 0) return g; - } - var s = Slot.CompareTo( other.Slot ); - return s != 0 ? s : SetId.Id.CompareTo( other.SetId.Id ); + var s = Slot.CompareTo(other.Slot); + return s != 0 ? s : SetId.Id.CompareTo(other.SetId.Id); } public MetaIndex FileIndex() - => ( MetaIndex )Slot; + => (MetaIndex)Slot; - public bool Apply( EstFile file ) + public bool Apply(EstFile file) { - return file.SetEntry( Names.CombinedRace( Gender, Race ), SetId.Id, Entry ) switch + return file.SetEntry(Names.CombinedRace(Gender, Race), SetId.Id, Entry) switch { EstFile.EstEntryChange.Unchanged => false, EstFile.EstEntryChange.Changed => true, @@ -109,7 +105,8 @@ public readonly struct EstManipulation : IMetaManipulation< EstManipulation > return false; if (Names.CombinedRace(Gender, Race) == GenderRace.Unknown) return false; - // No known check for set id or entry. + + // No known check for set id or entry. return true; } -} \ No newline at end of file +} diff --git a/Penumbra/Meta/Manipulations/GmpManipulation.cs b/Penumbra/Meta/Manipulations/GmpManipulation.cs index 94f7f971..928b6f55 100644 --- a/Penumbra/Meta/Manipulations/GmpManipulation.cs +++ b/Penumbra/Meta/Manipulations/GmpManipulation.cs @@ -5,55 +5,51 @@ using Penumbra.Meta.Files; namespace Penumbra.Meta.Manipulations; -[StructLayout( LayoutKind.Sequential, Pack = 1 )] -public readonly struct GmpManipulation : IMetaManipulation< GmpManipulation > +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public readonly struct GmpManipulation : IMetaManipulation { public GmpEntry Entry { get; private init; } - public SetId SetId { get; private init; } + public SetId SetId { get; private init; } [JsonConstructor] - public GmpManipulation( GmpEntry entry, SetId setId ) + public GmpManipulation(GmpEntry entry, SetId setId) { Entry = entry; SetId = setId; } - public GmpManipulation Copy( GmpEntry entry ) + public GmpManipulation Copy(GmpEntry entry) => new(entry, SetId); public override string ToString() => $"Gmp - {SetId}"; - public bool Equals( GmpManipulation other ) + public bool Equals(GmpManipulation other) => SetId == other.SetId; - public override bool Equals( object? obj ) - => obj is GmpManipulation other && Equals( other ); + public override bool Equals(object? obj) + => obj is GmpManipulation other && Equals(other); public override int GetHashCode() => SetId.GetHashCode(); - public int CompareTo( GmpManipulation other ) - => SetId.Id.CompareTo( other.SetId.Id ); + public int CompareTo(GmpManipulation other) + => SetId.Id.CompareTo(other.SetId.Id); public MetaIndex FileIndex() => MetaIndex.Gmp; - public bool Apply( ExpandedGmpFile file ) + public bool Apply(ExpandedGmpFile file) { - var entry = file[ SetId ]; - if( entry == Entry ) - { + var entry = file[SetId]; + if (entry == Entry) return false; - } - file[ SetId ] = Entry; + file[SetId] = Entry; return true; } public bool Validate() - { // No known conditions. - return true; - } -} \ No newline at end of file + => true; +} diff --git a/Penumbra/Meta/MetaFileManager.cs b/Penumbra/Meta/MetaFileManager.cs index 2f19537b..3155e188 100644 --- a/Penumbra/Meta/MetaFileManager.cs +++ b/Penumbra/Meta/MetaFileManager.cs @@ -10,6 +10,7 @@ using Penumbra.Interop.Services; using Penumbra.Interop.Structs; using Penumbra.Meta.Files; using Penumbra.Mods; +using Penumbra.Mods.Subclasses; using Penumbra.Services; using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager; diff --git a/Penumbra/Mods/Editor/DuplicateManager.cs b/Penumbra/Mods/Editor/DuplicateManager.cs index 12fb4f35..488c1c91 100644 --- a/Penumbra/Mods/Editor/DuplicateManager.cs +++ b/Penumbra/Mods/Editor/DuplicateManager.cs @@ -59,7 +59,7 @@ public class DuplicateManager public void Clear() { _cancellationTokenSource.Cancel(); - Worker = Task.CompletedTask; + Worker = Task.CompletedTask; _duplicates.Clear(); SavedSpace = 0; } diff --git a/Penumbra/Mods/Editor/FileRegistry.cs b/Penumbra/Mods/Editor/FileRegistry.cs index 2100526a..0aa70e61 100644 --- a/Penumbra/Mods/Editor/FileRegistry.cs +++ b/Penumbra/Mods/Editor/FileRegistry.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using Penumbra.Mods.Subclasses; using Penumbra.String.Classes; namespace Penumbra.Mods; diff --git a/Penumbra/Mods/Editor/IMod.cs b/Penumbra/Mods/Editor/IMod.cs index 6fa645a9..cd8a9594 100644 --- a/Penumbra/Mods/Editor/IMod.cs +++ b/Penumbra/Mods/Editor/IMod.cs @@ -7,14 +7,14 @@ public interface IMod { LowerString Name { get; } - public int Index { get; } + public int Index { get; } public int Priority { get; } - public ISubMod Default { get; } - public IReadOnlyList< IModGroup > Groups { get; } + public ISubMod Default { get; } + public IReadOnlyList Groups { get; } - public IEnumerable< SubMod > AllSubMods { get; } - - // Cache + public IEnumerable AllSubMods { get; } + + // Cache public int TotalManipulations { get; } -} \ No newline at end of file +} diff --git a/Penumbra/Mods/Editor/ModBackup.cs b/Penumbra/Mods/Editor/ModBackup.cs index f4904271..8de93bcc 100644 --- a/Penumbra/Mods/Editor/ModBackup.cs +++ b/Penumbra/Mods/Editor/ModBackup.cs @@ -1,25 +1,26 @@ using System.IO.Compression; -using OtterGui.Tasks; +using OtterGui.Tasks; using Penumbra.Mods.Manager; namespace Penumbra.Mods.Editor; /// Utility to create and apply a zipped backup of a mod. public class ModBackup -{ +{ /// Set when reading Config and migrating from v4 to v5. public static bool MigrateModBackups = false; + public static bool CreatingBackup { get; private set; } - private readonly Mod _mod; - public readonly string Name; - public readonly bool Exists; + private readonly Mod _mod; + public readonly string Name; + public readonly bool Exists; public ModBackup(ModExportManager modExportManager, Mod mod) - { - _mod = mod; - Name = Path.Combine(modExportManager.ExportDirectory.FullName, _mod.ModPath.Name) + ".pmp"; - Exists = File.Exists(Name); + { + _mod = mod; + Name = Path.Combine(modExportManager.ExportDirectory.FullName, _mod.ModPath.Name) + ".pmp"; + Exists = File.Exists(Name); } /// Migrate file extensions. diff --git a/Penumbra/Mods/Editor/ModFileCollection.cs b/Penumbra/Mods/Editor/ModFileCollection.cs index 85a7a544..e3862c90 100644 --- a/Penumbra/Mods/Editor/ModFileCollection.cs +++ b/Penumbra/Mods/Editor/ModFileCollection.cs @@ -1,4 +1,5 @@ using OtterGui; +using Penumbra.Mods.Subclasses; using Penumbra.String.Classes; namespace Penumbra.Mods.Editor; diff --git a/Penumbra/Mods/Editor/ModFileEditor.cs b/Penumbra/Mods/Editor/ModFileEditor.cs index 1ca3edd4..82629971 100644 --- a/Penumbra/Mods/Editor/ModFileEditor.cs +++ b/Penumbra/Mods/Editor/ModFileEditor.cs @@ -1,5 +1,6 @@ using Penumbra.Mods.Editor; using Penumbra.Mods.Manager; +using Penumbra.Mods.Subclasses; using Penumbra.String.Classes; namespace Penumbra.Mods; @@ -7,7 +8,7 @@ namespace Penumbra.Mods; public class ModFileEditor { private readonly ModFileCollection _files; - private readonly ModManager _modManager; + private readonly ModManager _modManager; public bool Changes { get; private set; } diff --git a/Penumbra/Mods/Editor/ModMerger.cs b/Penumbra/Mods/Editor/ModMerger.cs index 5c9be2ac..f90f6c0a 100644 --- a/Penumbra/Mods/Editor/ModMerger.cs +++ b/Penumbra/Mods/Editor/ModMerger.cs @@ -5,6 +5,7 @@ using Penumbra.Api.Enums; using Penumbra.Communication; using Penumbra.Meta.Manipulations; using Penumbra.Mods.Manager; +using Penumbra.Mods.Subclasses; using Penumbra.Services; using Penumbra.String.Classes; using Penumbra.UI.ModsTab; @@ -174,7 +175,7 @@ public class ModMerger : IDisposable ret = new FullPath(MergeToMod!.ModPath, relPath); return true; } - + foreach (var originalOption in mergeOptions) { foreach (var manip in originalOption.Manipulations) diff --git a/Penumbra/Mods/Editor/ModMetaEditor.cs b/Penumbra/Mods/Editor/ModMetaEditor.cs index e389c86a..09c5c77a 100644 --- a/Penumbra/Mods/Editor/ModMetaEditor.cs +++ b/Penumbra/Mods/Editor/ModMetaEditor.cs @@ -1,5 +1,6 @@ using Penumbra.Meta.Manipulations; using Penumbra.Mods.Manager; +using Penumbra.Mods.Subclasses; namespace Penumbra.Mods; @@ -146,6 +147,7 @@ public class ModMetaEditor } } } + Split(currentOption.Manipulations); } diff --git a/Penumbra/Mods/Editor/ModNormalizer.cs b/Penumbra/Mods/Editor/ModNormalizer.cs index 9b17c390..eebc8ab4 100644 --- a/Penumbra/Mods/Editor/ModNormalizer.cs +++ b/Penumbra/Mods/Editor/ModNormalizer.cs @@ -2,6 +2,7 @@ using Dalamud.Interface.Internal.Notifications; using OtterGui; using OtterGui.Tasks; using Penumbra.Mods.Manager; +using Penumbra.Mods.Subclasses; using Penumbra.String.Classes; namespace Penumbra.Mods; diff --git a/Penumbra/Mods/Editor/ModSwapEditor.cs b/Penumbra/Mods/Editor/ModSwapEditor.cs index c00bb821..b9834da8 100644 --- a/Penumbra/Mods/Editor/ModSwapEditor.cs +++ b/Penumbra/Mods/Editor/ModSwapEditor.cs @@ -1,11 +1,12 @@ using Penumbra.Mods; using Penumbra.Mods.Manager; +using Penumbra.Mods.Subclasses; using Penumbra.String.Classes; using Penumbra.Util; public class ModSwapEditor { - private readonly ModManager _modManager; + private readonly ModManager _modManager; private readonly Dictionary _swaps = new(); public IReadOnlyDictionary Swaps diff --git a/Penumbra/Mods/ItemSwap/CustomizationSwap.cs b/Penumbra/Mods/ItemSwap/CustomizationSwap.cs index da56d204..b9200a24 100644 --- a/Penumbra/Mods/ItemSwap/CustomizationSwap.cs +++ b/Penumbra/Mods/ItemSwap/CustomizationSwap.cs @@ -10,27 +10,29 @@ namespace Penumbra.Mods.ItemSwap; public static class CustomizationSwap { /// The .mdl file for customizations is unique per racecode, slot and id, thus the .mdl redirection itself is independent of the mode. - public static FileSwap CreateMdl( MetaFileManager manager, Func< Utf8GamePath, FullPath > redirections, BodySlot slot, GenderRace race, SetId idFrom, SetId idTo ) + public static FileSwap CreateMdl(MetaFileManager manager, Func redirections, BodySlot slot, GenderRace race, + SetId idFrom, SetId idTo) { - if( idFrom.Id > byte.MaxValue ) - { - throw new Exception( $"The Customization ID {idFrom} is too large for {slot}." ); - } + if (idFrom.Id > byte.MaxValue) + throw new Exception($"The Customization ID {idFrom} is too large for {slot}."); - var mdlPathFrom = GamePaths.Character.Mdl.Path( race, slot, idFrom, slot.ToCustomizationType() ); - var mdlPathTo = GamePaths.Character.Mdl.Path( race, slot, idTo, slot.ToCustomizationType() ); + var mdlPathFrom = GamePaths.Character.Mdl.Path(race, slot, idFrom, slot.ToCustomizationType()); + var mdlPathTo = GamePaths.Character.Mdl.Path(race, slot, idTo, slot.ToCustomizationType()); - var mdl = FileSwap.CreateSwap( manager, ResourceType.Mdl, redirections, mdlPathFrom, mdlPathTo ); - var range = slot == BodySlot.Tail && race is GenderRace.HrothgarMale or GenderRace.HrothgarFemale or GenderRace.HrothgarMaleNpc or GenderRace.HrothgarMaleNpc ? 5 : 1; + var mdl = FileSwap.CreateSwap(manager, ResourceType.Mdl, redirections, mdlPathFrom, mdlPathTo); + var range = slot == BodySlot.Tail + && race is GenderRace.HrothgarMale or GenderRace.HrothgarFemale or GenderRace.HrothgarMaleNpc or GenderRace.HrothgarMaleNpc + ? 5 + : 1; - foreach( ref var materialFileName in mdl.AsMdl()!.Materials.AsSpan() ) + foreach (ref var materialFileName in mdl.AsMdl()!.Materials.AsSpan()) { var name = materialFileName; - foreach( var variant in Enumerable.Range( 1, range ) ) + foreach (var variant in Enumerable.Range(1, range)) { name = materialFileName; - var mtrl = CreateMtrl( manager, redirections, slot, race, idFrom, idTo, ( byte )variant, ref name, ref mdl.DataWasChanged ); - mdl.ChildSwaps.Add( mtrl ); + var mtrl = CreateMtrl(manager, redirections, slot, race, idFrom, idTo, (byte)variant, ref name, ref mdl.DataWasChanged); + mdl.ChildSwaps.Add(mtrl); } materialFileName = name; @@ -39,71 +41,75 @@ public static class CustomizationSwap return mdl; } - public static FileSwap CreateMtrl( MetaFileManager manager, Func< Utf8GamePath, FullPath > redirections, BodySlot slot, GenderRace race, SetId idFrom, SetId idTo, byte variant, - ref string fileName, ref bool dataWasChanged ) + public static FileSwap CreateMtrl(MetaFileManager manager, Func redirections, BodySlot slot, GenderRace race, + SetId idFrom, SetId idTo, byte variant, + ref string fileName, ref bool dataWasChanged) { variant = slot is BodySlot.Face or BodySlot.Zear ? byte.MaxValue : variant; - var mtrlFromPath = GamePaths.Character.Mtrl.Path( race, slot, idFrom, fileName, out var gameRaceFrom, out var gameSetIdFrom, variant ); - var mtrlToPath = GamePaths.Character.Mtrl.Path( race, slot, idTo, fileName, out var gameRaceTo, out var gameSetIdTo, variant ); + var mtrlFromPath = GamePaths.Character.Mtrl.Path(race, slot, idFrom, fileName, out var gameRaceFrom, out var gameSetIdFrom, variant); + var mtrlToPath = GamePaths.Character.Mtrl.Path(race, slot, idTo, fileName, out var gameRaceTo, out var gameSetIdTo, variant); var newFileName = fileName; - newFileName = ItemSwap.ReplaceRace( newFileName, gameRaceTo, race, gameRaceTo != race ); - newFileName = ItemSwap.ReplaceBody( newFileName, slot, idTo, idFrom, idFrom != idTo ); - newFileName = ItemSwap.AddSuffix( newFileName, ".mtrl", $"_c{race.ToRaceCode()}", gameRaceFrom != race || MaterialHandling.IsSpecialCase( race, idFrom ) ); - newFileName = ItemSwap.AddSuffix( newFileName, ".mtrl", $"_{slot.ToAbbreviation()}{idFrom.Id:D4}", gameSetIdFrom != idFrom ); + newFileName = ItemSwap.ReplaceRace(newFileName, gameRaceTo, race, gameRaceTo != race); + newFileName = ItemSwap.ReplaceBody(newFileName, slot, idTo, idFrom, idFrom != idTo); + newFileName = ItemSwap.AddSuffix(newFileName, ".mtrl", $"_c{race.ToRaceCode()}", + gameRaceFrom != race || MaterialHandling.IsSpecialCase(race, idFrom)); + newFileName = ItemSwap.AddSuffix(newFileName, ".mtrl", $"_{slot.ToAbbreviation()}{idFrom.Id:D4}", gameSetIdFrom != idFrom); var actualMtrlFromPath = mtrlFromPath; - if( newFileName != fileName ) + if (newFileName != fileName) { - actualMtrlFromPath = GamePaths.Character.Mtrl.Path( race, slot, idFrom, newFileName, out _, out _, variant ); + actualMtrlFromPath = GamePaths.Character.Mtrl.Path(race, slot, idFrom, newFileName, out _, out _, variant); fileName = newFileName; dataWasChanged = true; } - var mtrl = FileSwap.CreateSwap( manager, ResourceType.Mtrl, redirections, actualMtrlFromPath, mtrlToPath, actualMtrlFromPath ); - var shpk = CreateShader( manager, redirections, ref mtrl.AsMtrl()!.ShaderPackage.Name, ref mtrl.DataWasChanged ); - mtrl.ChildSwaps.Add( shpk ); + var mtrl = FileSwap.CreateSwap(manager, ResourceType.Mtrl, redirections, actualMtrlFromPath, mtrlToPath, actualMtrlFromPath); + var shpk = CreateShader(manager, redirections, ref mtrl.AsMtrl()!.ShaderPackage.Name, ref mtrl.DataWasChanged); + mtrl.ChildSwaps.Add(shpk); - foreach( ref var texture in mtrl.AsMtrl()!.Textures.AsSpan() ) + foreach (ref var texture in mtrl.AsMtrl()!.Textures.AsSpan()) { - var tex = CreateTex( manager, redirections, slot, race, idFrom, ref texture, ref mtrl.DataWasChanged ); - mtrl.ChildSwaps.Add( tex ); + var tex = CreateTex(manager, redirections, slot, race, idFrom, ref texture, ref mtrl.DataWasChanged); + mtrl.ChildSwaps.Add(tex); } return mtrl; } - public static FileSwap CreateTex( MetaFileManager manager, Func< Utf8GamePath, FullPath > redirections, BodySlot slot, GenderRace race, SetId idFrom, ref MtrlFile.Texture texture, - ref bool dataWasChanged ) + public static FileSwap CreateTex(MetaFileManager manager, Func redirections, BodySlot slot, GenderRace race, + SetId idFrom, ref MtrlFile.Texture texture, + ref bool dataWasChanged) { var path = texture.Path; var addedDashes = false; - if( texture.DX11 ) + if (texture.DX11) { - var fileName = Path.GetFileName( path ); - if( !fileName.StartsWith( "--" ) ) + var fileName = Path.GetFileName(path); + if (!fileName.StartsWith("--")) { - path = path.Replace( fileName, $"--{fileName}" ); + path = path.Replace(fileName, $"--{fileName}"); addedDashes = true; } } - var newPath = ItemSwap.ReplaceAnyRace( path, race ); - newPath = ItemSwap.ReplaceAnyBody( newPath, slot, idFrom ); - newPath = ItemSwap.AddSuffix( newPath, ".tex", $"_{Path.GetFileName( texture.Path ).GetStableHashCode():x8}", true ); - if( newPath != path ) + var newPath = ItemSwap.ReplaceAnyRace(path, race); + newPath = ItemSwap.ReplaceAnyBody(newPath, slot, idFrom); + newPath = ItemSwap.AddSuffix(newPath, ".tex", $"_{Path.GetFileName(texture.Path).GetStableHashCode():x8}", true); + if (newPath != path) { - texture.Path = addedDashes ? newPath.Replace( "--", string.Empty ) : newPath; + texture.Path = addedDashes ? newPath.Replace("--", string.Empty) : newPath; dataWasChanged = true; } - return FileSwap.CreateSwap( manager, ResourceType.Tex, redirections, newPath, path, path ); + return FileSwap.CreateSwap(manager, ResourceType.Tex, redirections, newPath, path, path); } - public static FileSwap CreateShader( MetaFileManager manager, Func< Utf8GamePath, FullPath > redirections, ref string shaderName, ref bool dataWasChanged ) + public static FileSwap CreateShader(MetaFileManager manager, Func redirections, ref string shaderName, + ref bool dataWasChanged) { var path = $"shader/sm5/shpk/{shaderName}"; - return FileSwap.CreateSwap( manager, ResourceType.Shpk, redirections, path, path ); + return FileSwap.CreateSwap(manager, ResourceType.Shpk, redirections, path, path); } -} \ No newline at end of file +} diff --git a/Penumbra/Mods/ItemSwap/EquipmentSwap.cs b/Penumbra/Mods/ItemSwap/EquipmentSwap.cs index 188fc317..d95c8796 100644 --- a/Penumbra/Mods/ItemSwap/EquipmentSwap.cs +++ b/Penumbra/Mods/ItemSwap/EquipmentSwap.cs @@ -249,10 +249,10 @@ public static class EquipmentSwap private static (ImcFile, Variant[], EquipItem[]) GetVariants(MetaFileManager manager, IObjectIdentifier identifier, EquipSlot slotFrom, SetId idFrom, SetId idTo, Variant variantFrom) { - var entry = new ImcManipulation(slotFrom, variantFrom.Id, idFrom, default); - var imc = new ImcFile(manager, entry); + var entry = new ImcManipulation(slotFrom, variantFrom.Id, idFrom, default); + var imc = new ImcFile(manager, entry); EquipItem[] items; - Variant[] variants; + Variant[] variants; if (idFrom == idTo) { items = identifier.Identify(idFrom, variantFrom, slotFrom).ToArray(); @@ -264,8 +264,9 @@ public static class EquipmentSwap else { items = identifier.Identify(slotFrom.IsEquipment() - ? GamePaths.Equipment.Mdl.Path(idFrom, GenderRace.MidlanderMale, slotFrom) - : GamePaths.Accessory.Mdl.Path(idFrom, GenderRace.MidlanderMale, slotFrom)).Select(kvp => kvp.Value).OfType().ToArray(); + ? GamePaths.Equipment.Mdl.Path(idFrom, GenderRace.MidlanderMale, slotFrom) + : GamePaths.Accessory.Mdl.Path(idFrom, GenderRace.MidlanderMale, slotFrom)).Select(kvp => kvp.Value).OfType() + .ToArray(); variants = Enumerable.Range(0, imc.Count + 1).Select(i => (Variant)i).ToArray(); } @@ -283,11 +284,13 @@ public static class EquipmentSwap return new MetaSwap(manips, manipFrom, manipTo); } - public static MetaSwap CreateImc(MetaFileManager manager, Func redirections, Func manips, EquipSlot slot, + public static MetaSwap CreateImc(MetaFileManager manager, Func redirections, + Func manips, EquipSlot slot, SetId idFrom, SetId idTo, Variant variantFrom, Variant variantTo, ImcFile imcFileFrom, ImcFile imcFileTo) => CreateImc(manager, redirections, manips, slot, slot, idFrom, idTo, variantFrom, variantTo, imcFileFrom, imcFileTo); - public static MetaSwap CreateImc(MetaFileManager manager, Func redirections, Func manips, + public static MetaSwap CreateImc(MetaFileManager manager, Func redirections, + Func manips, EquipSlot slotFrom, EquipSlot slotTo, SetId idFrom, SetId idTo, Variant variantFrom, Variant variantTo, ImcFile imcFileFrom, ImcFile imcFileTo) { @@ -401,7 +404,8 @@ public static class EquipmentSwap ref MtrlFile.Texture texture, ref bool dataWasChanged) => CreateTex(manager, redirections, prefix, EquipSlot.Unknown, EquipSlot.Unknown, idFrom, idTo, ref texture, ref dataWasChanged); - public static FileSwap CreateTex(MetaFileManager manager, Func redirections, char prefix, EquipSlot slotFrom, EquipSlot slotTo, SetId idFrom, + public static FileSwap CreateTex(MetaFileManager manager, Func redirections, char prefix, EquipSlot slotFrom, + EquipSlot slotTo, SetId idFrom, SetId idTo, ref MtrlFile.Texture texture, ref bool dataWasChanged) { var path = texture.Path; @@ -428,13 +432,15 @@ public static class EquipmentSwap return FileSwap.CreateSwap(manager, ResourceType.Tex, redirections, newPath, path, path); } - public static FileSwap CreateShader(MetaFileManager manager, Func redirections, ref string shaderName, ref bool dataWasChanged) + public static FileSwap CreateShader(MetaFileManager manager, Func redirections, ref string shaderName, + ref bool dataWasChanged) { var path = $"shader/sm5/shpk/{shaderName}"; return FileSwap.CreateSwap(manager, ResourceType.Shpk, redirections, path, path); } - public static FileSwap CreateAtex(MetaFileManager manager, Func redirections, ref string filePath, ref bool dataWasChanged) + public static FileSwap CreateAtex(MetaFileManager manager, Func redirections, ref string filePath, + ref bool dataWasChanged) { var oldPath = filePath; filePath = ItemSwap.AddSuffix(filePath, ".atex", $"_{Path.GetFileName(filePath).GetStableHashCode():x8}"); diff --git a/Penumbra/Mods/ItemSwap/ItemSwap.cs b/Penumbra/Mods/ItemSwap/ItemSwap.cs index 02e02ccb..0140d189 100644 --- a/Penumbra/Mods/ItemSwap/ItemSwap.cs +++ b/Penumbra/Mods/ItemSwap/ItemSwap.cs @@ -20,47 +20,45 @@ public static class ItemSwap { public readonly ResourceType Type; - public MissingFileException( ResourceType type, object path ) + public MissingFileException(ResourceType type, object path) : base($"Could not load {type} File Data for \"{path}\".") => Type = type; } - private static bool LoadFile( MetaFileManager manager, FullPath path, out byte[] data ) + private static bool LoadFile(MetaFileManager manager, FullPath path, out byte[] data) { - if( path.FullName.Length > 0 ) - { + if (path.FullName.Length > 0) try { - if( path.IsRooted ) + if (path.IsRooted) { - data = File.ReadAllBytes( path.FullName ); + data = File.ReadAllBytes(path.FullName); return true; } - var file = manager.GameData.GetFile( path.InternalName.ToString() ); - if( file != null ) + var file = manager.GameData.GetFile(path.InternalName.ToString()); + if (file != null) { data = file.Data; return true; } } - catch( Exception e ) + catch (Exception e) { - Penumbra.Log.Debug( $"Could not load file {path}:\n{e}" ); + Penumbra.Log.Debug($"Could not load file {path}:\n{e}"); } - } - data = Array.Empty< byte >(); + data = Array.Empty(); return false; } public class GenericFile : IWritable { public readonly byte[] Data; - public bool Valid { get; } + public bool Valid { get; } - public GenericFile( MetaFileManager manager, FullPath path ) - => Valid = LoadFile( manager, path, out Data ); + public GenericFile(MetaFileManager manager, FullPath path) + => Valid = LoadFile(manager, path, out Data); public byte[] Write() => Data; @@ -68,69 +66,67 @@ public static class ItemSwap public static readonly GenericFile Invalid = new(null!, FullPath.Empty); } - public static bool LoadFile( MetaFileManager manager, FullPath path, [NotNullWhen( true )] out GenericFile? file ) + public static bool LoadFile(MetaFileManager manager, FullPath path, [NotNullWhen(true)] out GenericFile? file) { - file = new GenericFile( manager, path ); - if( file.Valid ) - { + file = new GenericFile(manager, path); + if (file.Valid) return true; - } file = null; return false; } - public static bool LoadMdl( MetaFileManager manager, FullPath path, [NotNullWhen( true )] out MdlFile? file ) + public static bool LoadMdl(MetaFileManager manager, FullPath path, [NotNullWhen(true)] out MdlFile? file) { try { - if( LoadFile( manager, path, out byte[] data ) ) + if (LoadFile(manager, path, out byte[] data)) { - file = new MdlFile( data ); + file = new MdlFile(data); return true; } } - catch( Exception e ) + catch (Exception e) { - Penumbra.Log.Debug( $"Could not parse file {path} to Mdl:\n{e}" ); + Penumbra.Log.Debug($"Could not parse file {path} to Mdl:\n{e}"); } file = null; return false; } - public static bool LoadMtrl(MetaFileManager manager, FullPath path, [NotNullWhen( true )] out MtrlFile? file ) + public static bool LoadMtrl(MetaFileManager manager, FullPath path, [NotNullWhen(true)] out MtrlFile? file) { try { - if( LoadFile( manager, path, out byte[] data ) ) + if (LoadFile(manager, path, out byte[] data)) { - file = new MtrlFile( data ); + file = new MtrlFile(data); return true; } } - catch( Exception e ) + catch (Exception e) { - Penumbra.Log.Debug( $"Could not parse file {path} to Mtrl:\n{e}" ); + Penumbra.Log.Debug($"Could not parse file {path} to Mtrl:\n{e}"); } file = null; return false; } - public static bool LoadAvfx( MetaFileManager manager, FullPath path, [NotNullWhen( true )] out AvfxFile? file ) + public static bool LoadAvfx(MetaFileManager manager, FullPath path, [NotNullWhen(true)] out AvfxFile? file) { try { - if( LoadFile( manager, path, out byte[] data ) ) + if (LoadFile(manager, path, out byte[] data)) { - file = new AvfxFile( data ); + file = new AvfxFile(data); return true; } } - catch( Exception e ) + catch (Exception e) { - Penumbra.Log.Debug( $"Could not parse file {path} to Avfx:\n{e}" ); + Penumbra.Log.Debug($"Could not parse file {path} to Avfx:\n{e}"); } file = null; @@ -138,40 +134,41 @@ public static class ItemSwap } - public static FileSwap CreatePhyb(MetaFileManager manager, Func< Utf8GamePath, FullPath > redirections, EstManipulation.EstType type, GenderRace race, ushort estEntry ) + public static FileSwap CreatePhyb(MetaFileManager manager, Func redirections, EstManipulation.EstType type, + GenderRace race, ushort estEntry) { - var phybPath = GamePaths.Skeleton.Phyb.Path( race, EstManipulation.ToName( type ), estEntry ); - return FileSwap.CreateSwap( manager, ResourceType.Phyb, redirections, phybPath, phybPath ); + var phybPath = GamePaths.Skeleton.Phyb.Path(race, EstManipulation.ToName(type), estEntry); + return FileSwap.CreateSwap(manager, ResourceType.Phyb, redirections, phybPath, phybPath); } - public static FileSwap CreateSklb(MetaFileManager manager, Func< Utf8GamePath, FullPath > redirections, EstManipulation.EstType type, GenderRace race, ushort estEntry ) + public static FileSwap CreateSklb(MetaFileManager manager, Func redirections, EstManipulation.EstType type, + GenderRace race, ushort estEntry) { - var sklbPath = GamePaths.Skeleton.Sklb.Path( race, EstManipulation.ToName( type ), estEntry ); - return FileSwap.CreateSwap(manager, ResourceType.Sklb, redirections, sklbPath, sklbPath ); + var sklbPath = GamePaths.Skeleton.Sklb.Path(race, EstManipulation.ToName(type), estEntry); + return FileSwap.CreateSwap(manager, ResourceType.Sklb, redirections, sklbPath, sklbPath); } /// metaChanges is not manipulated, but IReadOnlySet does not support TryGetValue. - public static MetaSwap? CreateEst( MetaFileManager manager, Func< Utf8GamePath, FullPath > redirections, Func< MetaManipulation, MetaManipulation > manips, EstManipulation.EstType type, - GenderRace genderRace, SetId idFrom, SetId idTo, bool ownMdl ) + public static MetaSwap? CreateEst(MetaFileManager manager, Func redirections, + Func manips, EstManipulation.EstType type, + GenderRace genderRace, SetId idFrom, SetId idTo, bool ownMdl) { - if( type == 0 ) - { + if (type == 0) return null; - } var (gender, race) = genderRace.Split(); - var fromDefault = new EstManipulation( gender, race, type, idFrom, EstFile.GetDefault( manager, type, genderRace, idFrom ) ); - var toDefault = new EstManipulation( gender, race, type, idTo, EstFile.GetDefault( manager, type, genderRace, idTo ) ); - var est = new MetaSwap( manips, fromDefault, toDefault ); + var fromDefault = new EstManipulation(gender, race, type, idFrom, EstFile.GetDefault(manager, type, genderRace, idFrom)); + var toDefault = new EstManipulation(gender, race, type, idTo, EstFile.GetDefault(manager, type, genderRace, idTo)); + var est = new MetaSwap(manips, fromDefault, toDefault); - if( ownMdl && est.SwapApplied.Est.Entry >= 2 ) + if (ownMdl && est.SwapApplied.Est.Entry >= 2) { - var phyb = CreatePhyb( manager, redirections, type, genderRace, est.SwapApplied.Est.Entry ); - est.ChildSwaps.Add( phyb ); - var sklb = CreateSklb( manager, redirections, type, genderRace, est.SwapApplied.Est.Entry ); - est.ChildSwaps.Add( sklb ); + var phyb = CreatePhyb(manager, redirections, type, genderRace, est.SwapApplied.Est.Entry); + est.ChildSwaps.Add(phyb); + var sklb = CreateSklb(manager, redirections, type, genderRace, est.SwapApplied.Est.Entry); + est.ChildSwaps.Add(sklb); } - else if( est.SwapAppliedIsDefault ) + else if (est.SwapAppliedIsDefault) { return null; } @@ -179,57 +176,55 @@ public static class ItemSwap return est; } - public static int GetStableHashCode( this string str ) + public static int GetStableHashCode(this string str) { unchecked { var hash1 = 5381; var hash2 = hash1; - for( var i = 0; i < str.Length && str[ i ] != '\0'; i += 2 ) + for (var i = 0; i < str.Length && str[i] != '\0'; i += 2) { - hash1 = ( ( hash1 << 5 ) + hash1 ) ^ str[ i ]; - if( i == str.Length - 1 || str[ i + 1 ] == '\0' ) - { + hash1 = ((hash1 << 5) + hash1) ^ str[i]; + if (i == str.Length - 1 || str[i + 1] == '\0') break; - } - hash2 = ( ( hash2 << 5 ) + hash2 ) ^ str[ i + 1 ]; + hash2 = ((hash2 << 5) + hash2) ^ str[i + 1]; } return hash1 + hash2 * 1566083941; } } - public static string ReplaceAnyId( string path, char idType, SetId id, bool condition = true ) + public static string ReplaceAnyId(string path, char idType, SetId id, bool condition = true) => condition - ? Regex.Replace( path, $"{idType}\\d{{4}}", $"{idType}{id.Id:D4}" ) + ? Regex.Replace(path, $"{idType}\\d{{4}}", $"{idType}{id.Id:D4}") : path; - public static string ReplaceAnyRace( string path, GenderRace to, bool condition = true ) - => ReplaceAnyId( path, 'c', ( ushort )to, condition ); + public static string ReplaceAnyRace(string path, GenderRace to, bool condition = true) + => ReplaceAnyId(path, 'c', (ushort)to, condition); - public static string ReplaceAnyBody( string path, BodySlot slot, SetId to, bool condition = true ) - => ReplaceAnyId( path, slot.ToAbbreviation(), to, condition ); + public static string ReplaceAnyBody(string path, BodySlot slot, SetId to, bool condition = true) + => ReplaceAnyId(path, slot.ToAbbreviation(), to, condition); - public static string ReplaceId( string path, char type, SetId idFrom, SetId idTo, bool condition = true ) + public static string ReplaceId(string path, char type, SetId idFrom, SetId idTo, bool condition = true) => condition - ? path.Replace( $"{type}{idFrom.Id:D4}", $"{type}{idTo.Id:D4}" ) + ? path.Replace($"{type}{idFrom.Id:D4}", $"{type}{idTo.Id:D4}") : path; - public static string ReplaceSlot( string path, EquipSlot from, EquipSlot to, bool condition = true ) + public static string ReplaceSlot(string path, EquipSlot from, EquipSlot to, bool condition = true) => condition - ? path.Replace( $"_{from.ToSuffix()}_", $"_{to.ToSuffix()}_" ) + ? path.Replace($"_{from.ToSuffix()}_", $"_{to.ToSuffix()}_") : path; - public static string ReplaceRace( string path, GenderRace from, GenderRace to, bool condition = true ) - => ReplaceId( path, 'c', ( ushort )from, ( ushort )to, condition ); + public static string ReplaceRace(string path, GenderRace from, GenderRace to, bool condition = true) + => ReplaceId(path, 'c', (ushort)from, (ushort)to, condition); - public static string ReplaceBody( string path, BodySlot slot, SetId idFrom, SetId idTo, bool condition = true ) - => ReplaceId( path, slot.ToAbbreviation(), idFrom, idTo, condition ); + public static string ReplaceBody(string path, BodySlot slot, SetId idFrom, SetId idTo, bool condition = true) + => ReplaceId(path, slot.ToAbbreviation(), idFrom, idTo, condition); - public static string AddSuffix( string path, string ext, string suffix, bool condition = true ) + public static string AddSuffix(string path, string ext, string suffix, bool condition = true) => condition - ? path.Replace( ext, suffix + ext ) + ? path.Replace(ext, suffix + ext) : path; -} \ No newline at end of file +} diff --git a/Penumbra/Mods/ItemSwap/ItemSwapContainer.cs b/Penumbra/Mods/ItemSwap/ItemSwapContainer.cs index 8e6473cc..1db890ed 100644 --- a/Penumbra/Mods/ItemSwap/ItemSwapContainer.cs +++ b/Penumbra/Mods/ItemSwap/ItemSwapContainer.cs @@ -6,6 +6,7 @@ using Penumbra.Meta.Manipulations; using Penumbra.String.Classes; using Penumbra.Meta; using Penumbra.Mods.Manager; +using Penumbra.Mods.Subclasses; using Penumbra.Services; namespace Penumbra.Mods.ItemSwap; @@ -13,18 +14,18 @@ namespace Penumbra.Mods.ItemSwap; public class ItemSwapContainer { private readonly MetaFileManager _manager; - private readonly IdentifierService _identifier; + private readonly IdentifierService _identifier; - private Dictionary< Utf8GamePath, FullPath > _modRedirections = new(); - private HashSet< MetaManipulation > _modManipulations = new(); + private Dictionary _modRedirections = new(); + private HashSet _modManipulations = new(); - public IReadOnlyDictionary< Utf8GamePath, FullPath > ModRedirections + public IReadOnlyDictionary ModRedirections => _modRedirections; - public IReadOnlySet< MetaManipulation > ModManipulations + public IReadOnlySet ModManipulations => _modManipulations; - public readonly List< Swap > Swaps = new(); + public readonly List Swaps = new(); public bool Loaded { get; private set; } @@ -40,72 +41,69 @@ public class ItemSwapContainer NoSwaps, } - public bool WriteMod( ModManager manager, Mod mod, WriteType writeType = WriteType.NoSwaps, DirectoryInfo? directory = null, int groupIndex = -1, int optionIndex = 0 ) + public bool WriteMod(ModManager manager, Mod mod, WriteType writeType = WriteType.NoSwaps, DirectoryInfo? directory = null, + int groupIndex = -1, int optionIndex = 0) { - var convertedManips = new HashSet< MetaManipulation >( Swaps.Count ); - var convertedFiles = new Dictionary< Utf8GamePath, FullPath >( Swaps.Count ); - var convertedSwaps = new Dictionary< Utf8GamePath, FullPath >( Swaps.Count ); + var convertedManips = new HashSet(Swaps.Count); + var convertedFiles = new Dictionary(Swaps.Count); + var convertedSwaps = new Dictionary(Swaps.Count); directory ??= mod.ModPath; try { - foreach( var swap in Swaps.SelectMany( s => s.WithChildren() ) ) + foreach (var swap in Swaps.SelectMany(s => s.WithChildren())) { - switch( swap ) + switch (swap) { case FileSwap file: // Skip, nothing to do - if( file.SwapToModdedEqualsOriginal ) - { + if (file.SwapToModdedEqualsOriginal) continue; - } - if( writeType == WriteType.UseSwaps && file.SwapToModdedExistsInGame && !file.DataWasChanged ) + if (writeType == WriteType.UseSwaps && file.SwapToModdedExistsInGame && !file.DataWasChanged) { - convertedSwaps.TryAdd( file.SwapFromRequestPath, file.SwapToModded ); + convertedSwaps.TryAdd(file.SwapFromRequestPath, file.SwapToModded); } else { - var path = file.GetNewPath( directory.FullName ); + var path = file.GetNewPath(directory.FullName); var bytes = file.FileData.Write(); - Directory.CreateDirectory( Path.GetDirectoryName( path )! ); - _manager.Compactor.WriteAllBytes( path, bytes ); - convertedFiles.TryAdd( file.SwapFromRequestPath, new FullPath( path ) ); + Directory.CreateDirectory(Path.GetDirectoryName(path)!); + _manager.Compactor.WriteAllBytes(path, bytes); + convertedFiles.TryAdd(file.SwapFromRequestPath, new FullPath(path)); } break; case MetaSwap meta: - if( !meta.SwapAppliedIsDefault ) - { - convertedManips.Add( meta.SwapApplied ); - } + if (!meta.SwapAppliedIsDefault) + convertedManips.Add(meta.SwapApplied); break; } } - manager.OptionEditor.OptionSetFiles( mod, groupIndex, optionIndex, convertedFiles ); - manager.OptionEditor.OptionSetFileSwaps( mod, groupIndex, optionIndex, convertedSwaps ); - manager.OptionEditor.OptionSetManipulations( mod, groupIndex, optionIndex, convertedManips ); + manager.OptionEditor.OptionSetFiles(mod, groupIndex, optionIndex, convertedFiles); + manager.OptionEditor.OptionSetFileSwaps(mod, groupIndex, optionIndex, convertedSwaps); + manager.OptionEditor.OptionSetManipulations(mod, groupIndex, optionIndex, convertedManips); return true; } - catch( Exception e ) + catch (Exception e) { - Penumbra.Log.Error( $"Could not write FileSwapContainer to {mod.ModPath}:\n{e}" ); + Penumbra.Log.Error($"Could not write FileSwapContainer to {mod.ModPath}:\n{e}"); return false; } } - public void LoadMod( Mod? mod, ModSettings? settings ) + public void LoadMod(Mod? mod, ModSettings? settings) { Clear(); - if( mod == null ) + if (mod == null) { - _modRedirections = new Dictionary< Utf8GamePath, FullPath >(); - _modManipulations = new HashSet< MetaManipulation >(); + _modRedirections = new Dictionary(); + _modManipulations = new HashSet(); } else { - ( _modRedirections, _modManipulations ) = ModSettings.GetResolveData( mod, settings ); + (_modRedirections, _modManipulations) = ModSettings.GetResolveData(mod, settings); } } @@ -113,59 +111,61 @@ public class ItemSwapContainer { _manager = manager; _identifier = identifier; - LoadMod( null, null ); + LoadMod(null, null); } - private Func< Utf8GamePath, FullPath > PathResolver( ModCollection? collection ) + private Func PathResolver(ModCollection? collection) => collection != null - ? p => collection.ResolvePath( p ) ?? new FullPath( p ) - : p => ModRedirections.TryGetValue( p, out var path ) ? path : new FullPath( p ); + ? p => collection.ResolvePath(p) ?? new FullPath(p) + : p => ModRedirections.TryGetValue(p, out var path) ? path : new FullPath(p); - private Func< MetaManipulation, MetaManipulation > MetaResolver( ModCollection? collection ) + private Func MetaResolver(ModCollection? collection) { var set = collection?.MetaCache?.Manipulations.ToHashSet() ?? _modManipulations; - return m => set.TryGetValue( m, out var a ) ? a : m; + return m => set.TryGetValue(m, out var a) ? a : m; } - public EquipItem[] LoadEquipment( EquipItem from, EquipItem to, ModCollection? collection = null, bool useRightRing = true, bool useLeftRing = true ) + public EquipItem[] LoadEquipment(EquipItem from, EquipItem to, ModCollection? collection = null, bool useRightRing = true, + bool useLeftRing = true) { Swaps.Clear(); Loaded = false; - var ret = EquipmentSwap.CreateItemSwap( _manager, _identifier.AwaitedService, Swaps, PathResolver( collection ), MetaResolver( collection ), from, to, useRightRing, useLeftRing ); + var ret = EquipmentSwap.CreateItemSwap(_manager, _identifier.AwaitedService, Swaps, PathResolver(collection), MetaResolver(collection), + from, to, useRightRing, useLeftRing); Loaded = true; return ret; } - public EquipItem[] LoadTypeSwap( EquipSlot slotFrom, EquipItem from, EquipSlot slotTo, EquipItem to, ModCollection? collection = null ) + public EquipItem[] LoadTypeSwap(EquipSlot slotFrom, EquipItem from, EquipSlot slotTo, EquipItem to, ModCollection? collection = null) { Swaps.Clear(); Loaded = false; - var ret = EquipmentSwap.CreateTypeSwap( _manager, _identifier.AwaitedService, Swaps, PathResolver( collection ), MetaResolver( collection ), slotFrom, from, slotTo, to ); + var ret = EquipmentSwap.CreateTypeSwap(_manager, _identifier.AwaitedService, Swaps, PathResolver(collection), MetaResolver(collection), + slotFrom, from, slotTo, to); Loaded = true; return ret; } - public bool LoadCustomization( MetaFileManager manager, BodySlot slot, GenderRace race, SetId from, SetId to, ModCollection? collection = null ) + public bool LoadCustomization(MetaFileManager manager, BodySlot slot, GenderRace race, SetId from, SetId to, + ModCollection? collection = null) { - var pathResolver = PathResolver( collection ); - var mdl = CustomizationSwap.CreateMdl( manager, pathResolver, slot, race, from, to ); + var pathResolver = PathResolver(collection); + var mdl = CustomizationSwap.CreateMdl(manager, pathResolver, slot, race, from, to); var type = slot switch { BodySlot.Hair => EstManipulation.EstType.Hair, BodySlot.Face => EstManipulation.EstType.Face, - _ => ( EstManipulation.EstType )0, + _ => (EstManipulation.EstType)0, }; - var metaResolver = MetaResolver( collection ); - var est = ItemSwap.CreateEst( manager, pathResolver, metaResolver, type, race, from, to, true ); + var metaResolver = MetaResolver(collection); + var est = ItemSwap.CreateEst(manager, pathResolver, metaResolver, type, race, from, to, true); - Swaps.Add( mdl ); - if( est != null ) - { - Swaps.Add( est ); - } + Swaps.Add(mdl); + if (est != null) + Swaps.Add(est); Loaded = true; return true; } -} \ No newline at end of file +} diff --git a/Penumbra/Mods/Manager/ModExportManager.cs b/Penumbra/Mods/Manager/ModExportManager.cs index 7d79d3d4..676018be 100644 --- a/Penumbra/Mods/Manager/ModExportManager.cs +++ b/Penumbra/Mods/Manager/ModExportManager.cs @@ -89,4 +89,4 @@ public class ModExportManager : IDisposable new ModBackup(this, mod).Move(null, newDirectory.Name); mod.ModPath = newDirectory; } -} \ No newline at end of file +} diff --git a/Penumbra/Mods/Manager/ModFileSystem.cs b/Penumbra/Mods/Manager/ModFileSystem.cs index f7006c4c..013d0e40 100644 --- a/Penumbra/Mods/Manager/ModFileSystem.cs +++ b/Penumbra/Mods/Manager/ModFileSystem.cs @@ -2,11 +2,9 @@ using System.Diagnostics.CodeAnalysis; using System.Text.RegularExpressions; using OtterGui.Filesystem; using Penumbra.Communication; -using Penumbra.Mods.Manager; using Penumbra.Services; -using Penumbra.Util; -namespace Penumbra.Mods; +namespace Penumbra.Mods.Manager; public sealed class ModFileSystem : FileSystem, IDisposable, ISavable { diff --git a/Penumbra/Mods/Manager/ModImportManager.cs b/Penumbra/Mods/Manager/ModImportManager.cs index 6c49ccf8..cc91dfa6 100644 --- a/Penumbra/Mods/Manager/ModImportManager.cs +++ b/Penumbra/Mods/Manager/ModImportManager.cs @@ -1,4 +1,3 @@ -using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using Dalamud.Interface.Internal.Notifications; using Penumbra.Import; diff --git a/Penumbra/Mods/Manager/ModManager.cs b/Penumbra/Mods/Manager/ModManager.cs index f8d293a2..e258f996 100644 --- a/Penumbra/Mods/Manager/ModManager.cs +++ b/Penumbra/Mods/Manager/ModManager.cs @@ -1,4 +1,3 @@ -using System.Collections.Concurrent; using Penumbra.Communication; using Penumbra.Mods.Editor; using Penumbra.Services; @@ -16,7 +15,7 @@ public enum NewDirectoryState Identical, Empty, } - + /// Describes the state of a changed mod event. public enum ModPathChangeType { @@ -25,7 +24,7 @@ public enum ModPathChangeType Moved, Reloaded, StartingReload, -} +} public sealed class ModManager : ModStorage, IDisposable { @@ -46,8 +45,8 @@ public sealed class ModManager : ModStorage, IDisposable _communicator = communicator; DataEditor = dataEditor; OptionEditor = optionEditor; - Creator = creator; - SetBaseDirectory(config.ModDirectory, true); + Creator = creator; + SetBaseDirectory(config.ModDirectory, true); _communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.ModManager); DiscoverMods(); } @@ -242,7 +241,7 @@ public sealed class ModManager : ModStorage, IDisposable { switch (type) { - case ModPathChangeType.Added: + case ModPathChangeType.Added: SetNew(mod); break; case ModPathChangeType.Deleted: diff --git a/Penumbra/Mods/Manager/ModMigration.cs b/Penumbra/Mods/Manager/ModMigration.cs index 3cfab943..ddd88a72 100644 --- a/Penumbra/Mods/Manager/ModMigration.cs +++ b/Penumbra/Mods/Manager/ModMigration.cs @@ -6,7 +6,6 @@ using Penumbra.Api.Enums; using Penumbra.Mods.Subclasses; using Penumbra.Services; using Penumbra.String.Classes; -using Penumbra.Util; namespace Penumbra.Mods.Manager; @@ -19,7 +18,9 @@ public static partial class ModMigration private static partial Regex GroupStartRegex(); public static bool Migrate(ModCreator creator, SaveService saveService, Mod mod, JObject json, ref uint fileVersion) - => MigrateV0ToV1(creator, saveService, mod, json, ref fileVersion) || MigrateV1ToV2(saveService, mod, ref fileVersion) || MigrateV2ToV3(mod, ref fileVersion); + => MigrateV0ToV1(creator, saveService, mod, json, ref fileVersion) + || MigrateV1ToV2(saveService, mod, ref fileVersion) + || MigrateV2ToV3(mod, ref fileVersion); private static bool MigrateV2ToV3(Mod _, ref uint fileVersion) { @@ -63,8 +64,8 @@ public static partial class ModMigration var swaps = json["FileSwaps"]?.ToObject>() ?? new Dictionary(); - var groups = json["Groups"]?.ToObject>() ?? new Dictionary(); - var priority = 1; + var groups = json["Groups"]?.ToObject>() ?? new Dictionary(); + var priority = 1; var seenMetaFiles = new HashSet(); foreach (var group in groups.Values) ConvertGroup(creator, mod, group, ref priority, seenMetaFiles); @@ -128,8 +129,8 @@ public static partial class ModMigration var optionPriority = 0; var newMultiGroup = new MultiModGroup() { - Name = group.GroupName, - Priority = priority++, + Name = group.GroupName, + Priority = priority++, Description = string.Empty, }; mod.Groups.Add(newMultiGroup); @@ -146,8 +147,8 @@ public static partial class ModMigration var newSingleGroup = new SingleModGroup() { - Name = group.GroupName, - Priority = priority++, + Name = group.GroupName, + Priority = priority++, Description = string.Empty, }; mod.Groups.Add(newSingleGroup); diff --git a/Penumbra/Mods/Mod.cs b/Penumbra/Mods/Mod.cs index 4ce6da9a..41cc023e 100644 --- a/Penumbra/Mods/Mod.cs +++ b/Penumbra/Mods/Mod.cs @@ -5,7 +5,7 @@ using Penumbra.String.Classes; namespace Penumbra.Mods; -public sealed partial class Mod : IMod +public sealed class Mod : IMod { public static readonly TemporaryMod ForcedFiles = new() { diff --git a/Penumbra/Mods/ModCreator.cs b/Penumbra/Mods/ModCreator.cs index b5462eee..89d35cd2 100644 --- a/Penumbra/Mods/ModCreator.cs +++ b/Penumbra/Mods/ModCreator.cs @@ -113,9 +113,7 @@ public partial class ModCreator } if (changes) - { _saveService.SaveAllOptionGroups(mod, true); - } } /// Load the default option for a given mod. diff --git a/Penumbra/Mods/ModLocalData.cs b/Penumbra/Mods/ModLocalData.cs index 56ee827b..51fe8d58 100644 --- a/Penumbra/Mods/ModLocalData.cs +++ b/Penumbra/Mods/ModLocalData.cs @@ -2,7 +2,6 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Penumbra.Mods.Manager; using Penumbra.Services; -using Penumbra.Util; namespace Penumbra.Mods; diff --git a/Penumbra/Mods/ModMeta.cs b/Penumbra/Mods/ModMeta.cs index 49094aa0..d29cdb9c 100644 --- a/Penumbra/Mods/ModMeta.cs +++ b/Penumbra/Mods/ModMeta.cs @@ -1,7 +1,6 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Penumbra.Services; -using Penumbra.Util; namespace Penumbra.Mods; diff --git a/Penumbra/Mods/Subclasses/ISubMod.cs b/Penumbra/Mods/Subclasses/ISubMod.cs index ac92cd13..8c296f20 100644 --- a/Penumbra/Mods/Subclasses/ISubMod.cs +++ b/Penumbra/Mods/Subclasses/ISubMod.cs @@ -1,58 +1,57 @@ using Newtonsoft.Json; using Penumbra.Meta.Manipulations; -using Penumbra.Mods.Subclasses; using Penumbra.String.Classes; -namespace Penumbra.Mods; +namespace Penumbra.Mods.Subclasses; public interface ISubMod { - public string Name { get; } - public string FullName { get; } + public string Name { get; } + public string FullName { get; } public string Description { get; } - public IReadOnlyDictionary< Utf8GamePath, FullPath > Files { get; } - public IReadOnlyDictionary< Utf8GamePath, FullPath > FileSwaps { get; } - public IReadOnlySet< MetaManipulation > Manipulations { get; } + public IReadOnlyDictionary Files { get; } + public IReadOnlyDictionary FileSwaps { get; } + public IReadOnlySet Manipulations { get; } public bool IsDefault { get; } - public static void WriteSubMod( JsonWriter j, JsonSerializer serializer, ISubMod mod, DirectoryInfo basePath, int? priority ) + public static void WriteSubMod(JsonWriter j, JsonSerializer serializer, ISubMod mod, DirectoryInfo basePath, int? priority) { j.WriteStartObject(); - j.WritePropertyName( nameof( Name ) ); - j.WriteValue( mod.Name ); - j.WritePropertyName( nameof(Description) ); - j.WriteValue( mod.Description ); - if( priority != null ) + j.WritePropertyName(nameof(Name)); + j.WriteValue(mod.Name); + j.WritePropertyName(nameof(Description)); + j.WriteValue(mod.Description); + if (priority != null) { - j.WritePropertyName( nameof( IModGroup.Priority ) ); - j.WriteValue( priority.Value ); + j.WritePropertyName(nameof(IModGroup.Priority)); + j.WriteValue(priority.Value); } - j.WritePropertyName( nameof( mod.Files ) ); + j.WritePropertyName(nameof(mod.Files)); j.WriteStartObject(); - foreach( var (gamePath, file) in mod.Files ) + foreach (var (gamePath, file) in mod.Files) { - if( file.ToRelPath( basePath, out var relPath ) ) + if (file.ToRelPath(basePath, out var relPath)) { - j.WritePropertyName( gamePath.ToString() ); - j.WriteValue( relPath.ToString() ); + j.WritePropertyName(gamePath.ToString()); + j.WriteValue(relPath.ToString()); } } j.WriteEndObject(); - j.WritePropertyName( nameof( mod.FileSwaps ) ); + j.WritePropertyName(nameof(mod.FileSwaps)); j.WriteStartObject(); - foreach( var (gamePath, file) in mod.FileSwaps ) + foreach (var (gamePath, file) in mod.FileSwaps) { - j.WritePropertyName( gamePath.ToString() ); - j.WriteValue( file.ToString() ); + j.WritePropertyName(gamePath.ToString()); + j.WriteValue(file.ToString()); } j.WriteEndObject(); - j.WritePropertyName( nameof( mod.Manipulations ) ); - serializer.Serialize( j, mod.Manipulations ); + j.WritePropertyName(nameof(mod.Manipulations)); + serializer.Serialize(j, mod.Manipulations); j.WriteEndObject(); } -} \ No newline at end of file +} diff --git a/Penumbra/Mods/Subclasses/ModSettings.cs b/Penumbra/Mods/Subclasses/ModSettings.cs index 537c989f..122c6d29 100644 --- a/Penumbra/Mods/Subclasses/ModSettings.cs +++ b/Penumbra/Mods/Subclasses/ModSettings.cs @@ -3,10 +3,9 @@ using OtterGui.Filesystem; using Penumbra.Api.Enums; using Penumbra.Meta.Manipulations; using Penumbra.Mods.Manager; -using Penumbra.Mods.Subclasses; using Penumbra.String.Classes; -namespace Penumbra.Mods; +namespace Penumbra.Mods.Subclasses; /// Contains the settings for a given mod. public class ModSettings @@ -267,4 +266,4 @@ public class ModSettings return ( Enabled, Priority, dict ); } -} \ No newline at end of file +} diff --git a/Penumbra/Mods/Subclasses/MultiModGroup.cs b/Penumbra/Mods/Subclasses/MultiModGroup.cs index d40a79be..4d29c58d 100644 --- a/Penumbra/Mods/Subclasses/MultiModGroup.cs +++ b/Penumbra/Mods/Subclasses/MultiModGroup.cs @@ -4,10 +4,9 @@ using Newtonsoft.Json.Linq; using OtterGui; using OtterGui.Filesystem; using Penumbra.Api.Enums; -using Penumbra.Mods.Subclasses; -namespace Penumbra.Mods; - +namespace Penumbra.Mods.Subclasses; + /// Groups that allow all available options to be selected at once. public sealed class MultiModGroup : IModGroup { diff --git a/Penumbra/Mods/Subclasses/SingleModGroup.cs b/Penumbra/Mods/Subclasses/SingleModGroup.cs index a69238f5..1184b6ed 100644 --- a/Penumbra/Mods/Subclasses/SingleModGroup.cs +++ b/Penumbra/Mods/Subclasses/SingleModGroup.cs @@ -3,9 +3,8 @@ using Newtonsoft.Json.Linq; using OtterGui; using OtterGui.Filesystem; using Penumbra.Api.Enums; -using Penumbra.Mods.Subclasses; -namespace Penumbra.Mods; +namespace Penumbra.Mods.Subclasses; /// Groups that allow only one of their available options to be selected. public sealed class SingleModGroup : IModGroup @@ -18,59 +17,55 @@ public sealed class SingleModGroup : IModGroup public int Priority { get; set; } public uint DefaultSettings { get; set; } - public readonly List< SubMod > OptionData = new(); + public readonly List OptionData = new(); - public int OptionPriority( Index _ ) + public int OptionPriority(Index _) => Priority; - public ISubMod this[ Index idx ] - => OptionData[ idx ]; + public ISubMod this[Index idx] + => OptionData[idx]; [JsonIgnore] public int Count => OptionData.Count; - public IEnumerator< ISubMod > GetEnumerator() + public IEnumerator GetEnumerator() => OptionData.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - public static SingleModGroup? Load( Mod mod, JObject json, int groupIdx ) + public static SingleModGroup? Load(Mod mod, JObject json, int groupIdx) { - var options = json[ "Options" ]; + var options = json["Options"]; var ret = new SingleModGroup { - Name = json[ nameof( Name ) ]?.ToObject< string >() ?? string.Empty, - Description = json[ nameof( Description ) ]?.ToObject< string >() ?? string.Empty, - Priority = json[ nameof( Priority ) ]?.ToObject< int >() ?? 0, - DefaultSettings = json[ nameof( DefaultSettings ) ]?.ToObject< uint >() ?? 0u, + Name = json[nameof(Name)]?.ToObject() ?? string.Empty, + Description = json[nameof(Description)]?.ToObject() ?? string.Empty, + Priority = json[nameof(Priority)]?.ToObject() ?? 0, + DefaultSettings = json[nameof(DefaultSettings)]?.ToObject() ?? 0u, }; - if( ret.Name.Length == 0 ) - { + if (ret.Name.Length == 0) return null; - } - if( options != null ) - { - foreach( var child in options.Children() ) + if (options != null) + foreach (var child in options.Children()) { - var subMod = new SubMod( mod ); - subMod.SetPosition( groupIdx, ret.OptionData.Count ); - subMod.Load( mod.ModPath, child, out _ ); - ret.OptionData.Add( subMod ); + var subMod = new SubMod(mod); + subMod.SetPosition(groupIdx, ret.OptionData.Count); + subMod.Load(mod.ModPath, child, out _); + ret.OptionData.Add(subMod); } - } - if( ( int )ret.DefaultSettings >= ret.Count ) + if ((int)ret.DefaultSettings >= ret.Count) ret.DefaultSettings = 0; return ret; } - public IModGroup Convert( GroupType type ) + public IModGroup Convert(GroupType type) { - switch( type ) + switch (type) { case GroupType.Single: return this; case GroupType.Multi: @@ -79,47 +74,41 @@ public sealed class SingleModGroup : IModGroup Name = Name, Description = Description, Priority = Priority, - DefaultSettings = 1u << ( int )DefaultSettings, + DefaultSettings = 1u << (int)DefaultSettings, }; - multi.PrioritizedOptions.AddRange( OptionData.Select( ( o, i ) => ( o, i ) ) ); + multi.PrioritizedOptions.AddRange(OptionData.Select((o, i) => (o, i))); return multi; - default: throw new ArgumentOutOfRangeException( nameof( type ), type, null ); + default: throw new ArgumentOutOfRangeException(nameof(type), type, null); } } - public bool MoveOption( int optionIdxFrom, int optionIdxTo ) + public bool MoveOption(int optionIdxFrom, int optionIdxTo) { - if( !OptionData.Move( optionIdxFrom, optionIdxTo ) ) - { + if (!OptionData.Move(optionIdxFrom, optionIdxTo)) return false; - } // Update default settings with the move. - if( DefaultSettings == optionIdxFrom ) + if (DefaultSettings == optionIdxFrom) { - DefaultSettings = ( uint )optionIdxTo; + DefaultSettings = (uint)optionIdxTo; } - else if( optionIdxFrom < optionIdxTo ) + else if (optionIdxFrom < optionIdxTo) { - if( DefaultSettings > optionIdxFrom && DefaultSettings <= optionIdxTo ) - { + if (DefaultSettings > optionIdxFrom && DefaultSettings <= optionIdxTo) --DefaultSettings; - } } - else if( DefaultSettings < optionIdxFrom && DefaultSettings >= optionIdxTo ) + else if (DefaultSettings < optionIdxFrom && DefaultSettings >= optionIdxTo) { ++DefaultSettings; } - UpdatePositions( Math.Min( optionIdxFrom, optionIdxTo ) ); + UpdatePositions(Math.Min(optionIdxFrom, optionIdxTo)); return true; } - public void UpdatePositions( int from = 0 ) + public void UpdatePositions(int from = 0) { - foreach( var (o, i) in OptionData.WithIndex().Skip( from ) ) - { - o.SetPosition( o.GroupIdx, i ); - } + foreach (var (o, i) in OptionData.WithIndex().Skip(from)) + o.SetPosition(o.GroupIdx, i); } -} \ No newline at end of file +} diff --git a/Penumbra/Mods/Subclasses/Mod.Files.SubMod.cs b/Penumbra/Mods/Subclasses/SubMod.cs similarity index 97% rename from Penumbra/Mods/Subclasses/Mod.Files.SubMod.cs rename to Penumbra/Mods/Subclasses/SubMod.cs index 7c43de86..542b14d2 100644 --- a/Penumbra/Mods/Subclasses/Mod.Files.SubMod.cs +++ b/Penumbra/Mods/Subclasses/SubMod.cs @@ -1,11 +1,8 @@ using Newtonsoft.Json.Linq; -using Penumbra.Import; -using Penumbra.Meta; using Penumbra.Meta.Manipulations; -using Penumbra.Mods.Subclasses; using Penumbra.String.Classes; -namespace Penumbra.Mods; +namespace Penumbra.Mods.Subclasses; /// /// A sub mod is a collection of diff --git a/Penumbra/Mods/TemporaryMod.cs b/Penumbra/Mods/TemporaryMod.cs index fcd4a5f7..73273707 100644 --- a/Penumbra/Mods/TemporaryMod.cs +++ b/Penumbra/Mods/TemporaryMod.cs @@ -5,7 +5,6 @@ using Penumbra.Mods.Manager; using Penumbra.Mods.Subclasses; using Penumbra.Services; using Penumbra.String.Classes; -using Penumbra.Util; namespace Penumbra.Mods; @@ -21,80 +20,84 @@ public class TemporaryMod : IMod public readonly SubMod Default; ISubMod IMod.Default - => Default; + => Default; - public IReadOnlyList< IModGroup > Groups - => Array.Empty< IModGroup >(); + public IReadOnlyList Groups + => Array.Empty(); - public IEnumerable< SubMod > AllSubMods - => new[] { Default }; + public IEnumerable AllSubMods + => new[] + { + Default, + }; public TemporaryMod() - => Default = new SubMod( this ); + => Default = new SubMod(this); - public void SetFile( Utf8GamePath gamePath, FullPath fullPath ) - => Default.FileData[ gamePath ] = fullPath; + public void SetFile(Utf8GamePath gamePath, FullPath fullPath) + => Default.FileData[gamePath] = fullPath; - public bool SetManipulation( MetaManipulation manip ) - => Default.ManipulationData.Remove( manip ) | Default.ManipulationData.Add( manip ); + public bool SetManipulation(MetaManipulation manip) + => Default.ManipulationData.Remove(manip) | Default.ManipulationData.Add(manip); - public void SetAll( Dictionary< Utf8GamePath, FullPath > dict, HashSet< MetaManipulation > manips ) + public void SetAll(Dictionary dict, HashSet manips) { Default.FileData = dict; Default.ManipulationData = manips; } - public static void SaveTempCollection( Configuration config, SaveService saveService, ModManager modManager, ModCollection collection, string? character = null ) + public static void SaveTempCollection(Configuration config, SaveService saveService, ModManager modManager, ModCollection collection, + string? character = null) { DirectoryInfo? dir = null; try { - dir = ModCreator.CreateModFolder( modManager.BasePath, collection.Name ); - var fileDir = Directory.CreateDirectory( Path.Combine( dir.FullName, "files" ) ); - modManager.DataEditor.CreateMeta( dir, collection.Name, character ?? config.DefaultModAuthor, - $"Mod generated from temporary collection {collection.Name} for {character ?? "Unknown Character"}.", null, null ); - var mod = new Mod( dir ); + dir = ModCreator.CreateModFolder(modManager.BasePath, collection.Name); + var fileDir = Directory.CreateDirectory(Path.Combine(dir.FullName, "files")); + modManager.DataEditor.CreateMeta(dir, collection.Name, character ?? config.DefaultModAuthor, + $"Mod generated from temporary collection {collection.Name} for {character ?? "Unknown Character"}.", null, null); + var mod = new Mod(dir); var defaultMod = mod.Default; - foreach( var (gamePath, fullPath) in collection.ResolvedFiles ) + foreach (var (gamePath, fullPath) in collection.ResolvedFiles) { - if( gamePath.Path.EndsWith( ".imc"u8 ) ) + if (gamePath.Path.EndsWith(".imc"u8)) { continue; } var targetPath = fullPath.Path.FullName; - if( fullPath.Path.Name.StartsWith( '|' ) ) + if (fullPath.Path.Name.StartsWith('|')) { - targetPath = targetPath.Split( '|', 3, StringSplitOptions.RemoveEmptyEntries ).Last(); + targetPath = targetPath.Split('|', 3, StringSplitOptions.RemoveEmptyEntries).Last(); } - if( Path.IsPathRooted(targetPath) ) + if (Path.IsPathRooted(targetPath)) { - var target = Path.Combine( fileDir.FullName, Path.GetFileName(targetPath) ); - File.Copy( targetPath, target, true ); - defaultMod.FileData[ gamePath ] = new FullPath( target ); + var target = Path.Combine(fileDir.FullName, Path.GetFileName(targetPath)); + File.Copy(targetPath, target, true); + defaultMod.FileData[gamePath] = new FullPath(target); } else { - defaultMod.FileSwapData[ gamePath ] = new FullPath(targetPath); + defaultMod.FileSwapData[gamePath] = new FullPath(targetPath); } } - foreach( var manip in collection.MetaCache?.Manipulations ?? Array.Empty< MetaManipulation >() ) - defaultMod.ManipulationData.Add( manip ); + foreach (var manip in collection.MetaCache?.Manipulations ?? Array.Empty()) + defaultMod.ManipulationData.Add(manip); saveService.ImmediateSave(new ModSaveGroup(dir, defaultMod)); - modManager.AddMod( dir ); - Penumbra.Log.Information( $"Successfully generated mod {mod.Name} at {mod.ModPath.FullName} for collection {collection.Name}." ); + modManager.AddMod(dir); + Penumbra.Log.Information($"Successfully generated mod {mod.Name} at {mod.ModPath.FullName} for collection {collection.Name}."); } - catch( Exception e ) + catch (Exception e) { - Penumbra.Log.Error( $"Could not save temporary collection {collection.Name} to permanent Mod:\n{e}" ); - if( dir != null && Directory.Exists( dir.FullName ) ) + Penumbra.Log.Error($"Could not save temporary collection {collection.Name} to permanent Mod:\n{e}"); + if (dir != null && Directory.Exists(dir.FullName)) { try { - Directory.Delete( dir.FullName, true ); + Directory.Delete(dir.FullName, true); } catch { @@ -103,4 +106,4 @@ public class TemporaryMod : IMod } } } -} \ No newline at end of file +} diff --git a/Penumbra/Penumbra.cs b/Penumbra/Penumbra.cs index 1402ef89..019355af 100644 --- a/Penumbra/Penumbra.cs +++ b/Penumbra/Penumbra.cs @@ -20,6 +20,7 @@ using Penumbra.UI.Tabs; using ChangedItemClick = Penumbra.Communication.ChangedItemClick; using ChangedItemHover = Penumbra.Communication.ChangedItemHover; using OtterGui.Tasks; +using Penumbra.UI; namespace Penumbra; diff --git a/Penumbra/Services/ConfigMigrationService.cs b/Penumbra/Services/ConfigMigrationService.cs index 89f1063e..d896e526 100644 --- a/Penumbra/Services/ConfigMigrationService.cs +++ b/Penumbra/Services/ConfigMigrationService.cs @@ -7,6 +7,7 @@ using Penumbra.Interop.Services; using Penumbra.Mods; using Penumbra.Mods.Editor; using Penumbra.Mods.Manager; +using Penumbra.Mods.Subclasses; using Penumbra.UI.Classes; namespace Penumbra.Services; @@ -331,7 +332,8 @@ public class ConfigMigrationService dict = dict.ToDictionary(kvp => kvp.Key, kvp => kvp.Value with { Priority = maxPriority - kvp.Value.Priority }); var emptyStorage = new ModStorage(); - var collection = ModCollection.CreateFromData(_saveService, emptyStorage, ModCollection.DefaultCollectionName, 0, 1, dict, Array.Empty()); + var collection = ModCollection.CreateFromData(_saveService, emptyStorage, ModCollection.DefaultCollectionName, 0, 1, dict, + Array.Empty()); _saveService.ImmediateSave(new ModCollectionSave(emptyStorage, collection)); } catch (Exception e) diff --git a/Penumbra/Services/DalamudServices.cs b/Penumbra/Services/DalamudServices.cs index 6754d0bd..0cd4c97a 100644 --- a/Penumbra/Services/DalamudServices.cs +++ b/Penumbra/Services/DalamudServices.cs @@ -6,7 +6,6 @@ using Dalamud.Game.Gui; using Dalamud.Interface; using Dalamud.IoC; using Dalamud.Plugin; -using System.Reflection; using Dalamud.Interface.DragDrop; using Dalamud.Plugin.Services; using Microsoft.Extensions.DependencyInjection; diff --git a/Penumbra/Services/ServiceManager.cs b/Penumbra/Services/ServiceManager.cs index 07c7394c..b76c39ef 100644 --- a/Penumbra/Services/ServiceManager.cs +++ b/Penumbra/Services/ServiceManager.cs @@ -21,6 +21,7 @@ using Penumbra.UI; using Penumbra.UI.AdvancedWindow; using Penumbra.UI.Classes; using Penumbra.UI.ModsTab; +using Penumbra.UI.ResourceWatcher; using Penumbra.UI.Tabs; namespace Penumbra.Services; diff --git a/Penumbra/Services/StainService.cs b/Penumbra/Services/StainService.cs index 1c6b3ef1..30e22a7a 100644 --- a/Penumbra/Services/StainService.cs +++ b/Penumbra/Services/StainService.cs @@ -16,17 +16,18 @@ public class StainService : IDisposable { } } - public readonly StainData StainData; - public readonly FilterComboColors StainCombo; - public readonly StmFile StmFile; + public readonly StainData StainData; + public readonly FilterComboColors StainCombo; + public readonly StmFile StmFile; public readonly StainTemplateCombo TemplateCombo; public StainService(StartTracker timer, DalamudPluginInterface pluginInterface, IDataManager dataManager) { using var t = timer.Measure(StartTimeType.Stains); StainData = new StainData(pluginInterface, dataManager, dataManager.Language); - StainCombo = new FilterComboColors(140, StainData.Data.Prepend(new KeyValuePair(0, ("None", 0, false)))); - StmFile = new StmFile(dataManager); + StainCombo = new FilterComboColors(140, + StainData.Data.Prepend(new KeyValuePair(0, ("None", 0, false)))); + StmFile = new StmFile(dataManager); TemplateCombo = new StainTemplateCombo(StmFile.Entries.Keys.Prepend((ushort)0)); Penumbra.Log.Verbose($"[{nameof(StainService)}] Created."); } @@ -36,4 +37,4 @@ public class StainService : IDisposable StainData.Dispose(); Penumbra.Log.Verbose($"[{nameof(StainService)}] Disposed."); } -} \ No newline at end of file +} diff --git a/Penumbra/Services/ValidityChecker.cs b/Penumbra/Services/ValidityChecker.cs index e97a9a82..b8d9b30a 100644 --- a/Penumbra/Services/ValidityChecker.cs +++ b/Penumbra/Services/ValidityChecker.cs @@ -1,4 +1,3 @@ -using System.Reflection; using Dalamud.Interface.Internal.Notifications; using Dalamud.Plugin; @@ -25,20 +24,21 @@ public class ValidityChecker DevPenumbraExists = CheckDevPluginPenumbra(pi); IsNotInstalledPenumbra = CheckIsNotInstalled(pi); IsValidSourceRepo = CheckSourceRepo(pi); - + var assembly = Assembly.GetExecutingAssembly(); - Version = assembly.GetName().Version?.ToString() ?? string.Empty; + Version = assembly.GetName().Version?.ToString() ?? string.Empty; CommitHash = assembly.GetCustomAttribute()?.InformationalVersion ?? "Unknown"; } public void LogExceptions() { - if( ImcExceptions.Count > 0 ) - Penumbra.Chat.NotificationMessage( $"{ImcExceptions} IMC Exceptions thrown during Penumbra load. Please repair your game files.", "Warning", NotificationType.Warning ); + if (ImcExceptions.Count > 0) + Penumbra.Chat.NotificationMessage($"{ImcExceptions} IMC Exceptions thrown during Penumbra load. Please repair your game files.", + "Warning", NotificationType.Warning); } // Because remnants of penumbra in devPlugins cause issues, we check for them to warn users to remove them. - private static bool CheckDevPluginPenumbra( DalamudPluginInterface pi ) + private static bool CheckDevPluginPenumbra(DalamudPluginInterface pi) { #if !DEBUG var path = Path.Combine( pi.DalamudAssetDirectory.Parent?.FullName ?? "INVALIDPATH", "devPlugins", "Penumbra" ); @@ -59,7 +59,7 @@ public class ValidityChecker } // Check if the loaded version of Penumbra itself is in devPlugins. - private static bool CheckIsNotInstalled( DalamudPluginInterface pi ) + private static bool CheckIsNotInstalled(DalamudPluginInterface pi) { #if !DEBUG var checkedDirectory = pi.AssemblyLocation.Directory?.Parent?.Parent?.Name; @@ -76,7 +76,7 @@ public class ValidityChecker } // Check if the loaded version of Penumbra is installed from a valid source repo. - private static bool CheckSourceRepo( DalamudPluginInterface pi ) + private static bool CheckSourceRepo(DalamudPluginInterface pi) { #if !DEBUG return pi.SourceRepository?.Trim().ToLowerInvariant() switch @@ -90,4 +90,4 @@ public class ValidityChecker return true; #endif } -} \ No newline at end of file +} diff --git a/Penumbra/Services/Wrappers.cs b/Penumbra/Services/Wrappers.cs index d9bef172..69dbbeab 100644 --- a/Penumbra/Services/Wrappers.cs +++ b/Penumbra/Services/Wrappers.cs @@ -12,7 +12,8 @@ namespace Penumbra.Services; public sealed class IdentifierService : AsyncServiceWrapper { public IdentifierService(StartTracker tracker, DalamudPluginInterface pi, IDataManager data, ItemService items) - : base(nameof(IdentifierService), tracker, StartTimeType.Identifier, () => GameData.GameData.GetIdentifier(pi, data, items.AwaitedService)) + : base(nameof(IdentifierService), tracker, StartTimeType.Identifier, + () => GameData.GameData.GetIdentifier(pi, data, items.AwaitedService)) { } } @@ -30,4 +31,4 @@ public sealed class ActorService : AsyncServiceWrapper : base(nameof(ActorService), tracker, StartTimeType.Actors, () => new ActorManager(pi, objects, clientState, framework, gameData, gui, idx => (short)cutscene.GetParentIndex(idx))) { } -} \ No newline at end of file +} diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Files.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Files.cs index d14c7125..4a193591 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Files.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Files.cs @@ -4,6 +4,7 @@ using OtterGui; using OtterGui.Classes; using OtterGui.Raii; using Penumbra.Mods; +using Penumbra.Mods.Subclasses; using Penumbra.String.Classes; using Penumbra.UI.Classes; @@ -289,14 +290,14 @@ public partial class ModEditWindow if (_selectedFiles.Count == 0) tt += "\n\nNo files selected."; else if (!active) - tt += $"\n\nHold {_config.DeleteModModifier} to delete."; - + tt += $"\n\nHold {_config.DeleteModModifier} to delete."; + if (ImGuiUtil.DrawDisabledButton("Delete Selected Files", Vector2.Zero, tt, _selectedFiles.Count == 0 || !active)) _editor.FileEditor.DeleteFiles(_editor.Mod!, _editor.Option!, _editor.Files.Available.Where(_selectedFiles.Contains)); ImGui.SameLine(); var changes = _editor.FileEditor.Changes; - tt = changes ? "Apply the current file setup to the currently selected option." : "No changes made."; + tt = changes ? "Apply the current file setup to the currently selected option." : "No changes made."; if (ImGuiUtil.DrawDisabledButton("Apply Changes", Vector2.Zero, tt, !changes)) { var failedFiles = _editor.FileEditor.Apply(_editor.Mod!, (SubMod)_editor.Option!); diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.ColorTable.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.ColorTable.cs index 4f04150f..cccc43ee 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.ColorTable.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.ColorTable.cs @@ -32,7 +32,7 @@ public partial class ModEditWindow ImGui.SameLine(); ret |= ColorTableDyeableCheckbox(tab); } - + var hasDyeTable = tab.Mtrl.HasDyeTable; if (hasDyeTable) { @@ -114,10 +114,8 @@ public partial class ModEditWindow { var ret = false; if (tab.Mtrl.HasDyeTable) - { for (var i = 0; i < MtrlFile.ColorTable.NumRows; ++i) ret |= tab.Mtrl.ApplyDyeTemplate(_stainService.StmFile, i, dyeId); - } tab.UpdateColorTablePreview(); @@ -195,7 +193,7 @@ public partial class ModEditWindow } private static bool ColorTableDyeableCheckbox(MtrlTab tab) - { + { var dyeable = tab.Mtrl.HasDyeTable; var ret = ImGui.Checkbox("Dyeable", ref dyeable); @@ -259,9 +257,9 @@ public partial class ModEditWindow } using var id = ImRaii.PushId(rowIdx); - ref var row = ref tab.Mtrl.Table[rowIdx]; + ref var row = ref tab.Mtrl.Table[rowIdx]; var hasDye = tab.Mtrl.HasDyeTable; - ref var dye = ref tab.Mtrl.DyeTable[rowIdx]; + ref var dye = ref tab.Mtrl.DyeTable[rowIdx]; var floatSize = 70 * UiHelpers.Scale; var intSize = 45 * UiHelpers.Scale; ImGui.TableNextColumn(); @@ -301,7 +299,8 @@ public partial class ModEditWindow ImGui.SameLine(); var tmpFloat = row.SpecularStrength; ImGui.SetNextItemWidth(floatSize); - if (ImGui.DragFloat("##SpecularStrength", ref tmpFloat, 0.01f, 0f, HalfMaxValue, "%.2f") && FixFloat(ref tmpFloat, row.SpecularStrength)) + if (ImGui.DragFloat("##SpecularStrength", ref tmpFloat, 0.01f, 0f, HalfMaxValue, "%.2f") + && FixFloat(ref tmpFloat, row.SpecularStrength)) { row.SpecularStrength = tmpFloat; ret = true; diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.MtrlTab.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.MtrlTab.cs index 187d86c7..ad83843d 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.MtrlTab.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.MtrlTab.cs @@ -475,9 +475,9 @@ public partial class ModEditWindow } } - UpdateMaterialPreview(); - - if (!Mtrl.HasTable) + UpdateMaterialPreview(); + + if (!Mtrl.HasTable) return; foreach (var materialInfo in instances) @@ -591,9 +591,9 @@ public partial class ModEditWindow public void UpdateColorTableRowPreview(int rowIdx) { if (ColorTablePreviewers.Count == 0) - return; - - if (!Mtrl.HasTable) + return; + + if (!Mtrl.HasTable) return; var row = Mtrl.Table[rowIdx]; @@ -619,16 +619,16 @@ public partial class ModEditWindow public void UpdateColorTablePreview() { if (ColorTablePreviewers.Count == 0) - return; - - if (!Mtrl.HasTable) + return; + + if (!Mtrl.HasTable) return; var rows = Mtrl.Table; if (Mtrl.HasDyeTable) { - var stm = _edit._stainService.StmFile; - var stainId = (StainId)_edit._stainService.StainCombo.CurrentSelection.Key; + var stm = _edit._stainService.StmFile; + var stainId = (StainId)_edit._stainService.StainCombo.CurrentSelection.Key; for (var i = 0; i < MtrlFile.ColorTable.NumRows; ++i) { ref var row = ref rows[i]; diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Meta.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Meta.cs index a6a93a36..821f4454 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Meta.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Meta.cs @@ -8,7 +8,6 @@ using Penumbra.Interop.Structs; using Penumbra.Meta; using Penumbra.Meta.Files; using Penumbra.Meta.Manipulations; -using Penumbra.Mods; using Penumbra.Mods.Editor; using Penumbra.UI.Classes; @@ -66,20 +65,26 @@ public partial class ModEditWindow if (!child) return; - DrawEditHeader(_editor.MetaEditor.Eqp, "Equipment Parameter Edits (EQP)###EQP", 5, EqpRow.Draw, EqpRow.DrawNew , _editor.MetaEditor.OtherEqpCount); - DrawEditHeader(_editor.MetaEditor.Eqdp, "Racial Model Edits (EQDP)###EQDP", 7, EqdpRow.Draw, EqdpRow.DrawNew, _editor.MetaEditor.OtherEqdpCount); - DrawEditHeader(_editor.MetaEditor.Imc, "Variant Edits (IMC)###IMC", 10, ImcRow.Draw, ImcRow.DrawNew , _editor.MetaEditor.OtherImcCount); - DrawEditHeader(_editor.MetaEditor.Est, "Extra Skeleton Parameters (EST)###EST", 7, EstRow.Draw, EstRow.DrawNew , _editor.MetaEditor.OtherEstCount); - DrawEditHeader(_editor.MetaEditor.Gmp, "Visor/Gimmick Edits (GMP)###GMP", 7, GmpRow.Draw, GmpRow.DrawNew , _editor.MetaEditor.OtherGmpCount); - DrawEditHeader(_editor.MetaEditor.Rsp, "Racial Scaling Edits (RSP)###RSP", 5, RspRow.Draw, RspRow.DrawNew , _editor.MetaEditor.OtherRspCount); + DrawEditHeader(_editor.MetaEditor.Eqp, "Equipment Parameter Edits (EQP)###EQP", 5, EqpRow.Draw, EqpRow.DrawNew, + _editor.MetaEditor.OtherEqpCount); + DrawEditHeader(_editor.MetaEditor.Eqdp, "Racial Model Edits (EQDP)###EQDP", 7, EqdpRow.Draw, EqdpRow.DrawNew, + _editor.MetaEditor.OtherEqdpCount); + DrawEditHeader(_editor.MetaEditor.Imc, "Variant Edits (IMC)###IMC", 10, ImcRow.Draw, ImcRow.DrawNew, _editor.MetaEditor.OtherImcCount); + DrawEditHeader(_editor.MetaEditor.Est, "Extra Skeleton Parameters (EST)###EST", 7, EstRow.Draw, EstRow.DrawNew, + _editor.MetaEditor.OtherEstCount); + DrawEditHeader(_editor.MetaEditor.Gmp, "Visor/Gimmick Edits (GMP)###GMP", 7, GmpRow.Draw, GmpRow.DrawNew, + _editor.MetaEditor.OtherGmpCount); + DrawEditHeader(_editor.MetaEditor.Rsp, "Racial Scaling Edits (RSP)###RSP", 5, RspRow.Draw, RspRow.DrawNew, + _editor.MetaEditor.OtherRspCount); } - /// The headers for the different meta changes all have basically the same structure for different types. - private void DrawEditHeader(IReadOnlyCollection items, string label, int numColumns, Action draw, + /// The headers for the different meta changes all have basically the same structure for different types. + private void DrawEditHeader(IReadOnlyCollection items, string label, int numColumns, + Action draw, Action drawNew, int otherCount) - { - const ImGuiTableFlags flags = ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.BordersInnerV; + { + const ImGuiTableFlags flags = ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.BordersInnerV; var oldPos = ImGui.GetCursorPosY(); var header = ImGui.CollapsingHeader($"{items.Count} {label}"); @@ -88,10 +93,11 @@ public partial class ModEditWindow { var text = $"{otherCount} Edits in other Options"; var size = ImGui.CalcTextSize(text).X; - ImGui.SetCursorPos(new Vector2(ImGui.GetContentRegionAvail().X - size, oldPos + ImGui.GetStyle().FramePadding.Y)); - ImGuiUtil.TextColored(ColorId.RedundantAssignment.Value() | 0xFF000000, text); + ImGui.SetCursorPos(new Vector2(ImGui.GetContentRegionAvail().X - size, oldPos + ImGui.GetStyle().FramePadding.Y)); + ImGuiUtil.TextColored(ColorId.RedundantAssignment.Value() | 0xFF000000, text); ImGui.SetCursorPos(newPos); - } + } + if (!header) return; @@ -223,7 +229,8 @@ public partial class ModEditWindow ImGui.TableNextColumn(); if (IdInput("##eqdpId", IdWidth, _new.SetId.Id, out var setId, 0, ExpandedEqpGmpBase.Count - 1, _new.SetId <= 1)) { - var newDefaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(_new.Gender, _new.Race), _new.Slot.IsAccessory(), setId); + var newDefaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(_new.Gender, _new.Race), + _new.Slot.IsAccessory(), setId); _new = new EqdpManipulation(newDefaultEntry, _new.Slot, _new.Gender, _new.Race, setId); } @@ -232,7 +239,8 @@ public partial class ModEditWindow ImGui.TableNextColumn(); if (Combos.Race("##eqdpRace", _new.Race, out var race)) { - var newDefaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(_new.Gender, race), _new.Slot.IsAccessory(), _new.SetId); + var newDefaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(_new.Gender, race), + _new.Slot.IsAccessory(), _new.SetId); _new = new EqdpManipulation(newDefaultEntry, _new.Slot, _new.Gender, race, _new.SetId); } @@ -241,7 +249,8 @@ public partial class ModEditWindow ImGui.TableNextColumn(); if (Combos.Gender("##eqdpGender", _new.Gender, out var gender)) { - var newDefaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(gender, _new.Race), _new.Slot.IsAccessory(), _new.SetId); + var newDefaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(gender, _new.Race), + _new.Slot.IsAccessory(), _new.SetId); _new = new EqdpManipulation(newDefaultEntry, _new.Slot, gender, _new.Race, _new.SetId); } @@ -250,7 +259,8 @@ public partial class ModEditWindow ImGui.TableNextColumn(); if (Combos.EqdpEquipSlot("##eqdpSlot", _new.Slot, out var slot)) { - var newDefaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(_new.Gender, _new.Race), slot.IsAccessory(), _new.SetId); + var newDefaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(_new.Gender, _new.Race), + slot.IsAccessory(), _new.SetId); _new = new EqdpManipulation(newDefaultEntry, slot, _new.Gender, _new.Race, _new.SetId); } @@ -288,7 +298,8 @@ public partial class ModEditWindow ImGuiUtil.HoverTooltip(EquipSlotTooltip); // Values - var defaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(meta.Gender, meta.Race), meta.Slot.IsAccessory(), meta.SetId); + var defaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(meta.Gender, meta.Race), meta.Slot.IsAccessory(), + meta.SetId); var (defaultBit1, defaultBit2) = defaultEntry.ToBits(meta.Slot); var (bit1, bit2) = meta.Entry.ToBits(meta.Slot); ImGui.TableNextColumn(); @@ -311,7 +322,7 @@ public partial class ModEditWindow private static float SmallIdWidth => 45 * UiHelpers.Scale; - /// Convert throwing to null-return if the file does not exist. + /// Convert throwing to null-return if the file does not exist. private static ImcEntry? GetDefault(MetaFileManager metaFileManager, ImcManipulation imc) { try @@ -370,7 +381,8 @@ public partial class ModEditWindow if (_new.ObjectType is ObjectType.Equipment) { if (Combos.EqpEquipSlot("##imcSlot", 100, _new.EquipSlot, out var slot)) - _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, _new.SecondaryId, _new.Variant.Id, slot, _new.Entry) + _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, _new.SecondaryId, _new.Variant.Id, slot, + _new.Entry) .Copy(GetDefault(metaFileManager, _new) ?? new ImcEntry()); @@ -379,7 +391,8 @@ public partial class ModEditWindow else if (_new.ObjectType is ObjectType.Accessory) { if (Combos.AccessorySlot("##imcSlot", _new.EquipSlot, out var slot)) - _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, _new.SecondaryId, _new.Variant.Id, slot, _new.Entry) + _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, _new.SecondaryId, _new.Variant.Id, slot, + _new.Entry) .Copy(GetDefault(metaFileManager, _new) ?? new ImcEntry()); @@ -388,7 +401,8 @@ public partial class ModEditWindow else { if (IdInput("##imcId2", 100 * UiHelpers.Scale, _new.SecondaryId.Id, out var setId2, 0, ushort.MaxValue, false)) - _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, setId2, _new.Variant.Id, _new.EquipSlot, _new.Entry) + _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, setId2, _new.Variant.Id, _new.EquipSlot, + _new.Entry) .Copy(GetDefault(metaFileManager, _new) ?? new ImcEntry()); @@ -405,7 +419,8 @@ public partial class ModEditWindow if (_new.ObjectType is ObjectType.DemiHuman) { if (Combos.EqpEquipSlot("##imcSlot", 70, _new.EquipSlot, out var slot)) - _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, _new.SecondaryId, _new.Variant.Id, slot, _new.Entry) + _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, _new.SecondaryId, _new.Variant.Id, slot, + _new.Entry) .Copy(GetDefault(metaFileManager, _new) ?? new ImcEntry()); @@ -787,7 +802,8 @@ public partial class ModEditWindow using var color = ImRaii.PushColor(ImGuiCol.FrameBg, def < value ? ColorId.IncreasedMetaValue.Value() : ColorId.DecreasedMetaValue.Value(), def != value); - if (ImGui.DragFloat("##rspValue", ref value, 0.001f, RspManipulation.MinValue, RspManipulation.MaxValue) && value is >= RspManipulation.MinValue and <= RspManipulation.MaxValue) + if (ImGui.DragFloat("##rspValue", ref value, 0.001f, RspManipulation.MinValue, RspManipulation.MaxValue) + && value is >= RspManipulation.MinValue and <= RspManipulation.MaxValue) editor.MetaEditor.Change(meta.Copy(value)); ImGuiUtil.HoverTooltip($"Default Value: {def:0.###}"); diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs index c90eb2b4..5d74dc33 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs @@ -9,125 +9,108 @@ namespace Penumbra.UI.AdvancedWindow; public partial class ModEditWindow { - private readonly FileEditor< MdlFile > _modelTab; + private readonly FileEditor _modelTab; - private static bool DrawModelPanel( MdlFile file, bool disabled ) + private static bool DrawModelPanel(MdlFile file, bool disabled) { var ret = false; - for( var i = 0; i < file.Materials.Length; ++i ) + for (var i = 0; i < file.Materials.Length; ++i) { - using var id = ImRaii.PushId( i ); - var tmp = file.Materials[ i ]; - if( ImGui.InputText( string.Empty, ref tmp, Utf8GamePath.MaxGamePathLength, - disabled ? ImGuiInputTextFlags.ReadOnly : ImGuiInputTextFlags.None ) - && tmp.Length > 0 - && tmp != file.Materials[ i ] ) + using var id = ImRaii.PushId(i); + var tmp = file.Materials[i]; + if (ImGui.InputText(string.Empty, ref tmp, Utf8GamePath.MaxGamePathLength, + disabled ? ImGuiInputTextFlags.ReadOnly : ImGuiInputTextFlags.None) + && tmp.Length > 0 + && tmp != file.Materials[i]) { - file.Materials[ i ] = tmp; - ret = true; + file.Materials[i] = tmp; + ret = true; } } - ret |= DrawOtherModelDetails( file, disabled ); + ret |= DrawOtherModelDetails(file, disabled); return !disabled && ret; } - private static bool DrawOtherModelDetails( MdlFile file, bool _ ) + private static bool DrawOtherModelDetails(MdlFile file, bool _) { - if( !ImGui.CollapsingHeader( "Further Content" ) ) - { + if (!ImGui.CollapsingHeader("Further Content")) return false; - } - using( var table = ImRaii.Table( "##data", 2, ImGuiTableFlags.SizingFixedFit ) ) + using (var table = ImRaii.Table("##data", 2, ImGuiTableFlags.SizingFixedFit)) { - if( table ) + if (table) { - ImGuiUtil.DrawTableColumn( "Version" ); - ImGuiUtil.DrawTableColumn( file.Version.ToString() ); - ImGuiUtil.DrawTableColumn( "Radius" ); - ImGuiUtil.DrawTableColumn( file.Radius.ToString( CultureInfo.InvariantCulture ) ); - ImGuiUtil.DrawTableColumn( "Model Clip Out Distance" ); - ImGuiUtil.DrawTableColumn( file.ModelClipOutDistance.ToString( CultureInfo.InvariantCulture ) ); - ImGuiUtil.DrawTableColumn( "Shadow Clip Out Distance" ); - ImGuiUtil.DrawTableColumn( file.ShadowClipOutDistance.ToString( CultureInfo.InvariantCulture ) ); - ImGuiUtil.DrawTableColumn( "LOD Count" ); - ImGuiUtil.DrawTableColumn( file.LodCount.ToString() ); - ImGuiUtil.DrawTableColumn( "Enable Index Buffer Streaming" ); - ImGuiUtil.DrawTableColumn( file.EnableIndexBufferStreaming.ToString() ); - ImGuiUtil.DrawTableColumn( "Enable Edge Geometry" ); - ImGuiUtil.DrawTableColumn( file.EnableEdgeGeometry.ToString() ); - ImGuiUtil.DrawTableColumn( "Flags 1" ); - ImGuiUtil.DrawTableColumn( file.Flags1.ToString() ); - ImGuiUtil.DrawTableColumn( "Flags 2" ); - ImGuiUtil.DrawTableColumn( file.Flags2.ToString() ); - ImGuiUtil.DrawTableColumn( "Vertex Declarations" ); - ImGuiUtil.DrawTableColumn( file.VertexDeclarations.Length.ToString() ); - ImGuiUtil.DrawTableColumn( "Bone Bounding Boxes" ); - ImGuiUtil.DrawTableColumn( file.BoneBoundingBoxes.Length.ToString() ); - ImGuiUtil.DrawTableColumn( "Bone Tables" ); - ImGuiUtil.DrawTableColumn( file.BoneTables.Length.ToString() ); - ImGuiUtil.DrawTableColumn( "Element IDs" ); - ImGuiUtil.DrawTableColumn( file.ElementIds.Length.ToString() ); - ImGuiUtil.DrawTableColumn( "Extra LoDs" ); - ImGuiUtil.DrawTableColumn( file.ExtraLods.Length.ToString() ); - ImGuiUtil.DrawTableColumn( "Meshes" ); - ImGuiUtil.DrawTableColumn( file.Meshes.Length.ToString() ); - ImGuiUtil.DrawTableColumn( "Shape Meshes" ); - ImGuiUtil.DrawTableColumn( file.ShapeMeshes.Length.ToString() ); - ImGuiUtil.DrawTableColumn( "LoDs" ); - ImGuiUtil.DrawTableColumn( file.Lods.Length.ToString() ); - ImGuiUtil.DrawTableColumn( "Vertex Declarations" ); - ImGuiUtil.DrawTableColumn( file.VertexDeclarations.Length.ToString() ); - ImGuiUtil.DrawTableColumn( "Stack Size" ); - ImGuiUtil.DrawTableColumn( file.StackSize.ToString() ); + ImGuiUtil.DrawTableColumn("Version"); + ImGuiUtil.DrawTableColumn(file.Version.ToString()); + ImGuiUtil.DrawTableColumn("Radius"); + ImGuiUtil.DrawTableColumn(file.Radius.ToString(CultureInfo.InvariantCulture)); + ImGuiUtil.DrawTableColumn("Model Clip Out Distance"); + ImGuiUtil.DrawTableColumn(file.ModelClipOutDistance.ToString(CultureInfo.InvariantCulture)); + ImGuiUtil.DrawTableColumn("Shadow Clip Out Distance"); + ImGuiUtil.DrawTableColumn(file.ShadowClipOutDistance.ToString(CultureInfo.InvariantCulture)); + ImGuiUtil.DrawTableColumn("LOD Count"); + ImGuiUtil.DrawTableColumn(file.LodCount.ToString()); + ImGuiUtil.DrawTableColumn("Enable Index Buffer Streaming"); + ImGuiUtil.DrawTableColumn(file.EnableIndexBufferStreaming.ToString()); + ImGuiUtil.DrawTableColumn("Enable Edge Geometry"); + ImGuiUtil.DrawTableColumn(file.EnableEdgeGeometry.ToString()); + ImGuiUtil.DrawTableColumn("Flags 1"); + ImGuiUtil.DrawTableColumn(file.Flags1.ToString()); + ImGuiUtil.DrawTableColumn("Flags 2"); + ImGuiUtil.DrawTableColumn(file.Flags2.ToString()); + ImGuiUtil.DrawTableColumn("Vertex Declarations"); + ImGuiUtil.DrawTableColumn(file.VertexDeclarations.Length.ToString()); + ImGuiUtil.DrawTableColumn("Bone Bounding Boxes"); + ImGuiUtil.DrawTableColumn(file.BoneBoundingBoxes.Length.ToString()); + ImGuiUtil.DrawTableColumn("Bone Tables"); + ImGuiUtil.DrawTableColumn(file.BoneTables.Length.ToString()); + ImGuiUtil.DrawTableColumn("Element IDs"); + ImGuiUtil.DrawTableColumn(file.ElementIds.Length.ToString()); + ImGuiUtil.DrawTableColumn("Extra LoDs"); + ImGuiUtil.DrawTableColumn(file.ExtraLods.Length.ToString()); + ImGuiUtil.DrawTableColumn("Meshes"); + ImGuiUtil.DrawTableColumn(file.Meshes.Length.ToString()); + ImGuiUtil.DrawTableColumn("Shape Meshes"); + ImGuiUtil.DrawTableColumn(file.ShapeMeshes.Length.ToString()); + ImGuiUtil.DrawTableColumn("LoDs"); + ImGuiUtil.DrawTableColumn(file.Lods.Length.ToString()); + ImGuiUtil.DrawTableColumn("Vertex Declarations"); + ImGuiUtil.DrawTableColumn(file.VertexDeclarations.Length.ToString()); + ImGuiUtil.DrawTableColumn("Stack Size"); + ImGuiUtil.DrawTableColumn(file.StackSize.ToString()); } } - using( var attributes = ImRaii.TreeNode( "Attributes", ImGuiTreeNodeFlags.DefaultOpen ) ) + using (var attributes = ImRaii.TreeNode("Attributes", ImGuiTreeNodeFlags.DefaultOpen)) { - if( attributes ) - { - foreach( var attribute in file.Attributes ) - { - ImRaii.TreeNode( attribute, ImGuiTreeNodeFlags.Leaf ).Dispose(); - } - } + if (attributes) + foreach (var attribute in file.Attributes) + ImRaii.TreeNode(attribute, ImGuiTreeNodeFlags.Leaf).Dispose(); } - using( var bones = ImRaii.TreeNode( "Bones", ImGuiTreeNodeFlags.DefaultOpen ) ) + using (var bones = ImRaii.TreeNode("Bones", ImGuiTreeNodeFlags.DefaultOpen)) { - if( bones ) - { - foreach( var bone in file.Bones ) - { - ImRaii.TreeNode( bone, ImGuiTreeNodeFlags.Leaf ).Dispose(); - } - } + if (bones) + foreach (var bone in file.Bones) + ImRaii.TreeNode(bone, ImGuiTreeNodeFlags.Leaf).Dispose(); } - using( var shapes = ImRaii.TreeNode( "Shapes", ImGuiTreeNodeFlags.DefaultOpen ) ) + using (var shapes = ImRaii.TreeNode("Shapes", ImGuiTreeNodeFlags.DefaultOpen)) { - if( shapes ) - { - foreach( var shape in file.Shapes ) - { - ImRaii.TreeNode( shape.ShapeName, ImGuiTreeNodeFlags.Leaf ).Dispose(); - } - } + if (shapes) + foreach (var shape in file.Shapes) + ImRaii.TreeNode(shape.ShapeName, ImGuiTreeNodeFlags.Leaf).Dispose(); } - if( file.RemainingData.Length > 0 ) + if (file.RemainingData.Length > 0) { - using var t = ImRaii.TreeNode( $"Additional Data (Size: {file.RemainingData.Length})###AdditionalData" ); - if( t ) - { - ImGuiUtil.TextWrapped( string.Join( ' ', file.RemainingData.Select( c => $"{c:X2}" ) ) ); - } + using var t = ImRaii.TreeNode($"Additional Data (Size: {file.RemainingData.Length})###AdditionalData"); + if (t) + ImGuiUtil.TextWrapped(string.Join(' ', file.RemainingData.Select(c => $"{c:X2}"))); } return false; } - -} \ No newline at end of file +} diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.QuickImport.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.QuickImport.cs index 43a1990e..2f64f82a 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.QuickImport.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.QuickImport.cs @@ -7,6 +7,7 @@ using Penumbra.GameData.Files; using Penumbra.Interop.ResourceTree; using Penumbra.Mods; using Penumbra.Mods.Editor; +using Penumbra.Mods.Subclasses; using Penumbra.String.Classes; namespace Penumbra.UI.AdvancedWindow; diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.ShaderPackages.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.ShaderPackages.cs index fb2b5128..e475f47f 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.ShaderPackages.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.ShaderPackages.cs @@ -489,16 +489,22 @@ public partial class ModEditWindow continue; foreach (var (key, keyIdx) in node.SystemKeys.WithIndex()) + { ImRaii.TreeNode($"System Key 0x{tab.Shpk.SystemKeys[keyIdx].Id:X8} = 0x{key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); + } foreach (var (key, keyIdx) in node.SceneKeys.WithIndex()) + { ImRaii.TreeNode($"Scene Key 0x{tab.Shpk.SceneKeys[keyIdx].Id:X8} = 0x{key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); + } foreach (var (key, keyIdx) in node.MaterialKeys.WithIndex()) + { ImRaii.TreeNode($"Material Key 0x{tab.Shpk.MaterialKeys[keyIdx].Id:X8} = 0x{key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); + } foreach (var (key, keyIdx) in node.SubViewKeys.WithIndex()) ImRaii.TreeNode($"Sub-View Key #{keyIdx} = 0x{key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); @@ -530,8 +536,10 @@ public partial class ModEditWindow { using var font = ImRaii.PushFont(UiBuilder.MonoFont); foreach (var selector in tab.Shpk.NodeSelectors) + { ImRaii.TreeNode($"#{selector.Value:D4}: Selector: 0x{selector.Key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet) .Dispose(); + } } } diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.ShpkTab.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.ShpkTab.cs index 58e2e0c1..7f14165c 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.ShpkTab.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.ShpkTab.cs @@ -34,7 +34,7 @@ public partial class ModEditWindow Shpk = new ShpkFile(bytes, false); } - Header = $"Shader Package for DirectX {(int)Shpk.DirectXVersion}"; + Header = $"Shader Package for DirectX {(int)Shpk.DirectXVersion}"; Extension = Shpk.DirectXVersion switch { ShpkFile.DxVersion.DirectX9 => ".cso", diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Textures.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Textures.cs index 20aea21e..1ee0a128 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Textures.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Textures.cs @@ -193,17 +193,18 @@ public partial class ModEditWindow private void OpenSaveAsDialog(string defaultExtension) { var fileName = Path.GetFileNameWithoutExtension(_left.Path.Length > 0 ? _left.Path : _right.Path); - _fileDialog.OpenSavePicker("Save Texture as TEX, DDS or PNG...", "Textures{.png,.dds,.tex},.tex,.dds,.png", fileName, defaultExtension, (a, b) => - { - if (a) + _fileDialog.OpenSavePicker("Save Texture as TEX, DDS or PNG...", "Textures{.png,.dds,.tex},.tex,.dds,.png", fileName, defaultExtension, + (a, b) => { - _center.SaveAs(null, _textures, b, (CombinedTexture.TextureSaveType)_currentSaveAs, _addMipMaps); - if (b == _left.Path) - AddReloadTask(_left.Path, false); - else if (b == _right.Path) - AddReloadTask(_right.Path, true); - } - }, _mod!.ModPath.FullName, _forceTextureStartPath); + if (a) + { + _center.SaveAs(null, _textures, b, (CombinedTexture.TextureSaveType)_currentSaveAs, _addMipMaps); + if (b == _left.Path) + AddReloadTask(_left.Path, false); + else if (b == _right.Path) + AddReloadTask(_right.Path, true); + } + }, _mod!.ModPath.FullName, _forceTextureStartPath); _forceTextureStartPath = false; } diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.cs index 703329e6..745b412b 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.cs @@ -6,7 +6,6 @@ using Dalamud.Interface.Windowing; using Dalamud.Plugin.Services; using ImGuiNET; using OtterGui; -using OtterGui.Compression; using OtterGui.Raii; using Penumbra.Collections.Manager; using Penumbra.Communication; @@ -19,6 +18,7 @@ using Penumbra.Meta; using Penumbra.Mods; using Penumbra.Mods.Editor; using Penumbra.Mods.Manager; +using Penumbra.Mods.Subclasses; using Penumbra.Services; using Penumbra.String; using Penumbra.String.Classes; diff --git a/Penumbra/UI/AdvancedWindow/ModMergeTab.cs b/Penumbra/UI/AdvancedWindow/ModMergeTab.cs index 75f75de0..60247d81 100644 --- a/Penumbra/UI/AdvancedWindow/ModMergeTab.cs +++ b/Penumbra/UI/AdvancedWindow/ModMergeTab.cs @@ -2,9 +2,9 @@ using Dalamud.Interface; using ImGuiNET; using OtterGui; using OtterGui.Raii; -using Penumbra.Mods; using Penumbra.Mods.Editor; using Penumbra.Mods.Manager; +using Penumbra.Mods.Subclasses; using Penumbra.UI.Classes; namespace Penumbra.UI.AdvancedWindow; diff --git a/Penumbra/UI/AdvancedWindow/ResourceTreeViewer.cs b/Penumbra/UI/AdvancedWindow/ResourceTreeViewer.cs index f435cb98..5f09e584 100644 --- a/Penumbra/UI/AdvancedWindow/ResourceTreeViewer.cs +++ b/Penumbra/UI/AdvancedWindow/ResourceTreeViewer.cs @@ -10,20 +10,20 @@ namespace Penumbra.UI.AdvancedWindow; public class ResourceTreeViewer { private readonly Configuration _config; - private readonly ResourceTreeFactory _treeFactory; + private readonly ResourceTreeFactory _treeFactory; private readonly ChangedItemDrawer _changedItemDrawer; private readonly int _actionCapacity; private readonly Action _onRefresh; private readonly Action _drawActions; private readonly HashSet _unfolded; - private Task? _task; + private Task? _task; - public ResourceTreeViewer(Configuration config, ResourceTreeFactory treeFactory, ChangedItemDrawer changedItemDrawer, + public ResourceTreeViewer(Configuration config, ResourceTreeFactory treeFactory, ChangedItemDrawer changedItemDrawer, int actionCapacity, Action onRefresh, Action drawActions) { _config = config; - _treeFactory = treeFactory; + _treeFactory = treeFactory; _changedItemDrawer = changedItemDrawer; _actionCapacity = actionCapacity; _onRefresh = onRefresh; @@ -87,7 +87,7 @@ public class ResourceTreeViewer private Task RefreshCharacterList() => Task.Run(() => - { + { try { return _treeFactory.FromObjectTable(); @@ -107,38 +107,39 @@ public class ResourceTreeViewer foreach (var (resourceNode, index) in resourceNodes.WithIndex()) { if (resourceNode.Internal && !debugMode) - continue; - - var textColor = ImGui.GetColorU32(ImGuiCol.Text); - var textColorInternal = (textColor & 0x00FFFFFFu) | ((textColor & 0xFE000000u) >> 1); // Half opacity - - using var mutedColor = ImRaii.PushColor(ImGuiCol.Text, textColorInternal, resourceNode.Internal); - + continue; + + var textColor = ImGui.GetColorU32(ImGuiCol.Text); + var textColorInternal = (textColor & 0x00FFFFFFu) | ((textColor & 0xFE000000u) >> 1); // Half opacity + + using var mutedColor = ImRaii.PushColor(ImGuiCol.Text, textColorInternal, resourceNode.Internal); + var nodePathHash = unchecked(pathHash + resourceNode.ResourceHandle); using var id = ImRaii.PushId(index); ImGui.TableNextColumn(); var unfolded = _unfolded.Contains(nodePathHash); using (var indent = ImRaii.PushIndent(level)) - { - var unfoldable = debugMode - ? resourceNode.Children.Count > 0 - : resourceNode.Children.Any(child => !child.Internal); - if (unfoldable) - { - using var font = ImRaii.PushFont(UiBuilder.IconFont); - var icon = (unfolded ? FontAwesomeIcon.CaretDown : FontAwesomeIcon.CaretRight).ToIconString(); - var offset = (ImGui.GetFrameHeight() - ImGui.CalcTextSize(icon).X) / 2; - ImGui.SetCursorPosX(ImGui.GetCursorPosX() + offset); - ImGui.TextUnformatted(icon); - ImGui.SameLine(0f, offset + ImGui.GetStyle().ItemInnerSpacing.X); - } - else - { - ImGui.Dummy(new Vector2(ImGui.GetFrameHeight())); - ImGui.SameLine(0f, ImGui.GetStyle().ItemInnerSpacing.X); - } - _changedItemDrawer.DrawCategoryIcon(resourceNode.Icon); + { + var unfoldable = debugMode + ? resourceNode.Children.Count > 0 + : resourceNode.Children.Any(child => !child.Internal); + if (unfoldable) + { + using var font = ImRaii.PushFont(UiBuilder.IconFont); + var icon = (unfolded ? FontAwesomeIcon.CaretDown : FontAwesomeIcon.CaretRight).ToIconString(); + var offset = (ImGui.GetFrameHeight() - ImGui.CalcTextSize(icon).X) / 2; + ImGui.SetCursorPosX(ImGui.GetCursorPosX() + offset); + ImGui.TextUnformatted(icon); + ImGui.SameLine(0f, offset + ImGui.GetStyle().ItemInnerSpacing.X); + } + else + { + ImGui.Dummy(new Vector2(ImGui.GetFrameHeight())); + ImGui.SameLine(0f, ImGui.GetStyle().ItemInnerSpacing.X); + } + + _changedItemDrawer.DrawCategoryIcon(resourceNode.Icon); ImGui.SameLine(0f, ImGui.GetStyle().ItemInnerSpacing.X); ImGui.TableHeader(resourceNode.Name); if (ImGui.IsItemClicked() && unfoldable) @@ -150,11 +151,11 @@ public class ResourceTreeViewer unfolded = !unfolded; } - if (debugMode) - { + if (debugMode) + { using var _ = ImRaii.PushFont(UiBuilder.MonoFont); ImGuiUtil.HoverTooltip( - $"Resource Type: {resourceNode.Type}\nObject Address: 0x{resourceNode.ObjectAddress:X16}\nResource Handle: 0x{resourceNode.ResourceHandle:X16}\nLength: 0x{resourceNode.Length:X16}"); + $"Resource Type: {resourceNode.Type}\nObject Address: 0x{resourceNode.ObjectAddress:X16}\nResource Handle: 0x{resourceNode.ResourceHandle:X16}\nLength: 0x{resourceNode.Length:X16}"); } } @@ -187,8 +188,8 @@ public class ResourceTreeViewer ImGui.Selectable("(unavailable)", false, ImGuiSelectableFlags.Disabled, new Vector2(ImGui.GetContentRegionAvail().X, cellHeight)); ImGuiUtil.HoverTooltip("The actual path to this file is unavailable.\nIt may be managed by another plug-in."); - } - + } + mutedColor.Dispose(); if (_actionCapacity > 0) diff --git a/Penumbra/UI/Changelog.cs b/Penumbra/UI/Changelog.cs index d7845ab7..ed62bf83 100644 --- a/Penumbra/UI/Changelog.cs +++ b/Penumbra/UI/Changelog.cs @@ -4,7 +4,7 @@ namespace Penumbra.UI; public class PenumbraChangelog { - public const int LastChangelogVersion = 0; + public const int LastChangelogVersion = 0; private readonly Configuration _config; public readonly Changelog Changelog; @@ -41,19 +41,23 @@ public class PenumbraChangelog Add7_1_2(Changelog); Add7_2_0(Changelog); Add7_3_0(Changelog); - } - + } + #region Changelogs private static void Add7_3_0(Changelog log) => log.NextVersion("Version 0.7.3.0") - .RegisterEntry("Added the ability to drag and drop mod files from external sources (like a file explorer or browser) into Penumbras mod selector to import them.") + .RegisterEntry( + "Added the ability to drag and drop mod files from external sources (like a file explorer or browser) into Penumbras mod selector to import them.") .RegisterEntry("You can also drag and drop texture files into the textures tab of the Advanced Editing Window.", 1) - .RegisterEntry("Added a priority display to the mod selector using the currently selected collections priorities. This can be hidden in settings.") + .RegisterEntry( + "Added a priority display to the mod selector using the currently selected collections priorities. This can be hidden in settings.") .RegisterEntry("Added IPC for texture conversion, improved texture handling backend and threading.") - .RegisterEntry("Added Dalamud Substitution so that other plugins can more easily use replaced icons from Penumbras Interface collection when using Dalamuds new Texture Provider.") + .RegisterEntry( + "Added Dalamud Substitution so that other plugins can more easily use replaced icons from Penumbras Interface collection when using Dalamuds new Texture Provider.") .RegisterEntry("Added a filter to texture selection combos in the textures tab of the Advanced Editing Window.") - .RegisterEntry("Changed behaviour when failing to load group JSON files for mods - the pre-existing but failing files are now backed up before being deleted or overwritten.") + .RegisterEntry( + "Changed behaviour when failing to load group JSON files for mods - the pre-existing but failing files are now backed up before being deleted or overwritten.") .RegisterEntry("Further backend changes, mostly relating to the Glamourer rework.") .RegisterEntry("Fixed an issue with modded decals not loading correctly when used with the Glamourer rework.") .RegisterEntry("Fixed missing scaling with UI Scale for some combos.") @@ -66,49 +70,67 @@ public class PenumbraChangelog private static void Add7_2_0(Changelog log) => log.NextVersion("Version 0.7.2.0") - .RegisterEntry("Added Changed Item Categories and icons that can filter for specific types of Changed Items, in the Changed Items Tab as well as in the Changed Items panel for specific mods..") - .RegisterEntry("Icons at the top can be clicked to filter, as well as right-clicked to open a context menu with the option to inverse-filter for them", 1) + .RegisterEntry( + "Added Changed Item Categories and icons that can filter for specific types of Changed Items, in the Changed Items Tab as well as in the Changed Items panel for specific mods..") + .RegisterEntry( + "Icons at the top can be clicked to filter, as well as right-clicked to open a context menu with the option to inverse-filter for them", + 1) .RegisterEntry("There is also an ALL button that can be toggled.", 1) - .RegisterEntry("Modded files in the Font category now resolve from the Interface assignment instead of the base assignment, despite not technically being in the UI category.") - .RegisterEntry("Timeline files will no longer be associated with specific characters in cutscenes, since there is no way to correctly do this, and it could cause crashes if IVCS-requiring animations were used on characters without IVCS.") + .RegisterEntry( + "Modded files in the Font category now resolve from the Interface assignment instead of the base assignment, despite not technically being in the UI category.") + .RegisterEntry( + "Timeline files will no longer be associated with specific characters in cutscenes, since there is no way to correctly do this, and it could cause crashes if IVCS-requiring animations were used on characters without IVCS.") .RegisterEntry("File deletion in the Advanced Editing Window now also checks for your configured deletion key combo.") - .RegisterEntry("The Texture tab in the Advanced Editing Window now has some quick convert buttons to just convert the selected texture to a different format in-place.") - .RegisterEntry("These buttons only appear if only one texture is selected on the left side, it is not otherwise manipulated, and the texture is a .tex file.", 1) + .RegisterEntry( + "The Texture tab in the Advanced Editing Window now has some quick convert buttons to just convert the selected texture to a different format in-place.") + .RegisterEntry( + "These buttons only appear if only one texture is selected on the left side, it is not otherwise manipulated, and the texture is a .tex file.", + 1) .RegisterEntry("The text part of the mod filter in the mod selector now also resets when right-clicking the drop-down arrow.") .RegisterEntry("The Dissolve Folder option in the mod selector context menu has been moved to the bottom.") .RegisterEntry("Somewhat improved IMC handling to prevent some issues.") - .RegisterEntry("Improved the handling of mod renames on mods with default-search names to correctly rename their search-name in (hopefully) all cases too.") + .RegisterEntry( + "Improved the handling of mod renames on mods with default-search names to correctly rename their search-name in (hopefully) all cases too.") .RegisterEntry("A lot of backend improvements and changes related to the pending Glamourer rework.") .RegisterEntry("Fixed an issue where the displayed active collection count in the support info was wrong.") - .RegisterEntry("Fixed an issue with created directories dealing badly with non-standard whitespace characters like half-width or non-breaking spaces.") + .RegisterEntry( + "Fixed an issue with created directories dealing badly with non-standard whitespace characters like half-width or non-breaking spaces.") .RegisterEntry("Fixed an issue with unknown animation and vfx edits not being recognized correctly.") .RegisterEntry("Fixed an issue where changing option descriptions to be empty was not working correctly.") .RegisterEntry("Fixed an issue with texture names in the resource tree of the On-Screen views.") .RegisterEntry("Fixed a bug where the game would crash when drawing folders in the mod selector that contained a '%' symbol.") .RegisterEntry("Fixed an issue with parallel algorithms obtaining the wrong number of available cores.") .RegisterEntry("Updated the available selection of Battle NPC names.") - .RegisterEntry("A typo in the 0.7.1.2 Changlog has been fixed.") - .RegisterEntry("Added the Sea of Stars as accepted repository. (0.7.1.4)") - .RegisterEntry("Fixed an issue with collections sometimes not loading correctly, and IMC files not applying correctly. (0.7.1.3)"); - - + .RegisterEntry("A typo in the 0.7.1.2 Changlog has been fixed.") + .RegisterEntry("Added the Sea of Stars as accepted repository. (0.7.1.4)") + .RegisterEntry("Fixed an issue with collections sometimes not loading correctly, and IMC files not applying correctly. (0.7.1.3)"); + + private static void Add7_1_2(Changelog log) => log.NextVersion("Version 0.7.1.2") - .RegisterEntry("Changed threaded handling of collection caches. Maybe this fixes the startup problems some people are experiencing.") - .RegisterEntry("This is just testing and may not be the solution, or may even make things worse. Sorry if I have to put out multiple small patches again to get this right.", 1) + .RegisterEntry( + "Changed threaded handling of collection caches. Maybe this fixes the startup problems some people are experiencing.") + .RegisterEntry( + "This is just testing and may not be the solution, or may even make things worse. Sorry if I have to put out multiple small patches again to get this right.", + 1) .RegisterEntry("Fixed Penumbra failing to load if the main configuration file is corrupted.") .RegisterEntry("Some miscellaneous small bug fixes.") .RegisterEntry("Slight changes in behaviour for deduplicator/normalizer, mostly backend.") .RegisterEntry("A typo in the 0.7.1.0 Changelog has been fixed.") .RegisterEntry("Fixed left rings not being valid for IMC entries after validation. (7.1.1)") - .RegisterEntry("Relaxed the scaling restrictions for RSP scaling values to go from 0.01 to 512.0 instead of the prior upper limit of 8.0, in interface as well as validation, to better support the fetish community. (7.1.1)"); + .RegisterEntry( + "Relaxed the scaling restrictions for RSP scaling values to go from 0.01 to 512.0 instead of the prior upper limit of 8.0, in interface as well as validation, to better support the fetish community. (7.1.1)"); private static void Add7_1_0(Changelog log) => log.NextVersion("Version 0.7.1.0") .RegisterEntry("Updated for patch 6.4 - there may be some oversights on edge cases, but I could not find any issues myself.") - .RegisterHighlight("This update changed some Dragoon skills that were moving the player character before to not do that anymore. If you have any mods that applied to those skills, please make sure that they do not contain any redirections for .tmb files. If skills that should no longer move your character still do that for some reason, this is detectable by the server.", 1) - .RegisterEntry("Added a Mod Merging tab in the Advanced Editing Window. This can help you merge multiple mods to one, or split off specific options from an existing mod into a new mod.") - .RegisterEntry("Added advanced options to configure the minimum allowed window size for the main window (to reduce it). This is not quite supported and may look bad, so only use it if you really need smaller windows.") + .RegisterHighlight( + "This update changed some Dragoon skills that were moving the player character before to not do that anymore. If you have any mods that applied to those skills, please make sure that they do not contain any redirections for .tmb files. If skills that should no longer move your character still do that for some reason, this is detectable by the server.", + 1) + .RegisterEntry( + "Added a Mod Merging tab in the Advanced Editing Window. This can help you merge multiple mods to one, or split off specific options from an existing mod into a new mod.") + .RegisterEntry( + "Added advanced options to configure the minimum allowed window size for the main window (to reduce it). This is not quite supported and may look bad, so only use it if you really need smaller windows.") .RegisterEntry("The last tab selected in the main window is now saved and re-used when relaunching Penumbra.") .RegisterEntry("Added a hook to correctly associate some sounds that are played while weapons are drawn.") .RegisterEntry("Added a hook to correctly associate sounds that are played while dismounting.") @@ -125,7 +147,8 @@ public class PenumbraChangelog .RegisterEntry("Fixed an issue with the file selectors not always opening at the expected locations. (0.7.0.7)") .RegisterEntry("Fixed some cache handling issues. (0.7.0.5 - 0.7.0.10)") .RegisterEntry("Fixed an issue with multiple collection context menus appearing for some identifiers (0.7.0.5)") - .RegisterEntry("Fixed an issue where the Update Bibo button did only work if the Advanced Editing window was opened before. (0.7.0.5)"); + .RegisterEntry( + "Fixed an issue where the Update Bibo button did only work if the Advanced Editing window was opened before. (0.7.0.5)"); private static void Add7_0_4(Changelog log) => log.NextVersion("Version 0.7.0.4") @@ -136,7 +159,7 @@ public class PenumbraChangelog .RegisterEntry("Reverted trimming of whitespace for relative paths to only trim the end, not the start. (0.7.0.3)") .RegisterEntry("Fixed a bug that caused an integer overflow on textures of high dimensions. (0.7.0.3)") .RegisterEntry("Fixed a bug that caused Penumbra to enter invalid state when deleting mods. (0.7.0.2)") - .RegisterEntry("Added Notification on invalid collection names. (0.7.0.2)"); + .RegisterEntry("Added Notification on invalid collection names. (0.7.0.2)"); private static void Add7_0_1(Changelog log) => log.NextVersion("Version 0.7.0.1") @@ -145,26 +168,36 @@ public class PenumbraChangelog .RegisterEntry("Fixed a bug that showed the Your Character collection as redundant even if it was not.") .RegisterEntry("Fixed a bug that caused some required collection caches to not be built on startup and thus mods not to apply.") .RegisterEntry("Fixed a bug that showed the current collection as unused even if it was used."); + private static void Add7_0_0(Changelog log) => log.NextVersion("Version 0.7.0.0") - .RegisterHighlight("The entire backend was reworked (this is still in progress). While this does not come with a lot of functionality changes, basically every file and functionality was touched.") - .RegisterEntry("This may have (re-)introduced some bugs that have not yet been noticed despite a long testing period - there are not many users of the testing branch.", 1) + .RegisterHighlight( + "The entire backend was reworked (this is still in progress). While this does not come with a lot of functionality changes, basically every file and functionality was touched.") + .RegisterEntry( + "This may have (re-)introduced some bugs that have not yet been noticed despite a long testing period - there are not many users of the testing branch.", + 1) .RegisterEntry("If you encounter any - but especially breaking or lossy - bugs, please report them immediately.", 1) - .RegisterEntry("This also fixed or improved numerous bugs and issues that will not be listed here.", 1) - .RegisterEntry("GitHub currently reports 321 changed files with 34541 additions and 28464 deletions.", 1) + .RegisterEntry("This also fixed or improved numerous bugs and issues that will not be listed here.", 1) + .RegisterEntry("GitHub currently reports 321 changed files with 34541 additions and 28464 deletions.", 1) .RegisterEntry("Added Notifications on many failures that previously only wrote to log.") .RegisterEntry("Reworked the Collections Tab to hopefully be much more intuitive. It should be self-explanatory now.") .RegisterEntry("The tutorial was adapted to the new window, if you are unsure, maybe try restarting it.", 1) - .RegisterEntry("You can now toggle an incognito mode in the collection window so it shows shortened names of collections and players.", 1) - .RegisterEntry("You can get an overview about the current usage of a selected collection and its active and unused mod settings in the Collection Details panel.", 1) + .RegisterEntry( + "You can now toggle an incognito mode in the collection window so it shows shortened names of collections and players.", 1) + .RegisterEntry( + "You can get an overview about the current usage of a selected collection and its active and unused mod settings in the Collection Details panel.", + 1) .RegisterEntry("The currently selected collection is now highlighted in green (default, configurable) in multiple places.", 1) - .RegisterEntry("Mods now have a 'Collections' panel in the Mod Panel containing an overview about usage of the mod in all collections.") + .RegisterEntry( + "Mods now have a 'Collections' panel in the Mod Panel containing an overview about usage of the mod in all collections.") .RegisterEntry("The 'Changed Items' and 'Effective Changes' tab now contain a collection selector.") .RegisterEntry("Added the On-Screen tab to find what files a specific character is actually using (by Ny).") .RegisterEntry("Added 3 Quick Move folders in the mod selector that can be setup in context menus for easier cleanup.") - .RegisterEntry("Added handling for certain animation files for mounts and fashion accessories to correctly associate them to players.") + .RegisterEntry( + "Added handling for certain animation files for mounts and fashion accessories to correctly associate them to players.") .RegisterEntry("The file selectors in the Advanced Mod Editing Window now use filterable combos.") - .RegisterEntry("The Advanced Mod Editing Window now shows the number of meta edits and file swaps in unselected options and highlights the option selector.") + .RegisterEntry( + "The Advanced Mod Editing Window now shows the number of meta edits and file swaps in unselected options and highlights the option selector.") .RegisterEntry("Added API/IPC to start unpacking and installing mods from external tools (by Sebastina).") .RegisterEntry("Hidden files and folders are now ignored for unused files in Advanced Mod Editing (by myr)") .RegisterEntry("Paths in mods are now automatically trimmed of whitespace on loading.") @@ -173,13 +206,13 @@ public class PenumbraChangelog .RegisterEntry("Fixed some issues with tutorial windows.") .RegisterEntry("Fixed some bugs in the Resource Logger.") .RegisterEntry("Fixed Button Sizing for collapsible groups and several related bugs.") - .RegisterEntry("Fixed issue with mods with default settings other than 0.") - .RegisterEntry("Fixed issue with commands not registering on startup. (0.6.6.5)") - .RegisterEntry("Improved Startup Times and Time Tracking. (0.6.6.4)") - .RegisterEntry("Add Item Swapping between different types of Accessories and Hats. (0.6.6.4)") - .RegisterEntry("Fixed bugs with assignment of temporary collections and their deletion. (0.6.6.4)") - .RegisterEntry("Fixed bugs with new file loading mechanism. (0.6.6.2, 0.6.6.3)") - .RegisterEntry("Added API/IPC to open and close the main window and select specific tabs and mods. (0.6.6.2)"); + .RegisterEntry("Fixed issue with mods with default settings other than 0.") + .RegisterEntry("Fixed issue with commands not registering on startup. (0.6.6.5)") + .RegisterEntry("Improved Startup Times and Time Tracking. (0.6.6.4)") + .RegisterEntry("Add Item Swapping between different types of Accessories and Hats. (0.6.6.4)") + .RegisterEntry("Fixed bugs with assignment of temporary collections and their deletion. (0.6.6.4)") + .RegisterEntry("Fixed bugs with new file loading mechanism. (0.6.6.2, 0.6.6.3)") + .RegisterEntry("Added API/IPC to open and close the main window and select specific tabs and mods. (0.6.6.2)"); private static void Add6_6_1(Changelog log) => log.NextVersion("Version 0.6.6.1") diff --git a/Penumbra/UI/Classes/Colors.cs b/Penumbra/UI/Classes/Colors.cs index eb4dec4c..ebcff821 100644 --- a/Penumbra/UI/Classes/Colors.cs +++ b/Penumbra/UI/Classes/Colors.cs @@ -17,12 +17,12 @@ public enum ColorId FolderLine, ItemId, IncreasedMetaValue, - DecreasedMetaValue, - SelectedCollection, - RedundantAssignment, - NoModsAssignment, - NoAssignment, - SelectorPriority, + DecreasedMetaValue, + SelectedCollection, + RedundantAssignment, + NoModsAssignment, + NoAssignment, + SelectorPriority, InGameHighlight, } @@ -38,7 +38,7 @@ public static class Colors public const uint TutorialBorder = 0xD00000FF; public const uint ReniColorButton = CustomGui.ReniColorButton; public const uint ReniColorHovered = CustomGui.ReniColorHovered; - public const uint ReniColorActive = CustomGui.ReniColorActive ; + public const uint ReniColorActive = CustomGui.ReniColorActive; public static (uint DefaultColor, string Name, string Description) Data(this ColorId color) => color switch @@ -69,12 +69,12 @@ public static class Colors }; private static IReadOnlyDictionary _colors = new Dictionary(); - - /// Obtain the configured value for a color. + + /// Obtain the configured value for a color. public static uint Value(this ColorId color) => _colors.TryGetValue(color, out var value) ? value : color.Data().DefaultColor; - - /// Set the configurable colors dictionary to a value. + + /// Set the configurable colors dictionary to a value. public static void SetColors(Configuration config) => _colors = config.Colors; } diff --git a/Penumbra/UI/Classes/Combos.cs b/Penumbra/UI/Classes/Combos.cs index 26f747b7..2cba7cf5 100644 --- a/Penumbra/UI/Classes/Combos.cs +++ b/Penumbra/UI/Classes/Combos.cs @@ -8,38 +8,41 @@ namespace Penumbra.UI.Classes; public static class Combos { // Different combos to use with enums. - public static bool Race( string label, ModelRace current, out ModelRace race ) - => Race( label, 100, current, out race ); + public static bool Race(string label, ModelRace current, out ModelRace race) + => Race(label, 100, current, out race); - public static bool Race( string label, float unscaledWidth, ModelRace current, out ModelRace race ) - => ImGuiUtil.GenericEnumCombo( label, unscaledWidth * UiHelpers.Scale, current, out race, RaceEnumExtensions.ToName, 1 ); + public static bool Race(string label, float unscaledWidth, ModelRace current, out ModelRace race) + => ImGuiUtil.GenericEnumCombo(label, unscaledWidth * UiHelpers.Scale, current, out race, RaceEnumExtensions.ToName, 1); - public static bool Gender( string label, Gender current, out Gender gender ) - => Gender( label, 120, current, out gender ); + public static bool Gender(string label, Gender current, out Gender gender) + => Gender(label, 120, current, out gender); - public static bool Gender( string label, float unscaledWidth, Gender current, out Gender gender ) - => ImGuiUtil.GenericEnumCombo( label, unscaledWidth * UiHelpers.Scale, current, out gender, RaceEnumExtensions.ToName, 1 ); + public static bool Gender(string label, float unscaledWidth, Gender current, out Gender gender) + => ImGuiUtil.GenericEnumCombo(label, unscaledWidth * UiHelpers.Scale, current, out gender, RaceEnumExtensions.ToName, 1); - public static bool EqdpEquipSlot( string label, EquipSlot current, out EquipSlot slot ) - => ImGuiUtil.GenericEnumCombo( label, 100 * UiHelpers.Scale, current, out slot, EquipSlotExtensions.EqdpSlots, EquipSlotExtensions.ToName ); + public static bool EqdpEquipSlot(string label, EquipSlot current, out EquipSlot slot) + => ImGuiUtil.GenericEnumCombo(label, 100 * UiHelpers.Scale, current, out slot, EquipSlotExtensions.EqdpSlots, + EquipSlotExtensions.ToName); - public static bool EqpEquipSlot( string label, float width, EquipSlot current, out EquipSlot slot ) - => ImGuiUtil.GenericEnumCombo( label, width * UiHelpers.Scale, current, out slot, EquipSlotExtensions.EquipmentSlots, EquipSlotExtensions.ToName ); + public static bool EqpEquipSlot(string label, float width, EquipSlot current, out EquipSlot slot) + => ImGuiUtil.GenericEnumCombo(label, width * UiHelpers.Scale, current, out slot, EquipSlotExtensions.EquipmentSlots, + EquipSlotExtensions.ToName); - public static bool AccessorySlot( string label, EquipSlot current, out EquipSlot slot ) - => ImGuiUtil.GenericEnumCombo( label, 100 * UiHelpers.Scale, current, out slot, EquipSlotExtensions.AccessorySlots, EquipSlotExtensions.ToName ); + public static bool AccessorySlot(string label, EquipSlot current, out EquipSlot slot) + => ImGuiUtil.GenericEnumCombo(label, 100 * UiHelpers.Scale, current, out slot, EquipSlotExtensions.AccessorySlots, + EquipSlotExtensions.ToName); - public static bool SubRace( string label, SubRace current, out SubRace subRace ) - => ImGuiUtil.GenericEnumCombo( label, 150 * UiHelpers.Scale, current, out subRace, RaceEnumExtensions.ToName, 1 ); + public static bool SubRace(string label, SubRace current, out SubRace subRace) + => ImGuiUtil.GenericEnumCombo(label, 150 * UiHelpers.Scale, current, out subRace, RaceEnumExtensions.ToName, 1); - public static bool RspAttribute( string label, RspAttribute current, out RspAttribute attribute ) - => ImGuiUtil.GenericEnumCombo( label, 200 * UiHelpers.Scale, current, out attribute, - RspAttributeExtensions.ToFullString, 0, 1 ); + public static bool RspAttribute(string label, RspAttribute current, out RspAttribute attribute) + => ImGuiUtil.GenericEnumCombo(label, 200 * UiHelpers.Scale, current, out attribute, + RspAttributeExtensions.ToFullString, 0, 1); - public static bool EstSlot( string label, EstManipulation.EstType current, out EstManipulation.EstType attribute ) - => ImGuiUtil.GenericEnumCombo( label, 200 * UiHelpers.Scale, current, out attribute ); + public static bool EstSlot(string label, EstManipulation.EstType current, out EstManipulation.EstType attribute) + => ImGuiUtil.GenericEnumCombo(label, 200 * UiHelpers.Scale, current, out attribute); - public static bool ImcType( string label, ObjectType current, out ObjectType type ) - => ImGuiUtil.GenericEnumCombo( label, 110 * UiHelpers.Scale, current, out type, ObjectTypeExtensions.ValidImcTypes, - ObjectTypeExtensions.ToName ); -} \ No newline at end of file + public static bool ImcType(string label, ObjectType current, out ObjectType type) + => ImGuiUtil.GenericEnumCombo(label, 110 * UiHelpers.Scale, current, out type, ObjectTypeExtensions.ValidImcTypes, + ObjectTypeExtensions.ToName); +} diff --git a/Penumbra/UI/CollectionTab/CollectionPanel.cs b/Penumbra/UI/CollectionTab/CollectionPanel.cs index fe248d99..3ebd3252 100644 --- a/Penumbra/UI/CollectionTab/CollectionPanel.cs +++ b/Penumbra/UI/CollectionTab/CollectionPanel.cs @@ -22,7 +22,7 @@ public sealed class CollectionPanel : IDisposable private readonly ActiveCollections _active; private readonly CollectionSelector _selector; private readonly ActorService _actors; - private readonly ITargetManager _targets; + private readonly ITargetManager _targets; private readonly IndividualAssignmentUi _individualAssignmentUi; private readonly InheritanceUi _inheritanceUi; private readonly ModStorage _mods; diff --git a/Penumbra/UI/CollectionTab/InheritanceUi.cs b/Penumbra/UI/CollectionTab/InheritanceUi.cs index 4bcff426..88344e6a 100644 --- a/Penumbra/UI/CollectionTab/InheritanceUi.cs +++ b/Penumbra/UI/CollectionTab/InheritanceUi.cs @@ -30,23 +30,24 @@ public class InheritanceUi /// Draw the whole inheritance block. public void Draw() { - using var id = ImRaii.PushId("##Inheritance"); - ImGuiUtil.DrawColoredText(($"The {TutorialService.SelectedCollection} ", 0), (Name(_active.Current), ColorId.SelectedCollection.Value() | 0xFF000000), (" inherits from:", 0)); - ImGui.Dummy(Vector2.One); + using var id = ImRaii.PushId("##Inheritance"); + ImGuiUtil.DrawColoredText(($"The {TutorialService.SelectedCollection} ", 0), + (Name(_active.Current), ColorId.SelectedCollection.Value() | 0xFF000000), (" inherits from:", 0)); + ImGui.Dummy(Vector2.One); - DrawCurrentCollectionInheritance(); + DrawCurrentCollectionInheritance(); ImGui.SameLine(); DrawInheritanceTrashButton(); ImGui.SameLine(); - DrawRightText(); + DrawRightText(); DrawNewInheritanceSelection(); ImGui.SameLine(); if (ImGui.Button("More Information about Inheritance", new Vector2(ImGui.GetContentRegionAvail().X, 0))) - ImGui.OpenPopup("InheritanceHelp"); - + ImGui.OpenPopup("InheritanceHelp"); + DrawHelpPopup(); - DelayedActions(); + DelayedActions(); } // Keep for reuse. @@ -56,44 +57,44 @@ public class InheritanceUi private ModCollection? _newInheritance; private ModCollection? _movedInheritance; private (int, int)? _inheritanceAction; - private ModCollection? _newCurrentCollection; - + private ModCollection? _newCurrentCollection; + private void DrawRightText() { using var group = ImRaii.Group(); ImGuiUtil.TextWrapped( "Inheritance is a way to use a baseline of mods across multiple collections, without needing to change all those collections if you want to add a single mod."); ImGuiUtil.TextWrapped( - "You can select inheritances from the combo below to add them.\nSince the order of inheritances is important, you can reorder them here via drag and drop.\nYou can also delete inheritances by dragging them onto the trash can."); - } - - private void DrawHelpPopup() - => ImGuiUtil.HelpPopup("InheritanceHelp", new Vector2(1000 * UiHelpers.Scale, 20 * ImGui.GetTextLineHeightWithSpacing()), () => - { - ImGui.NewLine(); - ImGui.TextUnformatted("Every mod in a collection can have three basic states: 'Enabled', 'Disabled' and 'Unconfigured'."); - ImGui.BulletText("If the mod is 'Enabled' or 'Disabled', it does not matter if the collection inherits from other collections."); - ImGui.BulletText( - "If the mod is unconfigured, those inherited-from collections are checked in the order displayed here, including sub-inheritances."); - ImGui.BulletText( - "If a collection is found in which the mod is either 'Enabled' or 'Disabled', the settings from this collection will be used."); - ImGui.BulletText("If no such collection is found, the mod will be treated as disabled."); - ImGui.BulletText( - "Highlighted collections in the left box are never reached because they are already checked in a sub-inheritance before."); - ImGui.NewLine(); - ImGui.TextUnformatted("Example"); - ImGui.BulletText("Collection A has the Bibo+ body and a Hempen Camise mod enabled."); - ImGui.BulletText( - "Collection B inherits from A, leaves Bibo+ unconfigured, but has the Hempen Camise enabled with different settings than A."); - ImGui.BulletText("Collection C also inherits from A, has Bibo+ explicitly disabled and the Hempen Camise unconfigured."); - ImGui.BulletText("Collection D inherits from C and then B and leaves everything unconfigured."); - using var indent = ImRaii.PushIndent(); - ImGui.BulletText("B uses Bibo+ settings from A and its own Hempen Camise settings."); - ImGui.BulletText("C has Bibo+ disabled and uses A's Hempen Camise settings."); - ImGui.BulletText( - "D has Bibo+ disabled and uses A's Hempen Camise settings, not B's. It traversed the collections in Order D -> (C -> A) -> (B -> A)."); - }); - + "You can select inheritances from the combo below to add them.\nSince the order of inheritances is important, you can reorder them here via drag and drop.\nYou can also delete inheritances by dragging them onto the trash can."); + } + + private void DrawHelpPopup() + => ImGuiUtil.HelpPopup("InheritanceHelp", new Vector2(1000 * UiHelpers.Scale, 20 * ImGui.GetTextLineHeightWithSpacing()), () => + { + ImGui.NewLine(); + ImGui.TextUnformatted("Every mod in a collection can have three basic states: 'Enabled', 'Disabled' and 'Unconfigured'."); + ImGui.BulletText("If the mod is 'Enabled' or 'Disabled', it does not matter if the collection inherits from other collections."); + ImGui.BulletText( + "If the mod is unconfigured, those inherited-from collections are checked in the order displayed here, including sub-inheritances."); + ImGui.BulletText( + "If a collection is found in which the mod is either 'Enabled' or 'Disabled', the settings from this collection will be used."); + ImGui.BulletText("If no such collection is found, the mod will be treated as disabled."); + ImGui.BulletText( + "Highlighted collections in the left box are never reached because they are already checked in a sub-inheritance before."); + ImGui.NewLine(); + ImGui.TextUnformatted("Example"); + ImGui.BulletText("Collection A has the Bibo+ body and a Hempen Camise mod enabled."); + ImGui.BulletText( + "Collection B inherits from A, leaves Bibo+ unconfigured, but has the Hempen Camise enabled with different settings than A."); + ImGui.BulletText("Collection C also inherits from A, has Bibo+ explicitly disabled and the Hempen Camise unconfigured."); + ImGui.BulletText("Collection D inherits from C and then B and leaves everything unconfigured."); + using var indent = ImRaii.PushIndent(); + ImGui.BulletText("B uses Bibo+ settings from A and its own Hempen Camise settings."); + ImGui.BulletText("C has Bibo+ disabled and uses A's Hempen Camise settings."); + ImGui.BulletText( + "D has Bibo+ disabled and uses A's Hempen Camise settings, not B's. It traversed the collections in Order D -> (C -> A) -> (B -> A)."); + }); + /// /// If an inherited collection is expanded, @@ -122,7 +123,8 @@ public class InheritanceUi _seenInheritedCollections.Contains(inheritance)); _seenInheritedCollections.Add(inheritance); - ImRaii.TreeNode($"{Name(inheritance)}###{inheritance.Name}", ImGuiTreeNodeFlags.NoTreePushOnOpen | ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet); + ImRaii.TreeNode($"{Name(inheritance)}###{inheritance.Name}", + ImGuiTreeNodeFlags.NoTreePushOnOpen | ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet); var (minRect, maxRect) = (ImGui.GetItemRectMin(), ImGui.GetItemRectMax()); DrawInheritanceTreeClicks(inheritance, false); diff --git a/Penumbra/UI/FileDialogService.cs b/Penumbra/UI/FileDialogService.cs index dc638ef5..e5b0fa19 100644 --- a/Penumbra/UI/FileDialogService.cs +++ b/Penumbra/UI/FileDialogService.cs @@ -1,5 +1,3 @@ -using System.Collections.Concurrent; -using System.Reflection; using Dalamud.Interface; using Dalamud.Interface.ImGuiFileDialog; using Dalamud.Utility; diff --git a/Penumbra/UI/ModsTab/ModFileSystemSelector.cs b/Penumbra/UI/ModsTab/ModFileSystemSelector.cs index 91da4da5..3a7a7343 100644 --- a/Penumbra/UI/ModsTab/ModFileSystemSelector.cs +++ b/Penumbra/UI/ModsTab/ModFileSystemSelector.cs @@ -14,6 +14,7 @@ using Penumbra.Collections.Manager; using Penumbra.Communication; using Penumbra.Mods; using Penumbra.Mods.Manager; +using Penumbra.Mods.Subclasses; using Penumbra.Services; using Penumbra.UI.Classes; using ChatService = Penumbra.Services.ChatService; @@ -376,8 +377,10 @@ public sealed class ModFileSystemSelector : FileSystemSelector filter switch { - ModFilter.Enabled => "Enabled", - ModFilter.Disabled => "Disabled", - ModFilter.Favorite => "Favorite", - ModFilter.NotFavorite => "No Favorite", - ModFilter.NoConflict => "No Conflicts", - ModFilter.SolvedConflict => "Solved Conflicts", - ModFilter.UnsolvedConflict => "Unsolved Conflicts", + ModFilter.Enabled => "Enabled", + ModFilter.Disabled => "Disabled", + ModFilter.Favorite => "Favorite", + ModFilter.NotFavorite => "No Favorite", + ModFilter.NoConflict => "No Conflicts", + ModFilter.SolvedConflict => "Solved Conflicts", + ModFilter.UnsolvedConflict => "Unsolved Conflicts", ModFilter.HasNoMetaManipulations => "No Meta Manipulations", - ModFilter.HasMetaManipulations => "Meta Manipulations", - ModFilter.HasNoFileSwaps => "No File Swaps", - ModFilter.HasFileSwaps => "File Swaps", - ModFilter.HasNoConfig => "No Configuration", - ModFilter.HasConfig => "Configuration", - ModFilter.HasNoFiles => "No Files", - ModFilter.HasFiles => "Files", - ModFilter.IsNew => "Newly Imported", - ModFilter.NotNew => "Not Newly Imported", - ModFilter.Inherited => "Inherited Configuration", - ModFilter.Uninherited => "Own Configuration", - ModFilter.Undefined => "Not Configured", - _ => throw new ArgumentOutOfRangeException(nameof(filter), filter, null), + ModFilter.HasMetaManipulations => "Meta Manipulations", + ModFilter.HasNoFileSwaps => "No File Swaps", + ModFilter.HasFileSwaps => "File Swaps", + ModFilter.HasNoConfig => "No Configuration", + ModFilter.HasConfig => "Configuration", + ModFilter.HasNoFiles => "No Files", + ModFilter.HasFiles => "Files", + ModFilter.IsNew => "Newly Imported", + ModFilter.NotNew => "Not Newly Imported", + ModFilter.Inherited => "Inherited Configuration", + ModFilter.Uninherited => "Own Configuration", + ModFilter.Undefined => "Not Configured", + _ => throw new ArgumentOutOfRangeException(nameof(filter), filter, null), }; -} \ No newline at end of file +} diff --git a/Penumbra/UI/ModsTab/ModPanel.cs b/Penumbra/UI/ModsTab/ModPanel.cs index 1866606a..59c9d279 100644 --- a/Penumbra/UI/ModsTab/ModPanel.cs +++ b/Penumbra/UI/ModsTab/ModPanel.cs @@ -4,6 +4,7 @@ using ImGuiNET; using OtterGui; using OtterGui.Raii; using Penumbra.Mods; +using Penumbra.Mods.Manager; using Penumbra.UI.AdvancedWindow; namespace Penumbra.UI.ModsTab; diff --git a/Penumbra/UI/ModsTab/ModPanelConflictsTab.cs b/Penumbra/UI/ModsTab/ModPanelConflictsTab.cs index 83f79f56..38737274 100644 --- a/Penumbra/UI/ModsTab/ModPanelConflictsTab.cs +++ b/Penumbra/UI/ModsTab/ModPanelConflictsTab.cs @@ -12,7 +12,7 @@ namespace Penumbra.UI.ModsTab; public class ModPanelConflictsTab : ITab { private readonly ModFileSystemSelector _selector; - private readonly CollectionManager _collectionManager; + private readonly CollectionManager _collectionManager; public ModPanelConflictsTab(CollectionManager collectionManager, ModFileSystemSelector selector) { diff --git a/Penumbra/UI/ModsTab/ModPanelDescriptionTab.cs b/Penumbra/UI/ModsTab/ModPanelDescriptionTab.cs index 256be8d6..790bc383 100644 --- a/Penumbra/UI/ModsTab/ModPanelDescriptionTab.cs +++ b/Penumbra/UI/ModsTab/ModPanelDescriptionTab.cs @@ -3,9 +3,7 @@ using ImGuiNET; using OtterGui.Raii; using OtterGui; using OtterGui.Widgets; -using Penumbra.Mods; using Penumbra.Mods.Manager; -using Penumbra.UI.Classes; namespace Penumbra.UI.ModsTab; @@ -13,7 +11,7 @@ public class ModPanelDescriptionTab : ITab { private readonly ModFileSystemSelector _selector; private readonly TutorialService _tutorial; - private readonly ModManager _modManager; + private readonly ModManager _modManager; private readonly TagButtons _localTags = new(); private readonly TagButtons _modTags = new(); diff --git a/Penumbra/UI/ModsTab/ModPanelSettingsTab.cs b/Penumbra/UI/ModsTab/ModPanelSettingsTab.cs index acfdcf28..d63e42ef 100644 --- a/Penumbra/UI/ModsTab/ModPanelSettingsTab.cs +++ b/Penumbra/UI/ModsTab/ModPanelSettingsTab.cs @@ -4,10 +4,8 @@ using OtterGui; using OtterGui.Widgets; using Penumbra.Api.Enums; using Penumbra.Collections; -using Penumbra.Mods; using Penumbra.UI.Classes; using Dalamud.Interface.Components; -using Dalamud.Interface; using Penumbra.Collections.Manager; using Penumbra.Mods.Manager; using Penumbra.Mods.Subclasses; @@ -192,7 +190,7 @@ public class ModPanelSettingsTab : ITab _collectionManager.Editor.SetModSetting(_collectionManager.Active.Current, _selector.Selected!, groupIdx, (uint)idx2); if (option.Description.Length > 0) - ImGuiUtil.SelectableHelpMarker(option.Description); + ImGuiUtil.SelectableHelpMarker(option.Description); id.Pop(); } diff --git a/Penumbra/UI/ModsTab/ModPanelTabBar.cs b/Penumbra/UI/ModsTab/ModPanelTabBar.cs index 3f1b0f77..02ec9a32 100644 --- a/Penumbra/UI/ModsTab/ModPanelTabBar.cs +++ b/Penumbra/UI/ModsTab/ModPanelTabBar.cs @@ -5,6 +5,7 @@ using OtterGui.Raii; using OtterGui.Widgets; using Penumbra.Mods; using Penumbra.Mods.Manager; +using Penumbra.Mods.Subclasses; using Penumbra.UI.AdvancedWindow; namespace Penumbra.UI.ModsTab; diff --git a/Penumbra/UI/ResourceWatcher/Record.cs b/Penumbra/UI/ResourceWatcher/Record.cs index ec66ae08..dea68955 100644 --- a/Penumbra/UI/ResourceWatcher/Record.cs +++ b/Penumbra/UI/ResourceWatcher/Record.cs @@ -1,10 +1,9 @@ using OtterGui.Classes; using Penumbra.Collections; -using Penumbra.GameData.Enums; using Penumbra.Interop.Structs; using Penumbra.String; -namespace Penumbra.UI; +namespace Penumbra.UI.ResourceWatcher; [Flags] public enum RecordType : byte diff --git a/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs b/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs index e8031d4e..781c5fc1 100644 --- a/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs +++ b/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs @@ -1,4 +1,3 @@ -using System.Collections.Concurrent; using System.Text.RegularExpressions; using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.System.Resource; @@ -15,12 +14,12 @@ using Penumbra.String; using Penumbra.String.Classes; using Penumbra.UI.Classes; -namespace Penumbra.UI; +namespace Penumbra.UI.ResourceWatcher; public class ResourceWatcher : IDisposable, ITab { public const int DefaultMaxEntries = 1024; - public const RecordType AllRecords = RecordType.Request | RecordType.ResourceLoad | RecordType.FileLoad | RecordType.Destruction; + public const RecordType AllRecords = RecordType.Request | RecordType.ResourceLoad | RecordType.FileLoad | RecordType.Destruction; private readonly Configuration _config; private readonly ResourceService _resources; @@ -28,7 +27,7 @@ public class ResourceWatcher : IDisposable, ITab private readonly ActorService _actors; private readonly List _records = new(); private readonly ConcurrentQueue _newRecords = new(); - private readonly ResourceWatcherTable _table; + private readonly ResourceWatcherTable _table; private string _logFilter = string.Empty; private Regex? _logRegex; private int _newMaxEntries; diff --git a/Penumbra/UI/ResourceWatcher/ResourceWatcherTable.cs b/Penumbra/UI/ResourceWatcher/ResourceWatcherTable.cs index 905307ba..eb034459 100644 --- a/Penumbra/UI/ResourceWatcher/ResourceWatcherTable.cs +++ b/Penumbra/UI/ResourceWatcher/ResourceWatcherTable.cs @@ -4,10 +4,9 @@ using OtterGui; using OtterGui.Classes; using OtterGui.Raii; using OtterGui.Table; -using Penumbra.GameData.Enums; using Penumbra.String; -namespace Penumbra.UI; +namespace Penumbra.UI.ResourceWatcher; internal sealed class ResourceWatcherTable : Table { diff --git a/Penumbra/UI/Tabs/ChangedItemsTab.cs b/Penumbra/UI/Tabs/ChangedItemsTab.cs index 4605527a..f7e64125 100644 --- a/Penumbra/UI/Tabs/ChangedItemsTab.cs +++ b/Penumbra/UI/Tabs/ChangedItemsTab.cs @@ -35,9 +35,9 @@ public class ChangedItemsTab : ITab public void DrawContent() { - _collectionHeader.Draw(true); + _collectionHeader.Draw(true); _drawer.DrawTypeFilter(); - var varWidth = DrawFilters(); + var varWidth = DrawFilters(); using var child = ImRaii.Child("##changedItemsChild", -Vector2.One); if (!child) return; diff --git a/Penumbra/UI/Tabs/CollectionsTab.cs b/Penumbra/UI/Tabs/CollectionsTab.cs index 4d6d2dd6..5b51bd85 100644 --- a/Penumbra/UI/Tabs/CollectionsTab.cs +++ b/Penumbra/UI/Tabs/CollectionsTab.cs @@ -58,11 +58,12 @@ public class CollectionsTab : IDisposable, ITab public void DrawContent() { - var width = ImGui.CalcTextSize("nnnnnnnnnnnnnnnnnnnnnnnnnn").X; + var width = ImGui.CalcTextSize("nnnnnnnnnnnnnnnnnnnnnnnnnn").X; using (var group = ImRaii.Group()) { _selector.Draw(width); } + _tutorial.OpenTutorial(BasicTutorialSteps.EditingCollections); ImGui.SameLine(); @@ -91,7 +92,7 @@ public class CollectionsTab : IDisposable, ITab color.Pop(); _tutorial.OpenTutorial(BasicTutorialSteps.SimpleAssignments); ImGui.SameLine(); - + color.Push(ImGuiCol.Button, ImGui.GetColorU32(ImGuiCol.TabActive), Mode is PanelMode.IndividualAssignment); if (ImGui.Button("Individual Assignments", buttonSize)) Mode = PanelMode.IndividualAssignment; @@ -112,7 +113,7 @@ public class CollectionsTab : IDisposable, ITab color.Pop(); _tutorial.OpenTutorial(BasicTutorialSteps.CollectionDetails); ImGui.SameLine(); - + style.Push(ImGuiStyleVar.FrameBorderSize, ImGuiHelpers.GlobalScale); color.Push(ImGuiCol.Text, ColorId.FolderExpanded.Value()) .Push(ImGuiCol.Border, ColorId.FolderExpanded.Value()); diff --git a/Penumbra/UI/Tabs/DebugTab.cs b/Penumbra/UI/Tabs/DebugTab.cs index fc0168a0..8dae2caa 100644 --- a/Penumbra/UI/Tabs/DebugTab.cs +++ b/Penumbra/UI/Tabs/DebugTab.cs @@ -565,11 +565,12 @@ public class DebugTab : Window, ITab ImGui.InputText("File Name", ref _emoteSearchFile, 256); ImGui.InputText("Emote Name", ref _emoteSearchName, 256); - using var table = Table("##table", 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.SizingFixedFit, new Vector2(-1, 12 * ImGui.GetTextLineHeightWithSpacing())); + using var table = Table("##table", 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.SizingFixedFit, + new Vector2(-1, 12 * ImGui.GetTextLineHeightWithSpacing())); if (!table) return; - var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeightWithSpacing()); + var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeightWithSpacing()); var dummy = ImGuiClip.FilteredClippedDraw(_identifier.AwaitedService.Emotes, skips, p => p.Key.Contains(_emoteSearchFile, StringComparison.OrdinalIgnoreCase) && (_emoteSearchName.Length == 0 diff --git a/Penumbra/UI/Tabs/EffectiveTab.cs b/Penumbra/UI/Tabs/EffectiveTab.cs index 3c1d0801..0cc2e5c1 100644 --- a/Penumbra/UI/Tabs/EffectiveTab.cs +++ b/Penumbra/UI/Tabs/EffectiveTab.cs @@ -30,7 +30,7 @@ public class EffectiveTab : ITab public void DrawContent() { - SetupEffectiveSizes(); + SetupEffectiveSizes(); _collectionHeader.Draw(true); DrawFilters(); using var child = ImRaii.Child("##EffectiveChangesTab", -Vector2.One, false); diff --git a/Penumbra/UI/Tabs/SettingsTab.cs b/Penumbra/UI/Tabs/SettingsTab.cs index 701d1ef6..7c350106 100644 --- a/Penumbra/UI/Tabs/SettingsTab.cs +++ b/Penumbra/UI/Tabs/SettingsTab.cs @@ -703,12 +703,13 @@ public class SettingsTab : ITab if (_compactor.MassCompactRunning) { ImGui.ProgressBar((float)_compactor.CurrentIndex / _compactor.TotalFiles, - new Vector2(ImGui.GetContentRegionAvail().X - ImGui.GetStyle().ItemSpacing.X - UiHelpers.IconButtonSize.X, ImGui.GetFrameHeight()), + new Vector2(ImGui.GetContentRegionAvail().X - ImGui.GetStyle().ItemSpacing.X - UiHelpers.IconButtonSize.X, + ImGui.GetFrameHeight()), _compactor.CurrentFile?.FullName[(_modManager.BasePath.FullName.Length + 1)..] ?? "Gathering Files..."); ImGui.SameLine(); if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Ban.ToIconString(), UiHelpers.IconButtonSize, "Cancel the mass action.", !_compactor.MassCompactRunning, true)) - _compactor.CancelMassCompact(); + _compactor.CancelMassCompact(); } else { diff --git a/Penumbra/UI/TutorialService.cs b/Penumbra/UI/TutorialService.cs index 87e709c3..1a589c28 100644 --- a/Penumbra/UI/TutorialService.cs +++ b/Penumbra/UI/TutorialService.cs @@ -42,10 +42,10 @@ public enum BasicTutorialSteps /// Service for the in-game tutorial. public class TutorialService { - public const string SelectedCollection = "Selected Collection"; - public const string DefaultCollection = "Base Collection"; - public const string InterfaceCollection = "Interface Collection"; - public const string AssignedCollections = "Assigned Collections"; + public const string SelectedCollection = "Selected Collection"; + public const string DefaultCollection = "Base Collection"; + public const string InterfaceCollection = "Interface Collection"; + public const string AssignedCollections = "Assigned Collections"; public const string SupportedRedrawModifiers = " - nothing, to redraw all characters\n" + " - 'self' or '': your own character\n" @@ -79,20 +79,26 @@ public class TutorialService .Register("Initial Setup, Step 3: Collections", "Collections are lists of settings for your installed mods.\n\n" + "This is our next stop!\n\n" + "Go here after setting up your root folder to continue the tutorial!") - .Register("Initial Setup, Step 4: Managing Collections", "On the left, we have the collection selector. Here, we can create new collections - either empty ones or by duplicating existing ones - and delete any collections not needed anymore.\n" + .Register("Initial Setup, Step 4: Managing Collections", + "On the left, we have the collection selector. Here, we can create new collections - either empty ones or by duplicating existing ones - and delete any collections not needed anymore.\n" + $"There will always be one collection called {ModCollection.DefaultCollectionName} that can not be deleted.") .Register($"Initial Setup, Step 5: {SelectedCollection}", $"The {SelectedCollection} is the one we highlighted in the selector. It is the collection we are currently looking at and editing.\nAny changes we make in our mod settings later in the next tab will edit this collection.\n" + $"We should already have the collection named {ModCollection.DefaultCollectionName} selected, and for our simple setup, we do not need to do anything here.\n\n") - .Register("Initial Setup, Step 6: Simple Assignments", "Aside from being a collection of settings, we can also assign collections to different functions. This is used to make different mods apply to different characters.\n" + .Register("Initial Setup, Step 6: Simple Assignments", + "Aside from being a collection of settings, we can also assign collections to different functions. This is used to make different mods apply to different characters.\n" + "The Simple Assignments panel shows you the possible assignments that are enough for most people along with descriptions.\n" + $"If you are just starting, you can see that the {ModCollection.DefaultCollectionName} is currently assigned to {CollectionType.Default.ToName()} and {CollectionType.Interface.ToName()}.\n" + "You can also assign 'Use No Mods' instead of a collection by clicking on the function buttons.") - .Register("Individual Assignments", "In the Individual Assignments panel, you can manually create assignments for very specific characters or monsters, not just yourself or ones you can currently target.") - .Register("Group Assignments", "In the Group Assignments panel, you can create Assignments for more specific groups of characters based on race or age.") - .Register("Collection Details", "In the Collection Details panel, you can see a detailed overview over the usage of the currently selected collection, as well as remove outdated mod settings and setup inheritance.\n" + .Register("Individual Assignments", + "In the Individual Assignments panel, you can manually create assignments for very specific characters or monsters, not just yourself or ones you can currently target.") + .Register("Group Assignments", + "In the Group Assignments panel, you can create Assignments for more specific groups of characters based on race or age.") + .Register("Collection Details", + "In the Collection Details panel, you can see a detailed overview over the usage of the currently selected collection, as well as remove outdated mod settings and setup inheritance.\n" + "Inheritance can be used to make one collection take the settings of another as long as it does not setup the mod in question itself.") - .Register("Incognito Mode", "This button can toggle Incognito Mode, which shortens all collection names to two letters and a number,\n" + .Register("Incognito Mode", + "This button can toggle Incognito Mode, which shortens all collection names to two letters and a number,\n" + "and all displayed individual character names to their initials and world, in case you want to share screenshots.\n" + "It is strongly recommended to not show your characters name in public screenshots when using Penumbra.") .Deprecated() @@ -150,7 +156,7 @@ public class TutorialService _config.TutorialStep = v; _config.Save(); }); - + /// Update the current tutorial step if tutorials have changed since last update. public void UpdateTutorialStep() { diff --git a/Penumbra/UI/UiHelpers.cs b/Penumbra/UI/UiHelpers.cs index 7f4fc7cb..132dce86 100644 --- a/Penumbra/UI/UiHelpers.cs +++ b/Penumbra/UI/UiHelpers.cs @@ -114,8 +114,8 @@ public static class UiHelpers ScaleX5 = Scale * 5; } - IconButtonSize = new Vector2(ImGui.GetFrameHeight()); + IconButtonSize = new Vector2(ImGui.GetFrameHeight()); InputTextMinusButton3 = InputTextWidth.X - IconButtonSize.X - ScaleX3; - InputTextMinusButton = InputTextWidth.X - IconButtonSize.X - ImGui.GetStyle().ItemSpacing.X; + InputTextMinusButton = InputTextWidth.X - IconButtonSize.X - ImGui.GetStyle().ItemSpacing.X; } } diff --git a/Penumbra/UI/WindowSystem.cs b/Penumbra/UI/WindowSystem.cs index f08b6de9..25d91644 100644 --- a/Penumbra/UI/WindowSystem.cs +++ b/Penumbra/UI/WindowSystem.cs @@ -1,11 +1,10 @@ using Dalamud.Interface; using Dalamud.Interface.Windowing; using Dalamud.Plugin; -using Penumbra.UI; using Penumbra.UI.AdvancedWindow; using Penumbra.UI.Tabs; -namespace Penumbra; +namespace Penumbra.UI; public class PenumbraWindowSystem : IDisposable { diff --git a/Penumbra/Util/DictionaryExtensions.cs b/Penumbra/Util/DictionaryExtensions.cs index 74274c38..abf715e6 100644 --- a/Penumbra/Util/DictionaryExtensions.cs +++ b/Penumbra/Util/DictionaryExtensions.cs @@ -2,98 +2,84 @@ namespace Penumbra.Util; public static class DictionaryExtensions { - /// Returns whether two dictionaries contain equal keys and values. - public static bool SetEquals< TKey, TValue >( this IReadOnlyDictionary< TKey, TValue > lhs, IReadOnlyDictionary< TKey, TValue > rhs ) + /// Returns whether two dictionaries contain equal keys and values. + public static bool SetEquals(this IReadOnlyDictionary lhs, IReadOnlyDictionary rhs) { - if( ReferenceEquals( lhs, rhs ) ) - { + if (ReferenceEquals(lhs, rhs)) return true; - } - if( lhs.Count != rhs.Count ) - { + if (lhs.Count != rhs.Count) return false; - } - foreach( var (key, value) in lhs ) + foreach (var (key, value) in lhs) { - if( !rhs.TryGetValue( key, out var rhsValue ) ) - { + if (!rhs.TryGetValue(key, out var rhsValue)) return false; - } - if( value == null ) + if (value == null) { - if( rhsValue != null ) - { + if (rhsValue != null) return false; - } continue; } - if( !value.Equals( rhsValue ) ) - { + if (!value.Equals(rhsValue)) return false; - } } return true; } - /// Set one dictionary to the other, deleting previous entries and ensuring capacity beforehand. - public static void SetTo< TKey, TValue >( this Dictionary< TKey, TValue > lhs, IReadOnlyDictionary< TKey, TValue > rhs ) + /// Set one dictionary to the other, deleting previous entries and ensuring capacity beforehand. + public static void SetTo(this Dictionary lhs, IReadOnlyDictionary rhs) where TKey : notnull { - if( ReferenceEquals( lhs, rhs ) ) + if (ReferenceEquals(lhs, rhs)) return; lhs.Clear(); - lhs.EnsureCapacity( rhs.Count ); - foreach( var (key, value) in rhs ) - lhs.Add( key, value ); + lhs.EnsureCapacity(rhs.Count); + foreach (var (key, value) in rhs) + lhs.Add(key, value); } - /// Set one set to the other, deleting previous entries and ensuring capacity beforehand. + /// Set one set to the other, deleting previous entries and ensuring capacity beforehand. public static void SetTo(this HashSet lhs, IReadOnlySet rhs) { if (ReferenceEquals(lhs, rhs)) return; lhs.Clear(); - lhs.EnsureCapacity(rhs.Count); + lhs.EnsureCapacity(rhs.Count); foreach (var value in rhs) lhs.Add(value); } - /// Add all entries from the other dictionary that would not overwrite current keys. - public static void AddFrom< TKey, TValue >( this Dictionary< TKey, TValue > lhs, IReadOnlyDictionary< TKey, TValue > rhs ) + /// Add all entries from the other dictionary that would not overwrite current keys. + public static void AddFrom(this Dictionary lhs, IReadOnlyDictionary rhs) where TKey : notnull { - if( ReferenceEquals( lhs, rhs ) ) - { + if (ReferenceEquals(lhs, rhs)) return; - } - lhs.EnsureCapacity( lhs.Count + rhs.Count ); - foreach( var (key, value) in rhs ) - { - lhs.Add( key, value ); - } + lhs.EnsureCapacity(lhs.Count + rhs.Count); + foreach (var (key, value) in rhs) + lhs.Add(key, value); } - public static int ReplaceValue< TKey, TValue >( this Dictionary< TKey, TValue > dict, TValue from, TValue to ) + public static int ReplaceValue(this Dictionary dict, TValue from, TValue to) where TKey : notnull - where TValue : IEquatable< TValue > + where TValue : IEquatable { var count = 0; - foreach( var (key, _) in dict.ToArray().Where( kvp => kvp.Value.Equals( from ) ) ) + foreach (var (key, _) in dict.ToArray().Where(kvp => kvp.Value.Equals(from))) { - dict[ key ] = to; + dict[key] = to; ++count; } return count; } -} \ No newline at end of file +} diff --git a/Penumbra/Util/FixedUlongStringEnumConverter.cs b/Penumbra/Util/FixedUlongStringEnumConverter.cs index 85c61837..857d951d 100644 --- a/Penumbra/Util/FixedUlongStringEnumConverter.cs +++ b/Penumbra/Util/FixedUlongStringEnumConverter.cs @@ -8,84 +8,70 @@ namespace Penumbra.Util; // These converters fix this, taken from https://stackoverflow.com/questions/61740964/json-net-unable-to-deserialize-ulong-flag-type-enum/ public class ForceNumericFlagEnumConverter : FixedUlongStringEnumConverter { - private static bool HasFlagsAttribute( Type? objectType ) - => objectType != null && Attribute.IsDefined( Nullable.GetUnderlyingType( objectType ) ?? objectType, typeof( System.FlagsAttribute ) ); + private static bool HasFlagsAttribute(Type? objectType) + => objectType != null && Attribute.IsDefined(Nullable.GetUnderlyingType(objectType) ?? objectType, typeof(FlagsAttribute)); - public override void WriteJson( JsonWriter writer, object? value, JsonSerializer serializer ) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { var enumType = value?.GetType(); - if( HasFlagsAttribute( enumType ) ) + if (HasFlagsAttribute(enumType)) { - var underlyingType = Enum.GetUnderlyingType( enumType! ); - var underlyingValue = Convert.ChangeType( value, underlyingType ); - writer.WriteValue( underlyingValue ); + var underlyingType = Enum.GetUnderlyingType(enumType!); + var underlyingValue = Convert.ChangeType(value, underlyingType); + writer.WriteValue(underlyingValue); } else { - base.WriteJson( writer, value, serializer ); + base.WriteJson(writer, value, serializer); } } } public class FixedUlongStringEnumConverter : StringEnumConverter { - public override object? ReadJson( JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer ) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { - if( reader.MoveToContentAndAssert().TokenType != JsonToken.Integer || reader.ValueType != typeof( System.Numerics.BigInteger ) ) - { - return base.ReadJson( reader, objectType, existingValue, serializer ); - } + if (reader.MoveToContentAndAssert().TokenType != JsonToken.Integer || reader.ValueType != typeof(BigInteger)) + return base.ReadJson(reader, objectType, existingValue, serializer); // Todo: throw an exception if !this.AllowIntegerValues // https://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_Converters_StringEnumConverter_AllowIntegerValues.htm - var enumType = Nullable.GetUnderlyingType( objectType ) ?? objectType; - if( Enum.GetUnderlyingType( enumType ) == typeof( ulong ) ) + var enumType = Nullable.GetUnderlyingType(objectType) ?? objectType; + if (Enum.GetUnderlyingType(enumType) == typeof(ulong)) { - var bigInteger = ( System.Numerics.BigInteger )reader.Value!; - if( bigInteger >= ulong.MinValue && bigInteger <= ulong.MaxValue ) - { - return Enum.ToObject( enumType, checked( ( ulong )bigInteger ) ); - } + var bigInteger = (BigInteger)reader.Value!; + if (bigInteger >= ulong.MinValue && bigInteger <= ulong.MaxValue) + return Enum.ToObject(enumType, checked((ulong)bigInteger)); } - return base.ReadJson( reader, objectType, existingValue, serializer ); + return base.ReadJson(reader, objectType, existingValue, serializer); } } public static partial class JsonExtensions { - public static JsonReader MoveToContentAndAssert( this JsonReader reader ) + public static JsonReader MoveToContentAndAssert(this JsonReader reader) { - if( reader == null ) - { + if (reader == null) throw new ArgumentNullException(); - } - if( reader.TokenType == JsonToken.None ) // Skip past beginning of stream. - { + if (reader.TokenType == JsonToken.None) // Skip past beginning of stream. reader.ReadAndAssert(); - } - while( reader.TokenType == JsonToken.Comment ) // Skip past comments. - { + while (reader.TokenType == JsonToken.Comment) // Skip past comments. reader.ReadAndAssert(); - } return reader; } - private static JsonReader ReadAndAssert( this JsonReader reader ) + private static JsonReader ReadAndAssert(this JsonReader reader) { - if( reader == null ) - { + if (reader == null) throw new ArgumentNullException(); - } - if( !reader.Read() ) - { - throw new JsonReaderException( "Unexpected end of JSON stream." ); - } + if (!reader.Read()) + throw new JsonReaderException("Unexpected end of JSON stream."); return reader; } -} \ No newline at end of file +} diff --git a/Penumbra/Util/PenumbraSqPackStream.cs b/Penumbra/Util/PenumbraSqPackStream.cs index d5b51433..d913a019 100644 --- a/Penumbra/Util/PenumbraSqPackStream.cs +++ b/Penumbra/Util/PenumbraSqPackStream.cs @@ -10,45 +10,45 @@ public class PenumbraSqPackStream : IDisposable protected BinaryReader Reader { get; set; } - public PenumbraSqPackStream( FileInfo file ) - : this( file.OpenRead() ) + public PenumbraSqPackStream(FileInfo file) + : this(file.OpenRead()) { } - public PenumbraSqPackStream( Stream stream ) + public PenumbraSqPackStream(Stream stream) { BaseStream = stream; - Reader = new BinaryReader( BaseStream ); + Reader = new BinaryReader(BaseStream); } public SqPackHeader GetSqPackHeader() { BaseStream.Position = 0; - return Reader.ReadStructure< SqPackHeader >(); + return Reader.ReadStructure(); } - public SqPackFileInfo GetFileMetadata( long offset ) + public SqPackFileInfo GetFileMetadata(long offset) { BaseStream.Position = offset; - return Reader.ReadStructure< SqPackFileInfo >(); + return Reader.ReadStructure(); } - public T ReadFile< T >( long offset ) where T : PenumbraFileResource + public T ReadFile(long offset) where T : PenumbraFileResource { using var ms = new MemoryStream(); BaseStream.Position = offset; - var fileInfo = Reader.ReadStructure< SqPackFileInfo >(); - var file = Activator.CreateInstance< T >(); + var fileInfo = Reader.ReadStructure(); + var file = Activator.CreateInstance(); // check if we need to read the extended model header or just default to the standard file header - if( fileInfo.Type == FileType.Model ) + if (fileInfo.Type == FileType.Model) { BaseStream.Position = offset; - var modelFileInfo = Reader.ReadStructure< ModelBlock >(); + var modelFileInfo = Reader.ReadStructure(); file.FileInfo = new PenumbraFileInfo { @@ -74,33 +74,31 @@ public class PenumbraSqPackStream : IDisposable }; } - switch( fileInfo.Type ) + switch (fileInfo.Type) { - case FileType.Empty: throw new FileNotFoundException( $"The file located at 0x{offset:x} is empty." ); + case FileType.Empty: throw new FileNotFoundException($"The file located at 0x{offset:x} is empty."); case FileType.Standard: - ReadStandardFile( file, ms ); + ReadStandardFile(file, ms); break; case FileType.Model: - ReadModelFile( file, ms ); + ReadModelFile(file, ms); break; case FileType.Texture: - ReadTextureFile( file, ms ); + ReadTextureFile(file, ms); break; - default: throw new NotImplementedException( $"File Type {( uint )fileInfo.Type} is not implemented." ); + default: throw new NotImplementedException($"File Type {(uint)fileInfo.Type} is not implemented."); } file.Data = ms.ToArray(); - if( file.Data.Length != file.FileInfo.RawFileSize ) - { - Debug.WriteLine( "Read data size does not match file size." ); - } + if (file.Data.Length != file.FileInfo.RawFileSize) + Debug.WriteLine("Read data size does not match file size."); - file.FileStream = new MemoryStream( file.Data, false ); - file.Reader = new BinaryReader( file.FileStream ); + file.FileStream = new MemoryStream(file.Data, false); + file.Reader = new BinaryReader(file.FileStream); file.FileStream.Position = 0; file.LoadFile(); @@ -108,20 +106,18 @@ public class PenumbraSqPackStream : IDisposable return file; } - private void ReadStandardFile( PenumbraFileResource resource, MemoryStream ms ) + private void ReadStandardFile(PenumbraFileResource resource, MemoryStream ms) { - var blocks = Reader.ReadStructures< DatStdFileBlockInfos >( ( int )resource.FileInfo!.BlockCount ); + var blocks = Reader.ReadStructures((int)resource.FileInfo!.BlockCount); - foreach( var block in blocks ) - { - ReadFileBlock( resource.FileInfo.Offset + resource.FileInfo.HeaderSize + block.Offset, ms ); - } + foreach (var block in blocks) + ReadFileBlock(resource.FileInfo.Offset + resource.FileInfo.HeaderSize + block.Offset, ms); // reset position ready for reading ms.Position = 0; } - private unsafe void ReadModelFile( PenumbraFileResource resource, MemoryStream ms ) + private unsafe void ReadModelFile(PenumbraFileResource resource, MemoryStream ms) { var mdlBlock = resource.FileInfo!.ModelBlock; var baseOffset = resource.FileInfo.Offset + resource.FileInfo.HeaderSize; @@ -133,185 +129,165 @@ public class PenumbraSqPackStream : IDisposable // but it seems to work fine in explorer... int totalBlocks = mdlBlock.StackBlockNum; totalBlocks += mdlBlock.RuntimeBlockNum; - for( var i = 0; i < 3; i++ ) - { - totalBlocks += mdlBlock.VertexBufferBlockNum[ i ]; - } + for (var i = 0; i < 3; i++) + totalBlocks += mdlBlock.VertexBufferBlockNum[i]; - for( var i = 0; i < 3; i++ ) - { - totalBlocks += mdlBlock.EdgeGeometryVertexBufferBlockNum[ i ]; - } + for (var i = 0; i < 3; i++) + totalBlocks += mdlBlock.EdgeGeometryVertexBufferBlockNum[i]; - for( var i = 0; i < 3; i++ ) - { - totalBlocks += mdlBlock.IndexBufferBlockNum[ i ]; - } + for (var i = 0; i < 3; i++) + totalBlocks += mdlBlock.IndexBufferBlockNum[i]; - var compressedBlockSizes = Reader.ReadStructures< ushort >( totalBlocks ); + var compressedBlockSizes = Reader.ReadStructures(totalBlocks); var currentBlock = 0; var vertexDataOffsets = new int[3]; var indexDataOffsets = new int[3]; var vertexBufferSizes = new int[3]; var indexBufferSizes = new int[3]; - ms.Seek( 0x44, SeekOrigin.Begin ); + ms.Seek(0x44, SeekOrigin.Begin); - Reader.Seek( baseOffset + mdlBlock.StackOffset ); + Reader.Seek(baseOffset + mdlBlock.StackOffset); var stackStart = ms.Position; - for( var i = 0; i < mdlBlock.StackBlockNum; i++ ) + for (var i = 0; i < mdlBlock.StackBlockNum; i++) { var lastPos = Reader.BaseStream.Position; - ReadFileBlock( ms ); - Reader.Seek( lastPos + compressedBlockSizes[ currentBlock ] ); + ReadFileBlock(ms); + Reader.Seek(lastPos + compressedBlockSizes[currentBlock]); currentBlock++; } var stackEnd = ms.Position; - var stackSize = ( int )( stackEnd - stackStart ); + var stackSize = (int)(stackEnd - stackStart); - Reader.Seek( baseOffset + mdlBlock.RuntimeOffset ); + Reader.Seek(baseOffset + mdlBlock.RuntimeOffset); var runtimeStart = ms.Position; - for( var i = 0; i < mdlBlock.RuntimeBlockNum; i++ ) + for (var i = 0; i < mdlBlock.RuntimeBlockNum; i++) { var lastPos = Reader.BaseStream.Position; - ReadFileBlock( ms ); - Reader.Seek( lastPos + compressedBlockSizes[ currentBlock ] ); + ReadFileBlock(ms); + Reader.Seek(lastPos + compressedBlockSizes[currentBlock]); currentBlock++; } var runtimeEnd = ms.Position; - var runtimeSize = ( int )( runtimeEnd - runtimeStart ); + var runtimeSize = (int)(runtimeEnd - runtimeStart); - for( var i = 0; i < 3; i++ ) + for (var i = 0; i < 3; i++) { - if( mdlBlock.VertexBufferBlockNum[ i ] != 0 ) + if (mdlBlock.VertexBufferBlockNum[i] != 0) { - var currentVertexOffset = ( int )ms.Position; - if( i == 0 || currentVertexOffset != vertexDataOffsets[ i - 1 ] ) - { - vertexDataOffsets[ i ] = currentVertexOffset; - } + var currentVertexOffset = (int)ms.Position; + if (i == 0 || currentVertexOffset != vertexDataOffsets[i - 1]) + vertexDataOffsets[i] = currentVertexOffset; else - { - vertexDataOffsets[ i ] = 0; - } + vertexDataOffsets[i] = 0; - Reader.Seek( baseOffset + mdlBlock.VertexBufferOffset[ i ] ); + Reader.Seek(baseOffset + mdlBlock.VertexBufferOffset[i]); - for( var j = 0; j < mdlBlock.VertexBufferBlockNum[ i ]; j++ ) + for (var j = 0; j < mdlBlock.VertexBufferBlockNum[i]; j++) { var lastPos = Reader.BaseStream.Position; - vertexBufferSizes[ i ] += ( int )ReadFileBlock( ms ); - Reader.Seek( lastPos + compressedBlockSizes[ currentBlock ] ); + vertexBufferSizes[i] += (int)ReadFileBlock(ms); + Reader.Seek(lastPos + compressedBlockSizes[currentBlock]); currentBlock++; } } - if( mdlBlock.EdgeGeometryVertexBufferBlockNum[ i ] != 0 ) - { - for( var j = 0; j < mdlBlock.EdgeGeometryVertexBufferBlockNum[ i ]; j++ ) + if (mdlBlock.EdgeGeometryVertexBufferBlockNum[i] != 0) + for (var j = 0; j < mdlBlock.EdgeGeometryVertexBufferBlockNum[i]; j++) { var lastPos = Reader.BaseStream.Position; - ReadFileBlock( ms ); - Reader.Seek( lastPos + compressedBlockSizes[ currentBlock ] ); + ReadFileBlock(ms); + Reader.Seek(lastPos + compressedBlockSizes[currentBlock]); currentBlock++; } - } - if( mdlBlock.IndexBufferBlockNum[ i ] != 0 ) + if (mdlBlock.IndexBufferBlockNum[i] != 0) { - var currentIndexOffset = ( int )ms.Position; - if( i == 0 || currentIndexOffset != indexDataOffsets[ i - 1 ] ) - { - indexDataOffsets[ i ] = currentIndexOffset; - } + var currentIndexOffset = (int)ms.Position; + if (i == 0 || currentIndexOffset != indexDataOffsets[i - 1]) + indexDataOffsets[i] = currentIndexOffset; else - { - indexDataOffsets[ i ] = 0; - } + indexDataOffsets[i] = 0; // i guess this is only needed in the vertex area, for i = 0 // Reader.Seek( baseOffset + mdlBlock.IndexBufferOffset[ i ] ); - for( var j = 0; j < mdlBlock.IndexBufferBlockNum[ i ]; j++ ) + for (var j = 0; j < mdlBlock.IndexBufferBlockNum[i]; j++) { var lastPos = Reader.BaseStream.Position; - indexBufferSizes[ i ] += ( int )ReadFileBlock( ms ); - Reader.Seek( lastPos + compressedBlockSizes[ currentBlock ] ); + indexBufferSizes[i] += (int)ReadFileBlock(ms); + Reader.Seek(lastPos + compressedBlockSizes[currentBlock]); currentBlock++; } } } - ms.Seek( 0, SeekOrigin.Begin ); - ms.Write( BitConverter.GetBytes( mdlBlock.Version ) ); - ms.Write( BitConverter.GetBytes( stackSize ) ); - ms.Write( BitConverter.GetBytes( runtimeSize ) ); - ms.Write( BitConverter.GetBytes( mdlBlock.VertexDeclarationNum ) ); - ms.Write( BitConverter.GetBytes( mdlBlock.MaterialNum ) ); - for( var i = 0; i < 3; i++ ) - { - ms.Write( BitConverter.GetBytes( vertexDataOffsets[ i ] ) ); - } + ms.Seek(0, SeekOrigin.Begin); + ms.Write(BitConverter.GetBytes(mdlBlock.Version)); + ms.Write(BitConverter.GetBytes(stackSize)); + ms.Write(BitConverter.GetBytes(runtimeSize)); + ms.Write(BitConverter.GetBytes(mdlBlock.VertexDeclarationNum)); + ms.Write(BitConverter.GetBytes(mdlBlock.MaterialNum)); + for (var i = 0; i < 3; i++) + ms.Write(BitConverter.GetBytes(vertexDataOffsets[i])); - for( var i = 0; i < 3; i++ ) - { - ms.Write( BitConverter.GetBytes( indexDataOffsets[ i ] ) ); - } + for (var i = 0; i < 3; i++) + ms.Write(BitConverter.GetBytes(indexDataOffsets[i])); - for( var i = 0; i < 3; i++ ) - { - ms.Write( BitConverter.GetBytes( vertexBufferSizes[ i ] ) ); - } + for (var i = 0; i < 3; i++) + ms.Write(BitConverter.GetBytes(vertexBufferSizes[i])); - for( var i = 0; i < 3; i++ ) - { - ms.Write( BitConverter.GetBytes( indexBufferSizes[ i ] ) ); - } + for (var i = 0; i < 3; i++) + ms.Write(BitConverter.GetBytes(indexBufferSizes[i])); - ms.Write( new[] { mdlBlock.NumLods } ); - ms.Write( BitConverter.GetBytes( mdlBlock.IndexBufferStreamingEnabled ) ); - ms.Write( BitConverter.GetBytes( mdlBlock.EdgeGeometryEnabled ) ); - ms.Write( new byte[] { 0 } ); + ms.Write(new[] + { + mdlBlock.NumLods, + }); + ms.Write(BitConverter.GetBytes(mdlBlock.IndexBufferStreamingEnabled)); + ms.Write(BitConverter.GetBytes(mdlBlock.EdgeGeometryEnabled)); + ms.Write(new byte[] + { + 0, + }); } - private void ReadTextureFile( PenumbraFileResource resource, MemoryStream ms ) + private void ReadTextureFile(PenumbraFileResource resource, MemoryStream ms) { - if( resource.FileInfo!.BlockCount == 0 ) - { + if (resource.FileInfo!.BlockCount == 0) return; - } - var blocks = Reader.ReadStructures< LodBlock >( ( int )resource.FileInfo!.BlockCount ); + var blocks = Reader.ReadStructures((int)resource.FileInfo!.BlockCount); // if there is a mipmap header, the comp_offset // will not be 0 - var mipMapSize = blocks[ 0 ].CompressedOffset; - if( mipMapSize != 0 ) + var mipMapSize = blocks[0].CompressedOffset; + if (mipMapSize != 0) { var originalPos = BaseStream.Position; BaseStream.Position = resource.FileInfo.Offset + resource.FileInfo.HeaderSize; - ms.Write( Reader.ReadBytes( ( int )mipMapSize ) ); + ms.Write(Reader.ReadBytes((int)mipMapSize)); BaseStream.Position = originalPos; } // i is for texture blocks, j is 'data blocks'... - for( byte i = 0; i < blocks.Count; i++ ) + for (byte i = 0; i < blocks.Count; i++) { - if( blocks[ i ].CompressedSize == 0 ) + if (blocks[i].CompressedSize == 0) continue; // start from comp_offset - var runningBlockTotal = blocks[ i ].CompressedOffset + resource.FileInfo.Offset + resource.FileInfo.HeaderSize; - ReadFileBlock( runningBlockTotal, ms, true ); + var runningBlockTotal = blocks[i].CompressedOffset + resource.FileInfo.Offset + resource.FileInfo.HeaderSize; + ReadFileBlock(runningBlockTotal, ms, true); - for( var j = 1; j < blocks[ i ].BlockCount; j++ ) + for (var j = 1; j < blocks[i].BlockCount; j++) { - runningBlockTotal += ( uint )Reader.ReadInt16(); - ReadFileBlock( runningBlockTotal, ms, true ); + runningBlockTotal += (uint)Reader.ReadInt16(); + ReadFileBlock(runningBlockTotal, ms, true); } // unknown @@ -319,34 +295,32 @@ public class PenumbraSqPackStream : IDisposable } } - protected uint ReadFileBlock( MemoryStream dest, bool resetPosition = false ) - => ReadFileBlock( Reader.BaseStream.Position, dest, resetPosition ); + protected uint ReadFileBlock(MemoryStream dest, bool resetPosition = false) + => ReadFileBlock(Reader.BaseStream.Position, dest, resetPosition); - protected uint ReadFileBlock( long offset, MemoryStream dest, bool resetPosition = false ) + protected uint ReadFileBlock(long offset, MemoryStream dest, bool resetPosition = false) { var originalPosition = BaseStream.Position; BaseStream.Position = offset; - var blockHeader = Reader.ReadStructure< DatBlockHeader >(); + var blockHeader = Reader.ReadStructure(); // uncompressed block - if( blockHeader.CompressedSize == 32000 ) + if (blockHeader.CompressedSize == 32000) { - dest.Write( Reader.ReadBytes( ( int )blockHeader.UncompressedSize ) ); + dest.Write(Reader.ReadBytes((int)blockHeader.UncompressedSize)); } else { - var data = Reader.ReadBytes( ( int )blockHeader.CompressedSize ); + var data = Reader.ReadBytes((int)blockHeader.CompressedSize); - using var compressedStream = new MemoryStream( data ); - using var zlibStream = new DeflateStream( compressedStream, CompressionMode.Decompress ); - zlibStream.CopyTo( dest ); + using var compressedStream = new MemoryStream(data); + using var zlibStream = new DeflateStream(compressedStream, CompressionMode.Decompress); + zlibStream.CopyTo(dest); } - if( resetPosition ) - { + if (resetPosition) BaseStream.Position = originalPosition; - } return blockHeader.UncompressedSize; } @@ -390,7 +364,7 @@ public class PenumbraSqPackStream : IDisposable } } - [StructLayout( LayoutKind.Sequential )] + [StructLayout(LayoutKind.Sequential)] private struct DatBlockHeader { public uint Size; @@ -399,7 +373,7 @@ public class PenumbraSqPackStream : IDisposable public uint UncompressedSize; }; - [StructLayout( LayoutKind.Sequential )] + [StructLayout(LayoutKind.Sequential)] private struct LodBlock { public uint CompressedOffset; @@ -408,4 +382,4 @@ public class PenumbraSqPackStream : IDisposable public uint BlockOffset; public uint BlockCount; } -} \ No newline at end of file +} diff --git a/Penumbra/Util/PerformanceType.cs b/Penumbra/Util/PerformanceType.cs index c0ad766d..932072f0 100644 --- a/Penumbra/Util/PerformanceType.cs +++ b/Penumbra/Util/PerformanceType.cs @@ -1,5 +1,5 @@ global using StartTracker = OtterGui.Classes.StartTimeTracker; -global using PerformanceTracker = OtterGui.Classes.PerformanceTracker; +global using PerformanceTracker = OtterGui.Classes.PerformanceTracker; namespace Penumbra.Util;