Update for 6.0

This commit is contained in:
Ottermandias 2021-12-10 10:23:51 +01:00
parent 3bcd7a44da
commit 1d254e5856
7 changed files with 280 additions and 302 deletions

View file

@ -9,9 +9,9 @@ namespace Penumbra.GameData.Structs
[StructLayout( LayoutKind.Sequential, Pack = 1 )]
public class CharacterEquipment
{
public const int MainWeaponOffset = 0x0F08;
public const int OffWeaponOffset = 0x0F70;
public const int EquipmentOffset = 0x1040;
public const int MainWeaponOffset = 0x0C78;
public const int OffWeaponOffset = 0x0CE0;
public const int EquipmentOffset = 0xDB0;
public const int EquipmentSlots = 10;
public const int WeaponSlots = 2;

View file

@ -8,7 +8,7 @@ namespace Penumbra.PlayerWatch
{
public static class CharacterFactory
{
private static ConstructorInfo? _characterConstructor = null;
private static ConstructorInfo? _characterConstructor;
private static void Initialize()
{

View file

@ -1,81 +0,0 @@
using System;
using System.Reflection;
using System.Reflection.Emit;
namespace Penumbra.Extensions
{
public static class FuckedExtensions
{
private delegate ref TFieldType RefGet< in TObject, TFieldType >( TObject obj );
/// <summary>
/// Create a delegate which will return a zero-copy reference to a given field in a manner that's fucked tiers of quick and
/// fucked tiers of stupid, but hey, why not?
/// </summary>
/// <remarks>
/// The only thing that this can't do is inline, this always ends up as a call instruction because we're generating code at
/// runtime and need to jump to it. That said, this is still super quick and provides a convenient and type safe shim around
/// a primitive type
///
/// You can use the resultant <see cref="RefGet{TObject,TFieldType}"/> to access a ref to a field on an object without invoking any
/// unsafe code too.
/// </remarks>
/// <param name="fieldName">The name of the field to grab a reference to</param>
/// <typeparam name="TObject">The object that holds the field</typeparam>
/// <typeparam name="TField">The type of the underlying field</typeparam>
/// <returns>A delegate that will return a reference to a particular field - zero copy</returns>
/// <exception cref="MissingFieldException"></exception>
private static RefGet< TObject, TField > CreateRefGetter< TObject, TField >( string fieldName )
where TField : unmanaged
{
const BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
var fieldInfo = typeof( TObject ).GetField( fieldName, flags );
if( fieldInfo == null )
{
throw new MissingFieldException( typeof( TObject ).Name, fieldName );
}
var dm = new DynamicMethod(
$"__refget_{typeof( TObject ).Name}_{fieldInfo.Name}",
typeof( TField ).MakeByRefType(),
new[] { typeof( TObject ) },
typeof( TObject ),
true
);
var il = dm.GetILGenerator();
il.Emit( OpCodes.Ldarg_0 );
il.Emit( OpCodes.Ldflda, fieldInfo );
il.Emit( OpCodes.Ret );
return ( RefGet< TObject, TField > )dm.CreateDelegate( typeof( RefGet< TObject, TField > ) );
}
private static readonly RefGet< string, byte > StringRefGet = CreateRefGetter< string, byte >( "_firstChar" );
public static unsafe IntPtr UnsafePtr( this string str )
{
// nb: you can do it without __makeref but the code becomes way shittier because the way of getting the ptr
// is more fucked up so it's easier to just abuse __makeref
// but you can just use the StringRefGet func to get a `ref byte` too, though you'll probs want a better delegate so it's
// actually usable, lol
var fieldRef = __makeref( StringRefGet( str ) );
return *( IntPtr* )&fieldRef;
}
public static unsafe int UnsafeLength( this string str )
{
var fieldRef = __makeref( StringRefGet( str ) );
// c# strings are utf16 so we just multiply len by 2 to get the total byte count + 2 for null terminator (:D)
// very simple and intuitive
// this also maps to a defined structure, so you can just move the pointer backwards to read from the native string struct
// see: https://github.com/dotnet/coreclr/blob/master/src/vm/object.h#L897-L909
return *( int* )( *( IntPtr* )&fieldRef - 4 ) * 2 + 2;
}
}
}

View file

@ -11,8 +11,8 @@ using Penumbra.Structs;
using Penumbra.Util;
using FileMode = Penumbra.Structs.FileMode;
namespace Penumbra.Interop
{
namespace Penumbra.Interop;
public class ResourceLoader : IDisposable
{
public Penumbra Penumbra { get; set; }
@ -37,14 +37,34 @@ namespace Penumbra.Interop
public unsafe delegate void* GetResourceAsyncPrototype( IntPtr pFileManager, uint* pCategoryId, char* pResourceType
, uint* pResourceHash, char* pPath, void* pUnknown, bool isUnknown );
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate bool CheckFileStatePrototype( IntPtr unk1, ulong unk2 );
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate byte LoadTexFileExternPrototype( IntPtr resourceHandle, int unk1, IntPtr unk2, bool unk3, IntPtr unk4 );
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate byte LoadTexFileLocalPrototype( IntPtr resourceHandle, int unk1, IntPtr unk2, bool unk3 );
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate byte LoadMdlFileExternPrototype( IntPtr resourceHandle, IntPtr unk1, bool unk2, IntPtr unk3 );
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate byte LoadMdlFileLocalPrototype( IntPtr resourceHandle, IntPtr unk1, bool unk2 );
// Hooks
public Hook< GetResourceSyncPrototype >? GetResourceSyncHook { get; private set; }
public Hook< GetResourceAsyncPrototype >? GetResourceAsyncHook { get; private set; }
public Hook< ReadSqpackPrototype >? ReadSqpackHook { get; private set; }
public Hook< CheckFileStatePrototype >? CheckFileStateHook { get; private set; }
public Hook< LoadTexFileExternPrototype >? LoadTexFileExternHook { get; private set; }
public Hook< LoadMdlFileExternPrototype >? LoadMdlFileExternHook { get; private set; }
// Unmanaged functions
public ReadFilePrototype? ReadFile { get; private set; }
public CheckFileStatePrototype? CheckFileState { get; private set; }
public LoadTexFileLocalPrototype? LoadTexFileLocal { get; private set; }
public LoadMdlFileLocalPrototype? LoadMdlFileLocal { get; private set; }
public bool LogAllFiles = false;
public Regex? LogFileFilter = null;
@ -74,14 +94,46 @@ namespace Penumbra.Interop
Dalamud.SigScanner.ScanText( "E8 ?? ?? ?? 00 48 8B D8 EB ?? F0 FF 83 ?? ?? 00 00" );
GeneralUtil.PrintDebugAddress( "GetResourceAsync", getResourceAsyncAddress );
var checkFileStateAddress = Dalamud.SigScanner.ScanText( "E8 ?? ?? ?? ?? 48 85 c0 74 ?? 45 0f b6 ce 48 89 44 24" );
GeneralUtil.PrintDebugAddress( "CheckFileState", checkFileStateAddress );
var loadTexFileLocalAddress =
Dalamud.SigScanner.ScanText( "48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 30 49 8B F0 44 88 4C 24 20" );
GeneralUtil.PrintDebugAddress( "LoadTexFileLocal", loadTexFileLocalAddress );
var loadTexFileExternAddress =
Dalamud.SigScanner.ScanText( "E8 ?? ?? ?? ?? 0F B6 E8 48 8B CB E8" );
GeneralUtil.PrintDebugAddress( "LoadTexFileExtern", loadTexFileExternAddress );
var loadMdlFileLocalAddress =
Dalamud.SigScanner.ScanText( "40 55 53 56 57 41 56 41 57 48 8D 6C 24 D1 48 81 EC 98 00 00 00" );
GeneralUtil.PrintDebugAddress( "LoadMdlFileLocal", loadMdlFileLocalAddress );
var loadMdlFileExternAddress =
Dalamud.SigScanner.ScanText( "E8 ?? ?? ?? ?? EB 02 B0 F1" );
GeneralUtil.PrintDebugAddress( "LoadMdlFileExtern", loadMdlFileExternAddress );
ReadSqpackHook = new Hook< ReadSqpackPrototype >( readSqpackAddress, ReadSqpackHandler );
GetResourceSyncHook = new Hook< GetResourceSyncPrototype >( getResourceSyncAddress, GetResourceSyncHandler );
GetResourceAsyncHook = new Hook< GetResourceAsyncPrototype >( getResourceAsyncAddress, GetResourceAsyncHandler );
ReadFile = Marshal.GetDelegateForFunctionPointer< ReadFilePrototype >( readFileAddress );
LoadTexFileLocal = Marshal.GetDelegateForFunctionPointer< LoadTexFileLocalPrototype >( loadTexFileLocalAddress );
LoadMdlFileLocal = Marshal.GetDelegateForFunctionPointer< LoadMdlFileLocalPrototype >( loadMdlFileLocalAddress );
CheckFileStateHook = new Hook< CheckFileStatePrototype >( checkFileStateAddress, CheckFileStateDetour );
LoadTexFileExternHook = new Hook< LoadTexFileExternPrototype >( loadTexFileExternAddress, LoadTexFileExternDetour );
LoadMdlFileExternHook = new Hook< LoadMdlFileExternPrototype >( loadMdlFileExternAddress, LoadMdlFileExternDetour );
}
private static bool CheckFileStateDetour( IntPtr _, ulong _2 )
=> true;
private byte LoadTexFileExternDetour( IntPtr resourceHandle, int unk1, IntPtr unk2, bool unk3, IntPtr _ )
=> LoadTexFileLocal!.Invoke( resourceHandle, unk1, unk2, unk3 );
private byte LoadMdlFileExternDetour( IntPtr resourceHandle, IntPtr unk1, bool unk2, IntPtr _ )
=> LoadMdlFileLocal!.Invoke( resourceHandle, unk1, unk2 );
private unsafe void* GetResourceSyncHandler(
IntPtr pFileManager,
@ -234,7 +286,7 @@ namespace Penumbra.Interop
return;
}
if( ReadSqpackHook == null || GetResourceSyncHook == null || GetResourceAsyncHook == null )
if( ReadSqpackHook == null || GetResourceSyncHook == null || GetResourceAsyncHook == null || CheckFileStateHook == null || LoadTexFileExternHook == null || LoadMdlFileExternHook == null)
{
PluginLog.Error( "[GetResourceHandler] Could not activate hooks because at least one was not set." );
return;
@ -243,6 +295,9 @@ namespace Penumbra.Interop
ReadSqpackHook.Enable();
GetResourceSyncHook.Enable();
GetResourceAsyncHook.Enable();
CheckFileStateHook.Enable();
LoadTexFileExternHook.Enable();
LoadMdlFileExternHook.Enable();
IsEnabled = true;
}
@ -257,7 +312,9 @@ namespace Penumbra.Interop
ReadSqpackHook?.Disable();
GetResourceSyncHook?.Disable();
GetResourceAsyncHook?.Disable();
CheckFileStateHook?.Disable();
LoadTexFileExternHook?.Disable();
LoadMdlFileExternHook?.Disable();
IsEnabled = false;
}
@ -267,6 +324,8 @@ namespace Penumbra.Interop
ReadSqpackHook?.Dispose();
GetResourceSyncHook?.Dispose();
GetResourceAsyncHook?.Dispose();
}
CheckFileStateHook?.Dispose();
LoadTexFileExternHook?.Dispose();
LoadMdlFileExternHook?.Dispose();
}
}

View file

@ -7,7 +7,7 @@
"RepoUrl": "https://github.com/xivdev/Penumbra",
"ApplicableVersion": "any",
"Tags": [ "modding" ],
"DalamudApiLevel": 69420,
"DalamudApiLevel": 5,
"LoadPriority": 69420,
"IconUrl": "https://raw.githubusercontent.com/xivdev/Penumbra/master/images/icon.png"
}

View file

@ -94,7 +94,7 @@ public partial class SettingsInterface
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem );
var resourceHandler = *( ResourceManager** )( Dalamud.SigScanner.Module.BaseAddress + 0x1D93AC0 );
var resourceHandler = *( ResourceManager** )( Dalamud.SigScanner.Module.BaseAddress + 0x1E5B440 );
if( resourceHandler == null )
{