fix a crash on non-ascii file paths, sqpack file swapping

This commit is contained in:
Adam 2020-12-26 11:37:50 +11:00
parent 21758a8c85
commit 76269ba64a
6 changed files with 71 additions and 15 deletions

View file

@ -1,3 +1,5 @@
using System.Collections.Generic;
namespace Penumbra.Models
{
public class ModMeta
@ -5,5 +7,7 @@ namespace Penumbra.Models
public string Name { get; set; }
public string Author { get; set; }
public string Description { get; set; }
public Dictionary< string, string > FileSwaps { get; } = new();
}
}

View file

@ -7,11 +7,10 @@ namespace Penumbra.Mods
public class ModManager
{
public readonly Dictionary< string, FileInfo > ResolvedFiles = new();
public readonly Dictionary< string, string > SwappedFiles = new();
public ModCollection Mods { get; set; }
public ResourceMod[] AvailableMods => Mods?.EnabledMods;
private DirectoryInfo _basePath;
public void DiscoverMods()
@ -81,6 +80,20 @@ namespace Penumbra.Mods
mod.AddConflict( modName, path );
}
}
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 ] = swap.Value;
registeredFiles[ swap.Key ] = mod.Meta.Name;
}
else if( registeredFiles.TryGetValue( swap.Key, out var modName ) )
{
mod.AddConflict( modName, swap.Key );
}
}
}
}
@ -99,7 +112,23 @@ namespace Penumbra.Mods
public FileInfo GetCandidateForGameFile( string resourcePath )
{
return ResolvedFiles.TryGetValue( resourcePath.ToLowerInvariant(), out var fileInfo ) ? fileInfo : null;
var val = ResolvedFiles.TryGetValue( resourcePath.ToLowerInvariant(), out var candidate );
if( !val )
{
return null;
}
if( candidate.FullName.Length >= 260 || !candidate.Exists )
{
return null;
}
return candidate;
}
public string GetSwappedFilePath( string originalPath )
{
return SwappedFiles.TryGetValue( originalPath, out var swappedPath ) ? swappedPath : null;
}
}
}

View file

@ -13,7 +13,7 @@ namespace Penumbra.Mods
public List< FileInfo > ModFiles { get; } = new();
public Dictionary< string, List< string > > FileConflicts { get; set; } = new();
public Dictionary< string, List< string > > FileConflicts { get; } = new();
public void RefreshModFiles()
{

View file

@ -23,27 +23,27 @@
<ItemGroup>
<Reference Include="Dalamud">
<HintPath>$(DALAMUD_ROOT)\Dalamud.dll</HintPath>
<HintPath>..\libs\Dalamud.dll</HintPath>
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\Dalamud.dll</HintPath>
<HintPath>$(DALAMUD_ROOT)\Dalamud.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="ImGui.NET">
<HintPath>$(DALAMUD_ROOT)\ImGui.NET.dll</HintPath>
<HintPath>..\libs\ImGui.NET.dll</HintPath>
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\ImGui.NET.dll</HintPath>
<HintPath>$(DALAMUD_ROOT)\ImGui.NET.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="ImGuiScene">
<HintPath>$(DALAMUD_ROOT)\ImGuiScene.dll</HintPath>
<HintPath>..\libs\ImGuiScene.dll</HintPath>
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\ImGuiScene.dll</HintPath>
<HintPath>$(DALAMUD_ROOT)\ImGuiScene.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Lumina">
<HintPath>$(DALAMUD_ROOT)\Lumina.dll</HintPath>
<HintPath>..\libs\Lumina.dll</HintPath>
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\Lumina.dll</HintPath>
<HintPath>$(DALAMUD_ROOT)\Lumina.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>

View file

@ -158,23 +158,27 @@ namespace Penumbra
PluginLog.Log( "[GetResourceHandler] {0}", gameFsPath );
}
var candidate = Plugin.ModManager.GetCandidateForGameFile( gameFsPath );
var swappedFilePath = Plugin.ModManager.GetSwappedFilePath( gameFsPath );
var path = candidate?.FullName ?? swappedFilePath;
// path must be < 260 because statically defined array length :(
if( candidate == null || candidate.FullName.Length >= 260 || !candidate.Exists )
if( path == null || path.Length < 260 )
{
return CallOriginalHandler( isSync, pFileManager, pCategoryId, pResourceType, pResourceHash, pPath, pUnknown, isUnknown );
}
var cleanPath = candidate.FullName.Replace( '\\', '/' );
var asciiPath = Encoding.ASCII.GetBytes( cleanPath );
var cleanPath = path.Replace( '\\', '/' );
var utfPath = Encoding.UTF8.GetBytes( cleanPath );
var bPath = stackalloc byte[asciiPath.Length + 1];
Marshal.Copy( asciiPath, 0, new IntPtr( bPath ), asciiPath.Length );
var bPath = stackalloc byte[utfPath.Length + 1];
Marshal.Copy( utfPath, 0, new IntPtr( bPath ), utfPath.Length );
pPath = ( char* )bPath;
Crc32.Init();
Crc32.Update( asciiPath );
Crc32.Update( utfPath );
*pResourceHash = Crc32.Checksum;
return CallOriginalHandler( isSync, pFileManager, pCategoryId, pResourceType, pResourceHash, pPath, pUnknown, isUnknown );
@ -198,7 +202,7 @@ namespace Penumbra
pFileDesc->FileMode = FileMode.LoadUnpackedResource;
var utfPath = Encoding.Unicode.GetBytes( gameFsPath );
var utfPath = Encoding.UTF8.GetBytes( gameFsPath );
Marshal.Copy( utfPath, 0, new IntPtr( &pFileDesc->UtfFileName ), utfPath.Length );

View file

@ -414,6 +414,25 @@ 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" ) )