diff --git a/Penumbra/Interop/ResidentResourceManager.cs b/Penumbra/Interop/ResidentResourceManager.cs
index dbe49df1..8e75dcde 100644
--- a/Penumbra/Interop/ResidentResourceManager.cs
+++ b/Penumbra/Interop/ResidentResourceManager.cs
@@ -16,9 +16,9 @@ public unsafe class ResidentResourceManager
// A static pointer to the resident resource manager address.
[Signature( "0F 44 FE 48 8B 0D ?? ?? ?? ?? 48 85 C9 74 05", ScanType = ScanType.StaticAddress )]
- private readonly void** _residentResourceManagerAddress = null;
+ private readonly Structs.ResidentResourceManager** _residentResourceManagerAddress = null;
- public void* Address
+ public Structs.ResidentResourceManager* Address
=> *_residentResourceManagerAddress;
public ResidentResourceManager()
diff --git a/Penumbra/Interop/Resolver/PathResolver.Resolve.cs b/Penumbra/Interop/Resolver/PathResolver.Resolve.cs
index 77fba089..ce3ec0dd 100644
--- a/Penumbra/Interop/Resolver/PathResolver.Resolve.cs
+++ b/Penumbra/Interop/Resolver/PathResolver.Resolve.cs
@@ -107,6 +107,9 @@ public unsafe partial class PathResolver
? Penumbra.ModManager.Collections.DefaultCollection
: collection, path );
+ // Weapons have the characters DrawObject as a parent,
+ // but that may not be set yet when creating a new object, so we have to do the same detour
+ // as for Human DrawObjects that are just being created.
[MethodImpl( MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization )]
private IntPtr ResolveWeaponPathDetour( IntPtr drawObject, IntPtr path )
{
diff --git a/Penumbra/Interop/Structs/FileMode.cs b/Penumbra/Interop/Structs/FileMode.cs
index 21270176..13966e65 100644
--- a/Penumbra/Interop/Structs/FileMode.cs
+++ b/Penumbra/Interop/Structs/FileMode.cs
@@ -3,9 +3,9 @@ namespace Penumbra.Interop.Structs;
public enum FileMode : uint
{
LoadUnpackedResource = 0,
- LoadFileResource = 1, // Shit in My Games uses this
+ LoadFileResource = 1, // The config files in MyGames use this.
- // some shit here, the game does some jump if its < 0xA for other files for some reason but there's no impl, probs debug?
+ // Probably debug options only.
LoadIndexResource = 0xA, // load index/index2
LoadSqPackResource = 0xB,
}
\ No newline at end of file
diff --git a/Penumbra/Interop/Structs/ResidentResourceManager.cs b/Penumbra/Interop/Structs/ResidentResourceManager.cs
new file mode 100644
index 00000000..d5dd1715
--- /dev/null
+++ b/Penumbra/Interop/Structs/ResidentResourceManager.cs
@@ -0,0 +1,19 @@
+using System.Runtime.InteropServices;
+
+namespace Penumbra.Interop.Structs;
+
+[StructLayout(LayoutKind.Explicit)]
+public unsafe struct ResidentResourceManager
+{
+ [FieldOffset( 0x00 )]
+ public void** VTable;
+
+ [FieldOffset( 0x08 )]
+ public void** ResourceListVTable;
+
+ [FieldOffset( 0x14 )]
+ public uint NumResources;
+
+ [FieldOffset( 0x18 )]
+ public ResourceHandle** ResourceList;
+}
\ No newline at end of file
diff --git a/Penumbra/Penumbra.csproj b/Penumbra/Penumbra.csproj
index 84c1b98d..13a25cc0 100644
--- a/Penumbra/Penumbra.csproj
+++ b/Penumbra/Penumbra.csproj
@@ -79,8 +79,4 @@
Always
-
-
-
-
\ No newline at end of file
diff --git a/Penumbra/UI/MenuTabs/TabDebug.cs b/Penumbra/UI/MenuTabs/TabDebug.cs
index ab109e49..4aba0ee8 100644
--- a/Penumbra/UI/MenuTabs/TabDebug.cs
+++ b/Penumbra/UI/MenuTabs/TabDebug.cs
@@ -327,6 +327,36 @@ public partial class SettingsInterface
}
}
+
+ public unsafe void DrawDebugResidentResources()
+ {
+ if( !ImGui.CollapsingHeader( "Resident Resources##Debug" ) )
+ {
+ return;
+ }
+
+ if( Penumbra.ResidentResources.Address == null || Penumbra.ResidentResources.Address->NumResources == 0 )
+ {
+ return;
+ }
+
+ if( !ImGui.BeginTable( "##Resident ResourcesDebugList", 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit, -Vector2.UnitX ) )
+ {
+ return;
+ }
+
+ using var end = ImGuiRaii.DeferredEnd( ImGui.EndTable );
+
+ for( var i = 0; i < Penumbra.ResidentResources.Address->NumResources; ++i )
+ {
+ var resource = Penumbra.ResidentResources.Address->ResourceList[ i ];
+ ImGui.TableNextColumn();
+ ImGui.Text( $"0x{( ulong )resource:X}" );
+ ImGui.TableNextColumn();
+ ImGuiNative.igTextUnformatted( resource->FileName(), resource->FileName() + resource->FileNameLength );
+ }
+ }
+
private unsafe void DrawPathResolverDebug()
{
if( !ImGui.CollapsingHeader( "Path Resolver##Debug" ) )
@@ -404,6 +434,8 @@ public partial class SettingsInterface
ImGui.NewLine();
DrawDebugCharacterUtility();
ImGui.NewLine();
+ DrawDebugResidentResources();
+ ImGui.NewLine();
DrawDebugTabRedraw();
ImGui.NewLine();
DrawDebugTabIpc();
diff --git a/Penumbra/Util/RelPath.cs b/Penumbra/Util/RelPath.cs
deleted file mode 100644
index f4ce0021..00000000
--- a/Penumbra/Util/RelPath.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-using System;
-using System.IO;
-using System.Linq;
-using Penumbra.GameData.ByteString;
-using Penumbra.GameData.Util;
-
-namespace Penumbra.Util;
-
-public readonly struct RelPath : IComparable
-{
- public const int MaxRelPathLength = 256;
-
- private readonly string _path;
-
- private RelPath( string path, bool _ )
- => _path = path;
-
- private RelPath( string? path )
- {
- if( path != null && path.Length < MaxRelPathLength )
- {
- _path = Trim( ReplaceSlash( path ) );
- }
- else
- {
- _path = "";
- }
- }
-
- public RelPath( FullPath file, DirectoryInfo baseDir )
- => _path = CheckPre( file.FullName, baseDir ) ? ReplaceSlash( Trim( Substring( file.FullName, baseDir ) ) ) : string.Empty;
-
- public RelPath( FileInfo file, DirectoryInfo baseDir )
- => _path = CheckPre( file.FullName, baseDir ) ? Trim( Substring( file.FullName, baseDir ) ) : string.Empty;
-
- public RelPath( GamePath gamePath )
- => _path = ReplaceSlash( gamePath );
-
- public GamePath ToGamePath( int skipFolders = 0 )
- {
- string p = this;
- if( skipFolders > 0 )
- {
- p = string.Join( "/", p.Split( '\\' ).Skip( skipFolders ) );
- return GamePath.GenerateUncheckedLower( p );
- }
-
- return GamePath.GenerateUncheckedLower( p.Replace( '\\', '/' ) );
- }
-
- private static bool CheckPre( string file, DirectoryInfo baseDir )
- => file.StartsWith( baseDir.FullName ) && file.Length < MaxRelPathLength;
-
- private static string Substring( string file, DirectoryInfo baseDir )
- => file.Substring( baseDir.FullName.Length );
-
- private static string ReplaceSlash( string path )
- => path.Replace( '/', '\\' );
-
- private static string Trim( string path )
- => path.TrimStart( '\\' );
-
- public static implicit operator string( RelPath relPath )
- => relPath._path;
-
- public static explicit operator RelPath( string relPath )
- => new(relPath);
-
- public bool Empty
- => _path.Length == 0;
-
- public int CompareTo( object? rhs )
- {
- return rhs switch
- {
- string path => string.Compare( _path, path, StringComparison.InvariantCulture ),
- RelPath path => string.Compare( _path, path._path, StringComparison.InvariantCulture ),
- _ => -1,
- };
- }
-
- public override string ToString()
- => _path;
-}
\ No newline at end of file
diff --git a/Penumbra/Util/TempFile.cs b/Penumbra/Util/TempFile.cs
index 4e2e22ca..19e8b47e 100644
--- a/Penumbra/Util/TempFile.cs
+++ b/Penumbra/Util/TempFile.cs
@@ -12,7 +12,7 @@ public static class TempFile
{
var name = Path.GetRandomFileName();
var path = new FileInfo( Path.Combine( baseDir.FullName,
- suffix.Any() ? name.Substring( 0, name.LastIndexOf( '.' ) ) + suffix : name ) );
+ suffix.Length > 0 ? name[ ..name.LastIndexOf( '.' ) ] + suffix : name ) );
if( !path.Exists )
{
return path;
@@ -21,13 +21,4 @@ public static class TempFile
throw new IOException();
}
-
- public static FileInfo WriteNew( DirectoryInfo baseDir, byte[] data, string suffix = "" )
- {
- var fileName = TempFileName( baseDir, suffix );
- using var stream = fileName.OpenWrite();
- stream.Write( data, 0, data.Length );
- fileName.Refresh();
- return fileName;
- }
}
\ No newline at end of file