diff --git a/OtterGui b/OtterGui index 88bf2218..9ec5e2ad 160000 --- a/OtterGui +++ b/OtterGui @@ -1 +1 @@ -Subproject commit 88bf221852d4a1ac26f5ffbfb5e497220aef75c4 +Subproject commit 9ec5e2ad2f2d35d62c2ac7c300b914fffbda2191 diff --git a/Penumbra/Collections/ResolveData.cs b/Penumbra/Collections/ResolveData.cs index 6fb60d55..722675fd 100644 --- a/Penumbra/Collections/ResolveData.cs +++ b/Penumbra/Collections/ResolveData.cs @@ -1,5 +1,4 @@ using System; -using FFXIVClientStructs.FFXIV.Client.Game.Object; namespace Penumbra.Collections; diff --git a/Penumbra/Configuration.cs b/Penumbra/Configuration.cs index 7f2e7848..0e95a7f6 100644 --- a/Penumbra/Configuration.cs +++ b/Penumbra/Configuration.cs @@ -8,8 +8,10 @@ using Newtonsoft.Json; using OtterGui; using OtterGui.Classes; using OtterGui.Filesystem; +using OtterGui.Widgets; using Penumbra.Import; using Penumbra.Mods; +using Penumbra.UI; using Penumbra.UI.Classes; using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs; @@ -20,6 +22,8 @@ public partial class Configuration : IPluginConfiguration { public int Version { get; set; } = Constants.CurrentVersion; + public int LastSeenVersion { get; set; } = ConfigWindow.LastChangelogVersion; + public bool EnableMods { get; set; } = true; public string ModDirectory { get; set; } = string.Empty; diff --git a/Penumbra/Interop/Loader/ResourceLoader.Replacement.cs b/Penumbra/Interop/Loader/ResourceLoader.Replacement.cs index f14f19b5..afd18d2a 100644 --- a/Penumbra/Interop/Loader/ResourceLoader.Replacement.cs +++ b/Penumbra/Interop/Loader/ResourceLoader.Replacement.cs @@ -98,13 +98,8 @@ public unsafe partial class ResourceLoader return retUnmodified; } - // Replace the hash and path with the correct one for the replacement, - // but only for non-UI files. UI files can not reasonably be loaded multiple times at once, - // and seem to cause concurrency problems if multiple UI parts use the same resource for different use-cases. - if( *categoryId != ResourceCategory.Ui ) - { - *resourceHash = ComputeHash( resolvedPath.Value.InternalName, pGetResParams ); - } + // Replace the hash and path with the correct one for the replacement. + *resourceHash = ComputeHash( resolvedPath.Value.InternalName, pGetResParams ); path = resolvedPath.Value.InternalName.Path; var retModified = CallOriginalHandler( isSync, resourceManager, categoryId, resourceType, resourceHash, path, pGetResParams, isUnk ); @@ -154,7 +149,7 @@ public unsafe partial class ResourceLoader // We hook ReadSqPack to redirect rooted files to ReadFile. public delegate byte ReadSqPackPrototype( ResourceManager* resourceManager, SeFileDescriptor* pFileDesc, int priority, bool isSync ); - [Signature( "E8 ?? ?? ?? ?? EB 05 E8 ?? ?? ?? ?? 84 C0 0F 84 ?? 00 00 00 4C 8B C3", DetourName = nameof(ReadSqPackDetour) )] + [Signature( "E8 ?? ?? ?? ?? EB 05 E8 ?? ?? ?? ?? 84 C0 0F 84 ?? 00 00 00 4C 8B C3", DetourName = nameof( ReadSqPackDetour ) )] public Hook< ReadSqPackPrototype > ReadSqPackHook = null!; private byte ReadSqPackDetour( ResourceManager* resourceManager, SeFileDescriptor* fileDescriptor, int priority, bool isSync ) @@ -188,10 +183,10 @@ public unsafe partial class ResourceLoader var split = gamePath.Path.Split( ( byte )'|', 3, false ); fileDescriptor->ResourceHandle->FileNameData = split[ 2 ].Path; fileDescriptor->ResourceHandle->FileNameLength = split[ 2 ].Length; - - var funcFound = ResourceLoadCustomization.GetInvocationList() - .Any( f => ( ( ResourceLoadCustomizationDelegate )f ) - .Invoke( split[ 1 ], split[ 2 ], resourceManager, fileDescriptor, priority, isSync, out ret ) ); + var funcFound = fileDescriptor->ResourceHandle->Category != ResourceCategory.Ui + && ResourceLoadCustomization.GetInvocationList() + .Any( f => ( ( ResourceLoadCustomizationDelegate )f ) + .Invoke( split[ 1 ], split[ 2 ], resourceManager, fileDescriptor, priority, isSync, out ret ) ); if( !funcFound ) { @@ -227,8 +222,9 @@ public unsafe partial class ResourceLoader var fdPtr = ( char* )( fd + 0x21 ); for( var i = 0; i < gamePath.Length; ++i ) { - ( &fileDescriptor->Utf16FileName )[ i ] = ( char )gamePath.Path[ i ]; - fdPtr[ i ] = ( char )gamePath.Path[ i ]; + var c = ( char )gamePath.Path[ i ]; + ( &fileDescriptor->Utf16FileName )[ i ] = c; + fdPtr[ i ] = c; } ( &fileDescriptor->Utf16FileName )[ gamePath.Length ] = '\0'; diff --git a/Penumbra/Mods/Editor/Mod.Editor.Duplicates.cs b/Penumbra/Mods/Editor/Mod.Editor.Duplicates.cs index b5bd538c..486da507 100644 --- a/Penumbra/Mods/Editor/Mod.Editor.Duplicates.cs +++ b/Penumbra/Mods/Editor/Mod.Editor.Duplicates.cs @@ -124,6 +124,12 @@ public partial class Mod var lastSize = -1L; foreach( var file in files ) { + // Skip any UI Files because deduplication causes weird crashes for those. + if( file.SubModUsage.Any( f => f.Item2.Path.StartsWith( 'u', 'i', '/' ) ) ) + { + continue; + } + if( DuplicatesFinished ) { return; @@ -262,7 +268,6 @@ public partial class Mod } - // Deduplicate a mod simply by its directory without any confirmation or waiting time. internal static void DeduplicateMod( DirectoryInfo modDirectory ) { diff --git a/Penumbra/Penumbra.cs b/Penumbra/Penumbra.cs index 0e2310f2..e4081ba0 100644 --- a/Penumbra/Penumbra.cs +++ b/Penumbra/Penumbra.cs @@ -159,6 +159,7 @@ public class Penumbra : IDalamudPlugin system = new WindowSystem( Name ); system.AddWindow( _configWindow ); system.AddWindow( cfg.ModEditPopup ); + system.AddWindow( ConfigWindow.CreateChangelog() ); Dalamud.PluginInterface.UiBuilder.OpenConfigUi += cfg.Toggle; } diff --git a/Penumbra/UI/ConfigWindow.Changelog.cs b/Penumbra/UI/ConfigWindow.Changelog.cs new file mode 100644 index 00000000..c9dae1c2 --- /dev/null +++ b/Penumbra/UI/ConfigWindow.Changelog.cs @@ -0,0 +1,31 @@ +using Lumina.Excel.GeneratedSheets; +using OtterGui.Widgets; + +namespace Penumbra.UI; + +public partial class ConfigWindow +{ + public const int LastChangelogVersion = 0; + + public static Changelog CreateChangelog() + { + var ret = new Changelog( "Penumbra Changelog", () => Penumbra.Config.LastSeenVersion, version => + { + Penumbra.Config.LastSeenVersion = version; + Penumbra.Config.Save(); + } ); + + Add5_7_0( ret ); + + return ret; + } + + private static void Add5_7_0( Changelog log ) + => log.NextVersion( "Version 0.5.7.0" ) + .RegisterEntry( "Added a Changelog!" ) + .RegisterEntry( "Files in the UI category will no longer be deduplicated for the moment." ) + .RegisterHighlight( "If you experience UI-related crashes, please re-import your UI mods.", 1 ) + .RegisterEntry( "This is a temporary fix against those not-yet fully understood crashes and may be reworked later.", 1 ) + .RegisterEntry( "Fixed assigned collections not working correctly on adventurer plates." ) + .RegisterEntry( "Added some additional functionality for Mare Synchronos." ); +} \ No newline at end of file diff --git a/Penumbra/UI/ConfigWindow.SettingsTab.cs b/Penumbra/UI/ConfigWindow.SettingsTab.cs index b256b04a..242e33b4 100644 --- a/Penumbra/UI/ConfigWindow.SettingsTab.cs +++ b/Penumbra/UI/ConfigWindow.SettingsTab.cs @@ -359,6 +359,12 @@ public partial class ConfigWindow Penumbra.Config.TutorialStep = 0; Penumbra.Config.Save(); } + + ImGui.SetCursorPos( new Vector2( xPos, 4 * ImGui.GetFrameHeightWithSpacing() ) ); + if( ImGui.Button( "Show Changelogs", new Vector2( width, 0 ) ) ) + { + Penumbra.Config.LastSeenVersion = 0; + } } } } \ No newline at end of file