diff --git a/Penumbra/Models/ModMeta.cs b/Penumbra/Models/ModMeta.cs index 9d1b869d..b5bb3113 100644 --- a/Penumbra/Models/ModMeta.cs +++ b/Penumbra/Models/ModMeta.cs @@ -13,6 +13,8 @@ namespace Penumbra.Models public string Website { get; set; } public List ChangedItems { get; set; } = new(); + + public Dictionary< string, string > FileSwaps { get; } = new(); public GroupInformation Groups { get; set; } = new(); } diff --git a/Penumbra/Mods/ModManager.cs b/Penumbra/Mods/ModManager.cs index 3ce17242..4ab04660 100644 --- a/Penumbra/Mods/ModManager.cs +++ b/Penumbra/Mods/ModManager.cs @@ -1,16 +1,15 @@ using System; using System.Collections.Generic; -using System.IO; -using System.Windows.Forms.VisualStyles; -using Penumbra.Models; -using Swan.Logging; +using System.IO; +using Penumbra.Models; namespace Penumbra.Mods { public class ModManager : IDisposable { private readonly Plugin _plugin; - public readonly Dictionary< string, FileInfo > ResolvedFiles = new(); + public readonly Dictionary< string, FileInfo > ResolvedFiles = new(); + public readonly Dictionary< string, string > SwappedFiles = new(); public ModCollection Mods { get; set; } @@ -106,7 +105,8 @@ namespace Penumbra.Mods public void CalculateEffectiveFileList() { - ResolvedFiles.Clear(); + ResolvedFiles.Clear(); + SwappedFiles.Clear(); var registeredFiles = new Dictionary< string, string >(); @@ -148,6 +148,20 @@ namespace Penumbra.Mods mod.AddConflict( modName, gamePath ); } } + } + + foreach( var swap in mod.Meta.FileSwaps ) + { + // just assume people put not fucked paths in here lol + if( !SwappedFiles.ContainsKey( swap.Value ) ) + { + SwappedFiles[ swap.Key.ToLowerInvariant() ] = swap.Value; + registeredFiles[ swap.Key ] = mod.Meta.Name; + } + else if( registeredFiles.TryGetValue( swap.Key, out var modName ) ) + { + mod.AddConflict( modName, swap.Key ); + } } } } @@ -180,12 +194,18 @@ namespace Penumbra.Mods return candidate; } - public string ResolveReplacementFilePath( string gameResourcePath ) + public string GetSwappedFilePath( string gameResourcePath ) + { + return SwappedFiles.TryGetValue( gameResourcePath, out var swappedPath ) ? swappedPath : null; + } + + public string ResolveSwappedOrReplacementFilePath( string gameResourcePath ) { gameResourcePath = gameResourcePath.ToLowerInvariant(); - - return GetCandidateForGameFile( gameResourcePath )?.FullName; + + return GetCandidateForGameFile( gameResourcePath )?.FullName ?? GetSwappedFilePath( gameResourcePath ); } + public void Dispose() { diff --git a/Penumbra/ResourceLoader.cs b/Penumbra/ResourceLoader.cs index 37b3a323..86cf2b44 100644 --- a/Penumbra/ResourceLoader.cs +++ b/Penumbra/ResourceLoader.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Runtime.InteropServices; using System.Text; @@ -129,7 +129,7 @@ namespace Penumbra PluginLog.Log( "[GetResourceHandler] {0}", gameFsPath ); } - var replacementPath = Plugin.ModManager.ResolveReplacementFilePath( gameFsPath ); + var replacementPath = Plugin.ModManager.ResolveSwappedOrReplacementFilePath( gameFsPath ); // path must be < 260 because statically defined array length :( if( replacementPath == null || replacementPath.Length >= 260 ) diff --git a/Penumbra/UI/SettingsInterface.cs b/Penumbra/UI/SettingsInterface.cs index ba0e5c1d..0aec8150 100644 --- a/Penumbra/UI/SettingsInterface.cs +++ b/Penumbra/UI/SettingsInterface.cs @@ -683,6 +683,24 @@ namespace Penumbra.UI ImGui.EndTabItem(); } + if( _selectedMod.Mod.Meta.FileSwaps.Any() ) + { + if( ImGui.BeginTabItem( "File Swaps" ) ) + { + ImGui.SetNextItemWidth( -1 ); + if( ImGui.ListBoxHeader( "##", AutoFillSize ) ) + { + foreach( var file in _selectedMod.Mod.Meta.FileSwaps ) + { + // todo: fucking gross alloc every frame * items + ImGui.Selectable( $"{file.Key} -> {file.Value}" ); + } + } + + ImGui.ListBoxFooter(); + ImGui.EndTabItem(); + } + } if( _selectedMod.Mod.FileConflicts.Any() ) { if( ImGui.BeginTabItem( "File Conflicts" ) )