Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Titan out of memory problem #105

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 36 additions & 5 deletions Penumbra.GameData/Util/GamePath.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.IO;
using Lumina.Misc;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

Expand All @@ -11,23 +12,47 @@ namespace Penumbra.GameData.Util

private readonly string _path;

private readonly ulong _crc64;

private GamePath( string path, bool _ )
=> _path = path;
{
_path = path;
_crc64 = CalculateCrc64( path );
}

public GamePath( string? path )
{
if( path != null && path.Length < MaxGamePathLength )
{
_path = Lower( Trim( ReplaceSlash( path ) ) );
_path = Lower( Trim( ReplaceSlash( path ) ) );
_crc64 = CalculateCrc64( path );
}
else
{
_path = "";
_path = "";
_crc64 = 0L;
}
}

public GamePath( FileInfo file, DirectoryInfo baseDir )
=> _path = CheckPre( file, baseDir ) ? Lower( Trim( ReplaceSlash( Substring( file, baseDir ) ) ) ) : "";
{
_path = CheckPre( file, baseDir ) ? Lower( Trim( ReplaceSlash( Substring( file, baseDir ) ) ) ) : "";
_crc64 = _path != "" ? CalculateCrc64( _path ) : 0L;
}

public GamePath( ulong crc64 )
{
_path = "";
_crc64 = crc64;
}

private static ulong CalculateCrc64( string path )
{
var lastSlash = path.LastIndexOf( '/' );
var folder = path[ ..lastSlash ];
var file = path[ (lastSlash+1).. ];
return (ulong)Crc32.Get( folder ) << 32 | Crc32.Get( file );
}

private static bool CheckPre( FileInfo file, DirectoryInfo baseDir )
=> file.FullName.StartsWith( baseDir.FullName ) && file.FullName.Length < MaxGamePathLength;
Expand Down Expand Up @@ -65,12 +90,18 @@ public string Filename()
return idx == -1 ? _path : idx == _path.Length - 1 ? "" : _path.Substring( idx + 1 );
}

public int CompareTo( GamePath rhs )
{
return (_path == "" || rhs._path == "") ? _crc64.CompareTo(rhs._crc64) :
string.Compare( _path, rhs._path, StringComparison.InvariantCulture );
}

public int CompareTo( object? rhs )
{
return rhs switch
{
string path => string.Compare( _path, path, StringComparison.InvariantCulture ),
GamePath path => string.Compare( _path, path._path, StringComparison.InvariantCulture ),
GamePath path => CompareTo( path ),
_ => -1,
};
}
Expand Down
30 changes: 23 additions & 7 deletions Penumbra/Interop/ResourceLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public class ResourceLoader : IDisposable

public Crc32 Crc32 { get; }

protected static readonly IntPtr FLAG_POINTER = new( 0xDEADBEEF );


// Delegate prototypes
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
Expand All @@ -38,7 +40,7 @@ public class ResourceLoader : IDisposable
, uint* pResourceHash, char* pPath, void* pUnknown, bool isUnknown );

[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate bool CheckFileStatePrototype( IntPtr unk1, ulong unk2 );
public delegate IntPtr CheckFileStatePrototype( IntPtr unk1, ulong unk2 );

[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate byte LoadTexFileExternPrototype( IntPtr resourceHandle, int unk1, IntPtr unk2, bool unk3, IntPtr unk4 );
Expand Down Expand Up @@ -126,14 +128,28 @@ public unsafe void Init()
LoadMdlFileExternHook = new Hook< LoadMdlFileExternPrototype >( loadMdlFileExternAddress, LoadMdlFileExternDetour );
}

private static bool CheckFileStateDetour( IntPtr _, ulong _2 )
=> true;
private IntPtr CheckFileStateDetour( IntPtr ptr, ulong crc64 )
{
var modManager = Service< ModManager >.Get();
var gamePath = new GamePath( crc64 );
var replacementPath = modManager.ResolveSwappedOrReplacementPath( gamePath );

return replacementPath == null ? CheckFileStateHook!.Original( ptr, crc64 ) : FLAG_POINTER;
}

private byte LoadTexFileExternDetour( IntPtr resourceHandle, int unk1, IntPtr unk2, bool unk3, IntPtr _ )
=> LoadTexFileLocal!.Invoke( resourceHandle, unk1, unk2, unk3 );
private byte LoadTexFileExternDetour( IntPtr resourceHandle, int unk1, IntPtr unk2, bool unk3, IntPtr ptr )
{
return ptr.Equals( FLAG_POINTER ) ?
LoadTexFileLocal!.Invoke( resourceHandle, unk1, unk2, unk3 ) :
LoadTexFileExternHook!.Original( resourceHandle, unk1, unk2, unk3, ptr );
}

private byte LoadMdlFileExternDetour( IntPtr resourceHandle, IntPtr unk1, bool unk2, IntPtr _ )
=> LoadMdlFileLocal!.Invoke( resourceHandle, unk1, unk2 );
private byte LoadMdlFileExternDetour( IntPtr resourceHandle, IntPtr unk1, bool unk2, IntPtr ptr )
{
return ptr.Equals( FLAG_POINTER ) ?
LoadMdlFileLocal!.Invoke( resourceHandle, unk1, unk2 ) :
LoadMdlFileExternHook!.Original( resourceHandle, unk1, unk2, ptr );
}

private unsafe void* GetResourceSyncHandler(
IntPtr pFileManager,
Expand Down