mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 10:17:22 +01:00
fix a crash on non-ascii file paths, sqpack file swapping
This commit is contained in:
parent
21758a8c85
commit
76269ba64a
6 changed files with 71 additions and 15 deletions
|
|
@ -1,3 +1,5 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Penumbra.Models
|
namespace Penumbra.Models
|
||||||
{
|
{
|
||||||
public class ModMeta
|
public class ModMeta
|
||||||
|
|
@ -5,5 +7,7 @@ namespace Penumbra.Models
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Author { get; set; }
|
public string Author { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
|
|
||||||
|
public Dictionary< string, string > FileSwaps { get; } = new();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,11 +7,10 @@ namespace Penumbra.Mods
|
||||||
public class ModManager
|
public class ModManager
|
||||||
{
|
{
|
||||||
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; }
|
public ModCollection Mods { get; set; }
|
||||||
|
|
||||||
public ResourceMod[] AvailableMods => Mods?.EnabledMods;
|
|
||||||
|
|
||||||
private DirectoryInfo _basePath;
|
private DirectoryInfo _basePath;
|
||||||
|
|
||||||
public void DiscoverMods()
|
public void DiscoverMods()
|
||||||
|
|
@ -81,6 +80,20 @@ namespace Penumbra.Mods
|
||||||
mod.AddConflict( modName, path );
|
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 )
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -13,7 +13,7 @@ namespace Penumbra.Mods
|
||||||
|
|
||||||
public List< FileInfo > ModFiles { get; } = new();
|
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()
|
public void RefreshModFiles()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -23,27 +23,27 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Dalamud">
|
<Reference Include="Dalamud">
|
||||||
<HintPath>$(DALAMUD_ROOT)\Dalamud.dll</HintPath>
|
|
||||||
<HintPath>..\libs\Dalamud.dll</HintPath>
|
<HintPath>..\libs\Dalamud.dll</HintPath>
|
||||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\Dalamud.dll</HintPath>
|
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\Dalamud.dll</HintPath>
|
||||||
|
<HintPath>$(DALAMUD_ROOT)\Dalamud.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="ImGui.NET">
|
<Reference Include="ImGui.NET">
|
||||||
<HintPath>$(DALAMUD_ROOT)\ImGui.NET.dll</HintPath>
|
|
||||||
<HintPath>..\libs\ImGui.NET.dll</HintPath>
|
<HintPath>..\libs\ImGui.NET.dll</HintPath>
|
||||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\ImGui.NET.dll</HintPath>
|
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\ImGui.NET.dll</HintPath>
|
||||||
|
<HintPath>$(DALAMUD_ROOT)\ImGui.NET.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="ImGuiScene">
|
<Reference Include="ImGuiScene">
|
||||||
<HintPath>$(DALAMUD_ROOT)\ImGuiScene.dll</HintPath>
|
|
||||||
<HintPath>..\libs\ImGuiScene.dll</HintPath>
|
<HintPath>..\libs\ImGuiScene.dll</HintPath>
|
||||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\ImGuiScene.dll</HintPath>
|
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\ImGuiScene.dll</HintPath>
|
||||||
|
<HintPath>$(DALAMUD_ROOT)\ImGuiScene.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Lumina">
|
<Reference Include="Lumina">
|
||||||
<HintPath>$(DALAMUD_ROOT)\Lumina.dll</HintPath>
|
|
||||||
<HintPath>..\libs\Lumina.dll</HintPath>
|
<HintPath>..\libs\Lumina.dll</HintPath>
|
||||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\Lumina.dll</HintPath>
|
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\Lumina.dll</HintPath>
|
||||||
|
<HintPath>$(DALAMUD_ROOT)\Lumina.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -158,23 +158,27 @@ namespace Penumbra
|
||||||
PluginLog.Log( "[GetResourceHandler] {0}", gameFsPath );
|
PluginLog.Log( "[GetResourceHandler] {0}", gameFsPath );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var candidate = Plugin.ModManager.GetCandidateForGameFile( 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 :(
|
// 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 );
|
return CallOriginalHandler( isSync, pFileManager, pCategoryId, pResourceType, pResourceHash, pPath, pUnknown, isUnknown );
|
||||||
}
|
}
|
||||||
|
|
||||||
var cleanPath = candidate.FullName.Replace( '\\', '/' );
|
var cleanPath = path.Replace( '\\', '/' );
|
||||||
var asciiPath = Encoding.ASCII.GetBytes( cleanPath );
|
var utfPath = Encoding.UTF8.GetBytes( cleanPath );
|
||||||
|
|
||||||
var bPath = stackalloc byte[asciiPath.Length + 1];
|
var bPath = stackalloc byte[utfPath.Length + 1];
|
||||||
Marshal.Copy( asciiPath, 0, new IntPtr( bPath ), asciiPath.Length );
|
Marshal.Copy( utfPath, 0, new IntPtr( bPath ), utfPath.Length );
|
||||||
pPath = ( char* )bPath;
|
pPath = ( char* )bPath;
|
||||||
|
|
||||||
Crc32.Init();
|
Crc32.Init();
|
||||||
Crc32.Update( asciiPath );
|
Crc32.Update( utfPath );
|
||||||
*pResourceHash = Crc32.Checksum;
|
*pResourceHash = Crc32.Checksum;
|
||||||
|
|
||||||
return CallOriginalHandler( isSync, pFileManager, pCategoryId, pResourceType, pResourceHash, pPath, pUnknown, isUnknown );
|
return CallOriginalHandler( isSync, pFileManager, pCategoryId, pResourceType, pResourceHash, pPath, pUnknown, isUnknown );
|
||||||
|
|
@ -198,7 +202,7 @@ namespace Penumbra
|
||||||
|
|
||||||
pFileDesc->FileMode = FileMode.LoadUnpackedResource;
|
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 );
|
Marshal.Copy( utfPath, 0, new IntPtr( &pFileDesc->UtfFileName ), utfPath.Length );
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -414,6 +414,25 @@ namespace Penumbra.UI
|
||||||
ImGui.EndTabItem();
|
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( _selectedMod.Mod.FileConflicts.Any() )
|
||||||
{
|
{
|
||||||
if( ImGui.BeginTabItem( "File Conflicts" ) )
|
if( ImGui.BeginTabItem( "File Conflicts" ) )
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue