diff --git a/CommonLibF4/cmake/sourcelist.cmake b/CommonLibF4/cmake/sourcelist.cmake index 4b4cfe8c..5a86976c 100644 --- a/CommonLibF4/cmake/sourcelist.cmake +++ b/CommonLibF4/cmake/sourcelist.cmake @@ -43,6 +43,7 @@ set(SOURCES include/RE/Bethesda/BSFixedString.h include/RE/Bethesda/BSGeometry.h include/RE/Bethesda/BSGraphics.h + include/RE/Bethesda/BSGraphicsUtility.h include/RE/Bethesda/BSHavok.h include/RE/Bethesda/BSInputDeviceManager.h include/RE/Bethesda/BSInputEventReceiver.h @@ -155,6 +156,7 @@ set(SOURCES include/RE/Bethesda/BSTextureStreamer.h include/RE/Bethesda/BSThread.h include/RE/Bethesda/BSTimer.h + include/RE/Bethesda/BSUtilities.h include/RE/Bethesda/BSVisit.h include/RE/Bethesda/CELLJobs.h include/RE/Bethesda/CRC.h @@ -315,11 +317,15 @@ set(SOURCES include/RE/Scaleform/GFx/GFx_Loader.h include/RE/Scaleform/GFx/GFx_Log.h include/RE/Scaleform/GFx/GFx_Player.h + include/RE/Scaleform/GFx/GFx_PlayerImpl.h + include/RE/Scaleform/GFx/GFx_PlayerStats.h include/RE/Scaleform/GFx/GFx_Resource.h + include/RE/Scaleform/GFx/GFx_Stats.h include/RE/Scaleform/GFx/GFx_Types.h include/RE/Scaleform/Kernel/SF_AllocInfo.h include/RE/Scaleform/Kernel/SF_Allocator.h include/RE/Scaleform/Kernel/SF_Array.h + include/RE/Scaleform/Kernel/SF_ArrayPaged.h include/RE/Scaleform/Kernel/SF_Atomic.h include/RE/Scaleform/Kernel/SF_List.h include/RE/Scaleform/Kernel/SF_Log.h @@ -330,6 +336,7 @@ set(SOURCES include/RE/Scaleform/Kernel/SF_SysAlloc.h include/RE/Scaleform/Kernel/SF_System.h include/RE/Scaleform/Kernel/SF_Threads.h + include/RE/Scaleform/Kernel/SF_Types.h include/RE/Scaleform/Render/Render_Color.h include/RE/Scaleform/Render/Render_Constants.h include/RE/Scaleform/Render/Render_Containers.h @@ -337,13 +344,16 @@ set(SOURCES include/RE/Scaleform/Render/Render_Matrix2x4.h include/RE/Scaleform/Render/Render_Matrix3x4.h include/RE/Scaleform/Render/Render_Matrix4x4.h + include/RE/Scaleform/Render/Render_ScreenToWorld.h include/RE/Scaleform/Render/Render_ThreadCommandQueue.h include/RE/Scaleform/Render/Render_TreeNode.h + include/RE/Scaleform/Render/Render_TreeShape.h include/RE/Scaleform/Render/Render_Types2D.h include/RE/Scaleform/Render/Render_Viewport.h include/RE/VTABLE_IDs.h include/RE/msvc/memory.h include/RE/msvc/typeinfo.h + include/REL/IAT.h include/REL/ID.h include/REL/IDDB.h include/REL/Module.h @@ -421,6 +431,7 @@ set(SOURCES src/RE/NetImmerse/NiPoint3.cpp src/RE/NetImmerse/NiRect.cpp src/RE/Scaleform/GFx/GFx_Player.cpp + src/REL/IAT.cpp src/REL/IDDB.cpp src/REL/Module.cpp src/REL/Relocation.cpp diff --git a/CommonLibF4/include/RE/Bethesda/BSFixedString.h b/CommonLibF4/include/RE/Bethesda/BSFixedString.h index eca22314..81ba4145 100644 --- a/CommonLibF4/include/RE/Bethesda/BSFixedString.h +++ b/CommonLibF4/include/RE/Bethesda/BSFixedString.h @@ -323,3 +323,13 @@ namespace RE }; static_assert(std::is_empty_v); } + +template +struct std::formatter, CharT> : formatter +{ + template + constexpr auto format(const RE::detail::BSFixedString& a_version, FormatContext& a_ctx) const + { + return formatter::format(a_version.c_str(), a_ctx); + } +}; diff --git a/CommonLibF4/include/RE/Bethesda/BSGeometry.h b/CommonLibF4/include/RE/Bethesda/BSGeometry.h index 61a09bc5..e49e9205 100644 --- a/CommonLibF4/include/RE/Bethesda/BSGeometry.h +++ b/CommonLibF4/include/RE/Bethesda/BSGeometry.h @@ -52,4 +52,36 @@ namespace RE bool registered; // 159 }; static_assert(sizeof(BSGeometry) == 0x160); + + class __declspec(novtable) BSTriShape : + public BSGeometry // 000 + { + public: + static constexpr auto RTTI{ RTTI::BSTriShape }; + static constexpr auto VTABLE{ VTABLE::BSTriShape }; + static constexpr auto Ni_RTTI{ Ni_RTTI::BSTriShape }; + + BSTriShape(); + ~BSTriShape() override; // 00 + + // override (BSGeometry) + const NiRTTI* GetRTTI() const override // 02 + { + REL::Relocation rtti{ BSTriShape::Ni_RTTI }; + return rtti.get(); + } + + BSTriShape* IsTriShape() override { return this; } // 0A + NiObject* CreateClone(NiCloningProcess& a_cloneData) override; // 1A + void LoadBinary(NiStream& a_stream) override; // 1B + void LinkObject(NiStream& a_stream) override; // 1C - { BSGeometry::LinkObject(a_stream); } + bool RegisterStreamables(NiStream& a_stream) override; // 1D - { return BSGeometry::RegisterStreamables(a_stream); } + void SaveBinary(NiStream& a_stream) override; // 1E + bool IsEqual(NiObject* a_object) override; // 1F - { return false; } + + // members + std::uint32_t numTriangles; // 160 + std::uint16_t numVertices; // 164 + }; + static_assert(sizeof(BSTriShape) == 0x170); } diff --git a/CommonLibF4/include/RE/Bethesda/BSGraphics.h b/CommonLibF4/include/RE/Bethesda/BSGraphics.h index deb0b6e4..643c1b4a 100644 --- a/CommonLibF4/include/RE/Bethesda/BSGraphics.h +++ b/CommonLibF4/include/RE/Bethesda/BSGraphics.h @@ -8,20 +8,7 @@ #include "RE/NetImmerse/NiSmartPointer.h" #include "RE/NetImmerse/NiTexture.h" -struct ID3D11Buffer; -struct ID3D11ComputeShader; -struct ID3D11DepthStencilView; -struct ID3D11Device; -struct ID3D11DeviceContext; -struct ID3D11DomainShader; -struct ID3D11HullShader; -struct ID3D11PixelShader; -struct ID3D11RenderTargetView; -struct ID3D11ShaderResourceView; -struct ID3D11Texture2D; -struct ID3D11UnorderedAccessView; -struct ID3D11VertexShader; -struct IDXGISwapChain; +#include "REX/W32/D3D11.h" namespace RE { @@ -54,7 +41,6 @@ namespace RE enum class Format; enum class TextureAddressMode; - class RendererShadowState; class Texture; enum class MultiSampleLevel @@ -84,25 +70,33 @@ namespace RE { public: // members - ID3D11Buffer* buffer; // 00 - void* data; // 08 - Buffer* next; // 10 - ID3D11ShaderResourceView* shaderResource; // 18 - ID3D11UnorderedAccessView* unorderedAccess; // 20 - BSEventFlag* requestEventToWait; // 28 - std::uint32_t maxDataSize; // 30 - std::uint32_t dataSize; // 34 - std::uint32_t refCount; // 38 - BSTAtomicValue SRAcquire; // 3C - BSTAtomicValue UAVAcquire; // 40 - BSTAtomicValue pendingRequests; // 44 - std::uint32_t dataOffset; // 48 - bool invalidCpuData; // 4C - bool heapAllocated; // 4D - volatile bool pendingCopy; // 4E + REX::W32::ID3D11Buffer* buffer; // 00 + void* data; // 08 + Buffer* next; // 10 + REX::W32::ID3D11ShaderResourceView* shaderResource; // 18 + REX::W32::ID3D11UnorderedAccessView* unorderedAccess; // 20 + BSEventFlag* requestEventToWait; // 28 + std::uint32_t maxDataSize; // 30 + std::uint32_t dataSize; // 34 + std::uint32_t refCount; // 38 + BSTAtomicValue SRAcquire; // 3C + BSTAtomicValue UAVAcquire; // 40 + BSTAtomicValue pendingRequests; // 44 + std::uint32_t dataOffset; // 48 + bool invalidCpuData; // 4C + bool heapAllocated; // 4D + volatile bool pendingCopy; // 4E }; static_assert(sizeof(Buffer) == 0x50); + struct VertexBuffer : public Buffer + {}; + static_assert(sizeof(VertexBuffer) == 0x50); + + struct IndexBuffer : public Buffer + {}; + static_assert(sizeof(IndexBuffer) == 0x50); + struct TextureHeader { public: @@ -120,9 +114,9 @@ namespace RE { public: // members - ID3D11Buffer* buffer{ nullptr }; // 00 - float* data{ nullptr }; // 08 - bool dataIsCPUWorkBuffer{ false }; // 10 + REX::W32::ID3D11Buffer* buffer{ nullptr }; // 00 + float* data{ nullptr }; // 08 + bool dataIsCPUWorkBuffer{ false }; // 10 }; static_assert(sizeof(ConstantGroup) == 0x18); @@ -130,12 +124,12 @@ namespace RE { public: // members - std::uint32_t id{ 0 }; // 00 - ID3D11ComputeShader* shader{ nullptr }; // 08 - std::uint32_t byteCodeSize{ 0 }; // 10 - BSGraphics::ConstantGroup constantBuffers[3]; // 18 - std::uint64_t shaderDesc{ 0 }; // 60 - std::int8_t constantTable[32]{ 0 }; // 68 + std::uint32_t id{ 0 }; // 00 + REX::W32::ID3D11ComputeShader* shader{ nullptr }; // 08 + std::uint32_t byteCodeSize{ 0 }; // 10 + BSGraphics::ConstantGroup constantBuffers[3]; // 18 + std::uint64_t shaderDesc{ 0 }; // 60 + std::int8_t constantTable[32]{ 0 }; // 68 }; static_assert(sizeof(ComputeShader) == 0x88); @@ -144,7 +138,7 @@ namespace RE public: // members std::uint32_t id{ 0 }; // 00 - ID3D11DomainShader* shader{ nullptr }; // 08 + REX::W32::ID3D11DomainShader* shader{ nullptr }; // 08 std::uint32_t byteCodeSize{ 0 }; // 10 BSGraphics::ConstantGroup constantBuffers[3]{ 0 }; // 18 std::uint64_t shaderDesc{ 0 }; // 60 @@ -156,12 +150,12 @@ namespace RE { public: // members - std::uint32_t id{ 0 }; // 00 - ID3D11HullShader* shader{ nullptr }; // 08 - std::uint32_t byteCodeSize{ 0 }; // 10 - BSGraphics::ConstantGroup constantBuffers[3]; // 18 - std::uint64_t shaderDesc{ 0 }; // 60 - std::int8_t constantTable[32]{ 0 }; // 68 + std::uint32_t id{ 0 }; // 00 + REX::W32::ID3D11HullShader* shader{ nullptr }; // 08 + std::uint32_t byteCodeSize{ 0 }; // 10 + BSGraphics::ConstantGroup constantBuffers[3]; // 18 + std::uint64_t shaderDesc{ 0 }; // 60 + std::int8_t constantTable[32]{ 0 }; // 68 }; static_assert(sizeof(HullShader) == 0x88); @@ -169,10 +163,10 @@ namespace RE { public: // members - std::uint32_t id{ 0 }; // 00 - ID3D11PixelShader* shader{ nullptr }; // 08 - BSGraphics::ConstantGroup constantBuffers[3]; // 10 - std::int8_t constantTable[32]{ 0 }; // 58 + std::uint32_t id{ 0 }; // 00 + REX::W32::ID3D11PixelShader* shader{ nullptr }; // 08 + BSGraphics::ConstantGroup constantBuffers[3]; // 10 + std::int8_t constantTable[32]{ 0 }; // 58 }; static_assert(sizeof(PixelShader) == 0x78); @@ -180,12 +174,12 @@ namespace RE { public: // members - std::uint32_t id{ 0 }; // 00 - ID3D11VertexShader* shader{ nullptr }; // 08 - std::uint32_t byteCodeSize{ 0 }; // 10 - BSGraphics::ConstantGroup constantBuffers[3]; // 18 - std::uint64_t shaderDesc{ 0 }; // 60 - std::int8_t constantTable[32]{ 0 }; // 68 + std::uint32_t id{ 0 }; // 00 + REX::W32::ID3D11VertexShader* shader{ nullptr }; // 08 + std::uint32_t byteCodeSize{ 0 }; // 10 + BSGraphics::ConstantGroup constantBuffers[3]; // 18 + std::uint64_t shaderDesc{ 0 }; // 60 + std::int8_t constantTable[32]{ 0 }; // 68 }; static_assert(sizeof(VertexShader) == 0x88); @@ -193,9 +187,9 @@ namespace RE { public: // members - ID3D11Texture2D* texture; // 00 - ID3D11RenderTargetView* rtView[6]; // 08 - ID3D11ShaderResourceView* srView; // 38 + REX::W32::ID3D11Texture2D* texture; // 00 + REX::W32::ID3D11RenderTargetView* rtView[6]; // 08 + REX::W32::ID3D11ShaderResourceView* srView; // 38 }; static_assert(sizeof(CubeMapRenderTarget) == 0x40); @@ -203,13 +197,13 @@ namespace RE { public: // members - ID3D11Texture2D* texture; // 00 - ID3D11DepthStencilView* dsView[4]; // 08 - ID3D11DepthStencilView* dsViewReadOnlyDepth[4]; // 28 - ID3D11DepthStencilView* dsViewReadOnlyStencil[4]; // 48 - ID3D11DepthStencilView* dsViewReadOnlyDepthStencil[4]; // 68 - ID3D11ShaderResourceView* srViewDepth; // 88 - ID3D11ShaderResourceView* srViewStencil; // 90 + REX::W32::ID3D11Texture2D* texture; // 00 + REX::W32::ID3D11DepthStencilView* dsView[4]; // 08 + REX::W32::ID3D11DepthStencilView* dsViewReadOnlyDepth[4]; // 28 + REX::W32::ID3D11DepthStencilView* dsViewReadOnlyStencil[4]; // 48 + REX::W32::ID3D11DepthStencilView* dsViewReadOnlyDepthStencil[4]; // 68 + REX::W32::ID3D11ShaderResourceView* srViewDepth; // 88 + REX::W32::ID3D11ShaderResourceView* srViewStencil; // 90 }; static_assert(sizeof(DepthStencilTarget) == 0x98); @@ -217,28 +211,35 @@ namespace RE { public: // members - ID3D11Texture2D* texture; // 00 - ID3D11Texture2D* copyTexture; // 08 - ID3D11RenderTargetView* rtView; // 10 - ID3D11ShaderResourceView* srView; // 18 - ID3D11ShaderResourceView* copySRView; // 20 - ID3D11UnorderedAccessView* uaView; // 28 + REX::W32::ID3D11Texture2D* texture; // 00 + REX::W32::ID3D11Texture2D* copyTexture; // 08 + REX::W32::ID3D11RenderTargetView* rtView; // 10 + REX::W32::ID3D11ShaderResourceView* srView; // 18 + REX::W32::ID3D11ShaderResourceView* copySRView; // 20 + REX::W32::ID3D11UnorderedAccessView* uaView; // 28 }; static_assert(sizeof(RenderTarget) == 0x30); class RendererWindow { public: - void* hwnd; + REX::W32::HWND hwnd; std::int32_t windowX; std::int32_t windowY; std::int32_t windowWidth; std::int32_t windowHeight; - IDXGISwapChain* swapChain; + REX::W32::IDXGISwapChain* swapChain; RenderTarget swapChainRenderTarget; }; static_assert(sizeof(RendererWindow) == 0x50); + class alignas(0x10) RendererShadowState + { + public: + std::byte pad[0x910]; // 000 + }; + static_assert(sizeof(RendererShadowState) == 0x910); + class RendererData { public: @@ -265,8 +266,8 @@ namespace RE std::uint32_t newWidth; // 0038 std::uint32_t newHeight; // 003C std::uint32_t presentInterval; // 0040 - ID3D11Device* device; // 0048 - ID3D11DeviceContext* context; // 0050 + REX::W32::ID3D11Device* device; // 0048 + REX::W32::ID3D11DeviceContext* context; // 0050 RendererWindow renderWindow[32]; // 0058 RenderTarget renderTargets[101]; // 0A58 DepthStencilTarget depthStencilTargets[13]; // 1D48 @@ -303,6 +304,50 @@ namespace RE }; static_assert(sizeof(Renderer) == 0x25D0); + class Context + { + public: + REX::W32::ID3D11DeviceContext* deferredContext; // 0000 + REX::W32::ID3D11Buffer* shaderConstantBuffer[541]; // 0008 + REX::W32::ID3D11Buffer* vertexShaderConstantBufferTechnique[20]; // 10F0 + REX::W32::ID3D11Buffer* vertexShaderConstantBufferMaterial[10]; // 1190 + REX::W32::ID3D11Buffer* vertexShaderConstantBufferGeometry[28]; // 11E0 + REX::W32::ID3D11Buffer* hullShaderConstantBufferTechnique[20]; // 12C0 + REX::W32::ID3D11Buffer* hullShaderConstantBufferMaterial[10]; // 1360 + REX::W32::ID3D11Buffer* hullShaderConstantBufferGeometry[20]; // 13B0 + REX::W32::ID3D11Buffer* domainShaderConstantBufferTechnique[20]; // 1450 + REX::W32::ID3D11Buffer* domainShaderConstantBufferMaterial[10]; // 14F0 + REX::W32::ID3D11Buffer* domainShaderConstantBufferGeometry[20]; // 1540 + REX::W32::ID3D11Buffer* pixelShaderConstantBufferTechnique[36]; // 15E0 + REX::W32::ID3D11Buffer* pixelShaderConstantBufferMaterial[20]; // 1700 + REX::W32::ID3D11Buffer* pixelShaderConstantBufferGeometry[40]; // 17A0 + REX::W32::ID3D11Buffer* computeShaderConstantBufferTechnique[20]; // 18E0 + REX::W32::ID3D11Buffer* computeShaderConstantBufferMaterial[20]; // 1980 + REX::W32::ID3D11Buffer* computeShaderConstantBufferGeometry[34]; // 1A20 + REX::W32::ID3D11Buffer* alphaTestConstantBuffer; // 1B30 + REX::W32::ID3D11Buffer* perFrameConstantBuffer; // 1B38 + REX::W32::ID3D11Buffer* computeConstantBuffer; // 1B40 + REX::W32::ID3D11Buffer* instanceTransformConstantBuffer; // 1B48 + ConstantGroup miscConstantGroup; // 1B50 + RendererShadowState shadowState; // 1B70 + RendererShadowState lastDrawCallShadowState; // 2480 + REX::W32::ID3D11Buffer* dynamicVertexBuffer[8]; // 2D90 + REX::W32::ID3D11Query* dynamicVertexBufferAvailQuery[8]; // 2DD0 + std::int32_t dynamicVertexBufferAvail[8]; // 2E10 + std::uint32_t currentDynamicVertexBuffer; // 2E30 + std::uint32_t currentDynamicVertexBufferOffset; // 2E34 + REX::W32::ID3D11Buffer* sharedParticleIndexBuffer; // 2E38 + REX::W32::ID3D11Buffer* sharedParticleStaticBuffer; // 2E40 + ConstantGroup vertexConstantBuffersA[3]; // 2E48 + ConstantGroup pixelConstantBuffersA[3]; // 2E90 + ConstantGroup domainConstantBuffersA[3]; // 2ED8 + ConstantGroup hullConstantBuffersA[3]; // 2F20 + ConstantGroup computeConstantBuffersA[3]; // 2F68 + BSTHashMap inputLayoutMap; // 2FB0 + REX::W32::ID3D11InputLayout* particleShaderInputLayout; // 2FE0 + }; + static_assert(sizeof(Context) == 0x2FF0); + struct Vertex { enum Attribute : std::uint8_t @@ -353,10 +398,12 @@ namespace RE { return ((desc >> 44) & a_flag) != 0; } + void SetFlag(Vertex::Flags a_flag) { desc |= (static_cast(a_flag) << 44); } + void ClearFlag(Vertex::Flags a_flag) { desc &= ~(static_cast(a_flag) << 44); @@ -366,6 +413,7 @@ namespace RE { return (desc >> (4 * static_cast(a_attribute) + 2)) & 0x3C; } + void SetAttributeOffset(Vertex::Attribute a_attribute, std::uint32_t a_offset) { if (a_attribute != Vertex::Attribute::VA_POSITION) { @@ -375,6 +423,7 @@ namespace RE desc = lhs | rhs; } } + void ClearAttributeOffsets() { desc &= Vertex::Masks::DESC_MASK_OFFSET; @@ -384,6 +433,7 @@ namespace RE { return static_cast((desc & Vertex::Masks::DESC_MASK_OFFSET) >> 44); } + void SetFlags(Vertex::Flags a_flags) { desc |= (static_cast(a_flags) << 44) | (desc & Vertex::Masks::DESC_MASK_FLAGS); @@ -394,7 +444,6 @@ namespace RE return (desc & 0xF) * 4; } - private: // members std::uint64_t desc; // 00 }; @@ -402,10 +451,12 @@ namespace RE struct TriShape { - VertexDesc vertexDesc; - Buffer* buffer08; - Buffer* buffer10; + VertexDesc vertexDesc; // 00 + VertexBuffer* vertexBuffer; // 08 + IndexBuffer* indexBuffer; // 10 + std::uint32_t uiRefCount; // 18 }; + static_assert(sizeof(TriShape) == 0x20); struct FogStateType { diff --git a/CommonLibF4/include/RE/Bethesda/BSGraphicsUtility.h b/CommonLibF4/include/RE/Bethesda/BSGraphicsUtility.h new file mode 100644 index 00000000..b207685d --- /dev/null +++ b/CommonLibF4/include/RE/Bethesda/BSGraphicsUtility.h @@ -0,0 +1,74 @@ +#pragma once + +namespace RE +{ + class NiPoint2; + class NiPoint3; + class NiColorA; +} + +namespace RE::BSGraphics::Utility +{ + inline void ConvertHALFToNiPoint3Stream(const std::uint16_t* a_src, NiPoint3* a_dst, std::uint32_t a_count, std::uint32_t a_stride) + { + using func_t = decltype(&ConvertHALFToNiPoint3Stream); + static REL::Relocation func{ REL::ID(2277113) }; + func(a_src, a_dst, a_count, a_stride); + } + + inline void ConvertNiPoint3ToHALFStream(const NiPoint3* a_src, std::uint16_t* a_dst, std::uint32_t a_count) + { + using func_t = decltype(&ConvertNiPoint3ToHALFStream); + static REL::Relocation func{ REL::ID(2277114) }; + func(a_src, a_dst, a_count); + } + + inline std::uint64_t PackVertexData( + std::uint32_t a_numVertices, + NiPoint3* a_positions, + NiPoint2* a_texCoords0, + NiColorA* a_texCoords1, + NiPoint3* a_normals, + NiPoint3* a_binormals, + NiPoint3* a_tangents, + NiColorA* a_colors, + NiColorA* a_skinBoneWeights, + std::uint8_t* a_skinBoneIndices, + NiColorA* a_landscapeData1, + NiColorA* a_landscapeData2, + float* a_eyeData, + void* a_buffer, + std::uint32_t* a_bufferSize, + std::uint16_t* a_vertexMap, + std::uint32_t a_dynamicFlags, + std::uint16_t* a_tangentXBuffer, + std::uint32_t a_tangentXBufferStride) + { + using func_t = decltype(&PackVertexData); + static REL::Relocation func{ REL::ID(2277106) }; + return func(a_numVertices, a_positions, a_texCoords0, a_texCoords1, a_normals, a_binormals, a_tangents, a_colors, a_skinBoneWeights, a_skinBoneIndices, a_landscapeData1, a_landscapeData2, a_eyeData, a_buffer, a_bufferSize, a_vertexMap, a_dynamicFlags, a_tangentXBuffer, a_tangentXBufferStride); + + } + + inline void UnpackVertexData( + const std::uint8_t* a_vertices, + const std::uint16_t a_index, + const std::uint64_t a_vertexDesc, + NiPoint3* a_position, + NiPoint2* a_texCoord0, + NiPoint2* a_texCoord1, + NiPoint3* a_normal, + NiPoint3* a_binormal, + NiPoint3* a_tangent, + NiColorA* a_color, + NiColorA* a_skinBoneWeights, + std::uint8_t* a_boneIndex0, + std::uint8_t* a_boneIndex1, + std::uint8_t* a_boneIndex2, + std::uint8_t* a_boneIndex3) + { + using func_t = decltype(&UnpackVertexData); + static REL::Relocation func{ REL::ID(2277129) }; + func(a_vertices, a_index, a_vertexDesc, a_position, a_texCoord0, a_texCoord1, a_normal, a_binormal, a_tangent, a_color, a_skinBoneWeights, a_boneIndex0, a_boneIndex1, a_boneIndex2, a_boneIndex3); + } +} diff --git a/CommonLibF4/include/RE/Bethesda/BSUtilities.h b/CommonLibF4/include/RE/Bethesda/BSUtilities.h new file mode 100644 index 00000000..9c4781e2 --- /dev/null +++ b/CommonLibF4/include/RE/Bethesda/BSUtilities.h @@ -0,0 +1,32 @@ +#pragma once + +#include "RE/Bethesda/BSFixedString.h" + +namespace RE +{ + class NiAVObject; +} + +namespace RE::BSUtilities +{ + inline std::uint16_t ConvertFloatToHalf(float a_value) + { + using func_t = decltype(&ConvertFloatToHalf); + static REL::Relocation func{ REL::ID(2212098) }; + return func(a_value); + } + + inline float ConvertHalfToFloat(std::uint16_t a_value) + { + using func_t = decltype(&ConvertHalfToFloat); + static REL::Relocation func{ REL::ID(2195843) }; + return func(a_value); + } + + inline NiAVObject* GetObjectByName(NiAVObject* a_root, const BSFixedString& a_name, bool a_tryInternal, bool a_dontAttach) + { + using func_t = decltype(&GetObjectByName); + static REL::Relocation func{ REL::ID(843650) }; + return func(a_root, a_name, a_tryInternal, a_dontAttach); + } +} diff --git a/CommonLibF4/include/RE/Bethesda/Main.h b/CommonLibF4/include/RE/Bethesda/Main.h index 28675116..a6a3cdc0 100644 --- a/CommonLibF4/include/RE/Bethesda/Main.h +++ b/CommonLibF4/include/RE/Bethesda/Main.h @@ -56,7 +56,7 @@ namespace RE bool reloadContent; // 29 bool freezeTime; // 2A bool freezeNextFrame; // 2B - void* hwnd; // 30 + REX::W32::HWND hwnd; // 30 void* instance; // 38 std::uint32_t threadID; // 40 ScrapHeap packedTaskHeap; // 48 diff --git a/CommonLibF4/include/RE/Bethesda/Utilities.h b/CommonLibF4/include/RE/Bethesda/Utilities.h index 0be37ccf..254090fa 100644 --- a/CommonLibF4/include/RE/Bethesda/Utilities.h +++ b/CommonLibF4/include/RE/Bethesda/Utilities.h @@ -9,16 +9,6 @@ namespace RE { - namespace BSUtilities - { - inline NiAVObject* GetObjectByName(NiAVObject* a_root, const BSFixedString& a_name, bool a_tryInternal, bool a_dontAttach) - { - using func_t = decltype(&GetObjectByName); - REL::Relocation func{ REL::ID(843650) }; - return func(a_root, a_name, a_tryInternal, a_dontAttach); - } - } - namespace CombatUtilities { inline bool CalculateProjectileLOS( diff --git a/CommonLibF4/include/RE/Fallout.h b/CommonLibF4/include/RE/Fallout.h index 311670f3..f7ef767b 100644 --- a/CommonLibF4/include/RE/Fallout.h +++ b/CommonLibF4/include/RE/Fallout.h @@ -39,6 +39,7 @@ #include "RE/Bethesda/BSFixedString.h" #include "RE/Bethesda/BSGeometry.h" #include "RE/Bethesda/BSGraphics.h" +#include "RE/Bethesda/BSGraphicsUtility.h" #include "RE/Bethesda/BSHavok.h" #include "RE/Bethesda/BSInputDeviceManager.h" #include "RE/Bethesda/BSInputEventReceiver.h" @@ -151,6 +152,7 @@ #include "RE/Bethesda/BSTextureStreamer.h" #include "RE/Bethesda/BSThread.h" #include "RE/Bethesda/BSTimer.h" +#include "RE/Bethesda/BSUtilities.h" #include "RE/Bethesda/BSVisit.h" #include "RE/Bethesda/CELLJobs.h" #include "RE/Bethesda/CRC.h" @@ -308,11 +310,15 @@ #include "RE/Scaleform/GFx/GFx_Loader.h" #include "RE/Scaleform/GFx/GFx_Log.h" #include "RE/Scaleform/GFx/GFx_Player.h" +#include "RE/Scaleform/GFx/GFx_PlayerImpl.h" +#include "RE/Scaleform/GFx/GFx_PlayerStats.h" #include "RE/Scaleform/GFx/GFx_Resource.h" +#include "RE/Scaleform/GFx/GFx_Stats.h" #include "RE/Scaleform/GFx/GFx_Types.h" #include "RE/Scaleform/Kernel/SF_AllocInfo.h" #include "RE/Scaleform/Kernel/SF_Allocator.h" #include "RE/Scaleform/Kernel/SF_Array.h" +#include "RE/Scaleform/Kernel/SF_ArrayPaged.h" #include "RE/Scaleform/Kernel/SF_Atomic.h" #include "RE/Scaleform/Kernel/SF_List.h" #include "RE/Scaleform/Kernel/SF_Log.h" @@ -323,6 +329,7 @@ #include "RE/Scaleform/Kernel/SF_SysAlloc.h" #include "RE/Scaleform/Kernel/SF_System.h" #include "RE/Scaleform/Kernel/SF_Threads.h" +#include "RE/Scaleform/Kernel/SF_Types.h" #include "RE/Scaleform/Render/Render_Color.h" #include "RE/Scaleform/Render/Render_Constants.h" #include "RE/Scaleform/Render/Render_Containers.h" @@ -330,7 +337,9 @@ #include "RE/Scaleform/Render/Render_Matrix2x4.h" #include "RE/Scaleform/Render/Render_Matrix3x4.h" #include "RE/Scaleform/Render/Render_Matrix4x4.h" +#include "RE/Scaleform/Render/Render_ScreenToWorld.h" #include "RE/Scaleform/Render/Render_ThreadCommandQueue.h" #include "RE/Scaleform/Render/Render_TreeNode.h" +#include "RE/Scaleform/Render/Render_TreeShape.h" #include "RE/Scaleform/Render/Render_Types2D.h" #include "RE/Scaleform/Render/Render_Viewport.h" diff --git a/CommonLibF4/include/RE/Scaleform/GFx/GFx_AS3.h b/CommonLibF4/include/RE/Scaleform/GFx/GFx_AS3.h index 46a2dfad..e4ecff20 100644 --- a/CommonLibF4/include/RE/Scaleform/GFx/GFx_AS3.h +++ b/CommonLibF4/include/RE/Scaleform/GFx/GFx_AS3.h @@ -3,7 +3,7 @@ #include "RE/Scaleform/GFx/GFx_ASMovieRootBase.h" #include "RE/Scaleform/GFx/GFx_ASString.h" #include "RE/Scaleform/Kernel/SF_Allocator.h" -#include "RE/Scaleform/Kernel/SF_Array.h" +#include "RE/Scaleform/Kernel/SF_ArrayPaged.h" #include "RE/Scaleform/Kernel/SF_Memory.h" namespace RE::Scaleform diff --git a/CommonLibF4/include/RE/Scaleform/GFx/GFx_ASString.h b/CommonLibF4/include/RE/Scaleform/GFx/GFx_ASString.h index 43bc0c1c..7b6fa39d 100644 --- a/CommonLibF4/include/RE/Scaleform/GFx/GFx_ASString.h +++ b/CommonLibF4/include/RE/Scaleform/GFx/GFx_ASString.h @@ -70,9 +70,9 @@ namespace RE::Scaleform::GFx { public: // members - Scaleform::GFx::ASStringNodeHolder builtins[STAT]; // 00 - Scaleform::GFx::ASStringManager* stringManager; // ?? - const char** staticStrings; // ??+08 + ASStringNodeHolder builtins[STAT]; // 00 + ASStringManager* stringManager; // ?? + const char** staticStrings; // ??+08 }; static_assert(sizeof(ASStringBuiltinManagerT) == 0x218); } diff --git a/CommonLibF4/include/RE/Scaleform/GFx/GFx_Loader.h b/CommonLibF4/include/RE/Scaleform/GFx/GFx_Loader.h index a6411755..5c541c79 100644 --- a/CommonLibF4/include/RE/Scaleform/GFx/GFx_Loader.h +++ b/CommonLibF4/include/RE/Scaleform/GFx/GFx_Loader.h @@ -3,6 +3,7 @@ #include "RE/Scaleform/GFx/GFx_Resource.h" #include "RE/Scaleform/Kernel/SF_RefCount.h" #include "RE/Scaleform/Kernel/SF_System.h" +#include "RE/Scaleform/Kernel/SF_Types.h" namespace RE::Scaleform::GFx { @@ -57,41 +58,91 @@ namespace RE::Scaleform::GFx kAS3Support }; - [[nodiscard]] constexpr StateType GetStateType() const noexcept { return *sType; } + State(StateType a_type = StateType::kNone) : + sType(a_type) + {} + + [[nodiscard]] constexpr StateType GetStateType() const noexcept { return sType; } protected: // members - stl::enumeration sType; // 10 + StateType sType; // 10 }; static_assert(sizeof(State) == 0x18); + class __declspec(novtable) Translator : + public State + { + public: + enum class WordWrappingType : std::uint32_t + { + kDefault = 0, + kAsian = 1 << 0, + kProhibition = 1 << 1, + kNoHangulWrap = 1 << 2, + kHyphenation = 1 << 3, + kCustom = 0x80 + }; + + Translator() : + State(StateType::kTranslator) + {} + + explicit Translator(Flags a_wwMode) : + State(StateType::kTranslator), wwMode(a_wwMode) + {} + + // members + Flags wwMode; // 18 + }; + static_assert(sizeof(Translator) == 0x20); + class __declspec(novtable) ActionControl : public State // 00 { public: enum class ActionControlFlags : std::uint32_t { - Action_Verbose = 0x01, - Action_ErrorSuppress = 0x02, - Action_LogRootFilenames = 0x04, - Action_LogChildFilenames = 0x08, - Action_LogAllFilenames = 0x04 | 0x08, - Action_LongFilenames = 0x10 + kVerbose = 0x01, + kErrorSuppress = 0x02, + kLogRootFilenames = 0x04, + kLogChildFilenames = 0x08, + kLogAllFilenames = 0x04 | 0x08, + kLongFilenames = 0x10 }; + ActionControl(Flags a_actionFlags = ActionControlFlags::kLogChildFilenames) : + State(StateType::kActionControl), actionFlags(a_actionFlags) + {} + // members - stl::enumeration actionFlags; // 18 + Flags actionFlags; // 18 }; static_assert(sizeof(ActionControl) == 0x20); - class __declspec(novtable) Translator : - public State + class __declspec(novtable) UserEventHandler : + public State // 00 { public: - // members - std::uint32_t mode; //18 + UserEventHandler() : + State(StateType::kUserEventHandler) + {} + + virtual void HandleEvent(class Movie* pmovie, const class Event& event) = 0; }; - static_assert(sizeof(Translator) == 0x20); + static_assert(sizeof(UserEventHandler) == 0x18); + + class __declspec(novtable) FSCommandHandler : + public State // 00 + { + public: + FSCommandHandler() : + State(StateType::kFSCommandHandler) + {} + + virtual void HandleEvent(class Movie* pmovie, const class Event& event) = 0; + }; + static_assert(sizeof(FSCommandHandler) == 0x18); class __declspec(novtable) StateBag : public FileTypeConstants // 00 @@ -141,11 +192,11 @@ namespace RE::Scaleform::GFx }; // members - stl::enumeration format; // 00 - const char* prefix; // 08 - const char* swfName; // 10 - std::uint16_t version; // 18 - stl::enumeration exportFlags; // 1C + Flags format; // 00 + const char* prefix; // 08 + const char* swfName; // 10 + std::uint16_t version; // 18 + Flags exportFlags; // 1C }; static_assert(sizeof(ExporterInfo) == 0x20); @@ -175,7 +226,7 @@ namespace RE::Scaleform::GFx // add virtual bool CheckTagLoader(std::int32_t a_tagType) const; // 04 - [[nodiscard]] MovieDef* CreateMovie(const char* a_filename, LoadConstants a_loadConstants = LoadConstants::kAll, std::size_t a_memoryArena = 0) + [[nodiscard]] MovieDef* CreateMovie(const char* a_filename, Flags a_loadConstants = LoadConstants::kAll, std::size_t a_memoryArena = 0) { using func_t = decltype(&Loader::CreateMovie); REL::Relocation func{ REL::ID(912291) }; @@ -183,9 +234,9 @@ namespace RE::Scaleform::GFx } // members - LoaderImpl* impl; // 08 - ResourceLib* strongResourceLib; // 10 - stl::enumeration defLoadFlags; // 18 + LoaderImpl* impl; // 08 + ResourceLib* strongResourceLib; // 10 + Flags defLoadFlags; // 18 }; static_assert(sizeof(Loader) == 0x20); diff --git a/CommonLibF4/include/RE/Scaleform/GFx/GFx_Player.h b/CommonLibF4/include/RE/Scaleform/GFx/GFx_Player.h index 1168c00d..80429d39 100644 --- a/CommonLibF4/include/RE/Scaleform/GFx/GFx_Player.h +++ b/CommonLibF4/include/RE/Scaleform/GFx/GFx_Player.h @@ -2,6 +2,7 @@ #include "RE/Scaleform/GFx/GFx_Loader.h" #include "RE/Scaleform/GFx/GFx_Log.h" +#include "RE/Scaleform/GFx/GFx_PlayerStats.h" #include "RE/Scaleform/GFx/GFx_Types.h" #include "RE/Scaleform/Kernel/SF_RefCount.h" #include "RE/Scaleform/Render/Render_Constants.h" @@ -12,9 +13,9 @@ namespace RE::Scaleform::GFx { class ASMovieRootBase; - class InteractiveObject; class EventId; class FunctionHandler; + class InteractiveObject; class MemoryContext; class Movie; class MovieDef; @@ -282,6 +283,237 @@ namespace RE::Scaleform::GFx }; static_assert(sizeof(ValueUnion) == 0x8); + class DisplayInfo + { + public: + enum class SetFlags : std::uint16_t + { + kX = 0x01, + kY = 0x02, + kRotation = 0x04, + kXScale = 0x08, + kYScale = 0x10, + kAlpha = 0x20, + kVisible = 0x40, + kZ = 0x80, + kXRotation = 0x100, + kYRotation = 0x200, + kZScale = 0x400, + kFOV = 0x800, + kProjMatrix3D = 0x1000, + kViewMatrix3D = 0x2000, + kEdgeAAMode = 0x4000, + }; + + DisplayInfo() = default; + + double GetX() const + { + assert(varsSet.any(SetFlags::kX)); + return x; + } + + double GetY() const + { + assert(varsSet.any(SetFlags::kY)); + return y; + } + + double GetZ() const + { + assert(varsSet.any(SetFlags::kZ)); + return z; + } + + double GetXScale() const + { + assert(varsSet.any(SetFlags::kXScale)); + return xScale; + } + + double GetYScale() const + { + assert(varsSet.any(SetFlags::kYScale)); + return yScale; + } + + double GetZScale() const + { + assert(varsSet.any(SetFlags::kZScale)); + return zScale; + } + + double GetRotation() const + { + assert(varsSet.any(SetFlags::kRotation)); + return rotation; + } + + double GetXRotation() const + { + assert(varsSet.any(SetFlags::kXRotation)); + return xRotation; + } + + double GetYRotation() const + { + assert(varsSet.any(SetFlags::kYRotation)); + return yRotation; + } + + double GetAlpha() const + { + assert(varsSet.any(SetFlags::kAlpha)); + return alpha; + } + + bool GetVisible() const + { + assert(varsSet.any(SetFlags::kVisible)); + return visible; + } + + double GetFOV() const + { + assert(varsSet.any(SetFlags::kFOV)); + return fov; + } + + const Matrix3F* GetViewMatrix3D() const + { + return varsSet.any(SetFlags::kViewMatrix3D) ? &viewMatrix3D : nullptr; + } + + const Matrix4F* GetProjectionMatrix3D() const + { + return varsSet.any(SetFlags::kProjMatrix3D) ? &projectionMatrix3D : nullptr; + } + + Render::EdgeAAMode GetEdgeAAMode() const + { + assert(varsSet.any(SetFlags::kEdgeAAMode)); + return edgeAAMode; + } + + void SetX(double a_x) + { + varsSet.set(SetFlags::kX); + x = a_x; + } + + void SetY(double a_y) + { + varsSet.set(SetFlags::kY); + y = a_y; + } + + void SetZ(double a_z) + { + varsSet.set(SetFlags::kZ); + z = a_z; + } + + void SetXScale(double a_xScale) + { + varsSet.set(SetFlags::kXScale); + xScale = a_xScale; + } + + void SetYScale(double a_yScale) + { + varsSet.set(SetFlags::kYScale); + yScale = a_yScale; + } + + void SetZScale(double a_zScale) + { + varsSet.set(SetFlags::kZScale); + zScale = a_zScale; + } + + void SetRotation(double a_rotation) + { + varsSet.set(SetFlags::kRotation); + rotation = a_rotation; + } + + void SetXRotation(double a_xRotation) + { + varsSet.set(SetFlags::kXRotation); + xRotation = a_xRotation; + } + + void SetYRotation(double a_yRotation) + { + varsSet.set(SetFlags::kYRotation); + yRotation = a_yRotation; + } + + void SetAlpha(double a_alpha) + { + varsSet.set(SetFlags::kAlpha); + alpha = a_alpha; + } + + void SetVisible(bool a_visible) + { + varsSet.set(SetFlags::kVisible); + visible = a_visible; + } + + void SetFOV(double a_fov) + { + varsSet.set(SetFlags::kFOV); + fov = a_fov; + } + + void SetViewMatrix3D(const Matrix3F* a_matrix) + { + if (a_matrix) { + varsSet.set(SetFlags::kViewMatrix3D); + viewMatrix3D = *a_matrix; + } else { + varsSet.reset(SetFlags::kViewMatrix3D); + } + } + + void SetProjectionMatrix3D(const Matrix4F* a_matrix) + { + if (a_matrix) { + varsSet.set(SetFlags::kProjMatrix3D); + projectionMatrix3D = *a_matrix; + } else { + varsSet.reset(SetFlags::kProjMatrix3D); + } + } + + void SetEdgeAAMode(Render::EdgeAAMode a_mode) + { + varsSet.set(SetFlags::kEdgeAAMode); + edgeAAMode = a_mode; + } + + private: + // members + double x; + double y; + double rotation; + double xScale; + double yScale; + double alpha; + double z; + double xRotation; + double yRotation; + double zScale; + double fov; + alignas(16) Render::Matrix3x4 viewMatrix3D; + Render::Matrix4x4 projectionMatrix3D; + Render::EdgeAAMode edgeAAMode; + Flags varsSet{}; + bool visible; + }; + static_assert(sizeof(DisplayInfo) == 0xE0); + class __declspec(novtable) ObjectInterface : public NewOverrideBase<327> { @@ -379,6 +611,13 @@ namespace RE::Scaleform::GFx return func(this, a_data, a_visitor, a_isDObj); } + bool GetDisplayInfo(void* a_data, DisplayInfo* a_info) const + { + using func_t = decltype(&ObjectInterface::GetDisplayInfo); + REL::Relocation func{ REL::ID(2285873) }; + return func(this, a_data, a_info); + } + // members MovieImpl* movieRoot; // 08 }; @@ -732,6 +971,12 @@ namespace RE::Scaleform::GFx return RemoveElements(0); } + bool GetDisplayInfo(DisplayInfo* a_info) const + { + assert(IsDisplayObject()); + return _objectInterface->GetDisplayInfo(_value.data, a_info); + } + [[nodiscard]] Movie* GetMovie() const { assert(_objectInterface && _objectInterface->movieRoot); @@ -796,6 +1041,51 @@ namespace RE::Scaleform::GFx }; static_assert(sizeof(FunctionHandler) == 0x10); + class __declspec(novtable) ExternalInterface : + public State // 00 + { + public: + ExternalInterface() : + State(StateType::kExternalInterface) + {} + + virtual ~ExternalInterface() = default; // 00 + + // add + virtual void Callback(Movie* a_movieView, const char* a_methodName, const Value* a_args, std::uint32_t a_numArgs) = 0; // 01 + }; + static_assert(sizeof(ExternalInterface) == 0x18); + + class __declspec(novtable) MultitouchInterface : + public State // 00 + { + public: + enum class MultitouchInputMode : std::int32_t + { + kNone = 0, + kTouchPoint = 0x1, + kGesture = 0x2, + kMixed = (kTouchPoint | kGesture) + }; + + enum GestureMask : std::int32_t + { + kMTG_None = 0, + kMTG_Pan = 0x1, + kMTG_Zoom = 0x2, + kMTG_Rotate = 0x4, + kMTG_Swipe = 0x8 + }; + + MultitouchInterface() : + State(StateType::kMultitouchInterface) + {} + + virtual std::uint32_t GetMaxTouchPoints() const = 0; + virtual std::uint32_t GetSupportedGesturesMask() const = 0; + virtual bool SetMultitouchInputMode(MultitouchInputMode a_inputMode) = 0; + }; + using MovieDisplayHandle = Render::DisplayHandle; class __declspec(novtable) Movie : @@ -965,15 +1255,6 @@ namespace RE::Scaleform::GFx }; static_assert(sizeof(Movie) == 0x20); - class __declspec(novtable) MovieImpl : - public Movie // 00 - { - public: - // members - std::byte pad[0x3140 - 0x20]; // 20 - }; - static_assert(sizeof(MovieImpl) == 0x3140); - class __declspec(novtable) alignas(0x08) KeyboardState : public RefCountBase // 00 { @@ -994,4 +1275,18 @@ namespace RE::Scaleform::GFx std::byte pad[0x688 - 0x10]; // 10 - TODO }; static_assert(sizeof(KeyboardState) == 0x688); + + class __declspec(novtable) ExternalLibPtr + { + public: + ExternalLibPtr(MovieImpl* a_movieRoot) : + owner(a_movieRoot) + {} + + virtual ~ExternalLibPtr() = default; + + // members + MovieImpl* owner; + }; + static_assert(sizeof(ExternalLibPtr) == 0x10); } diff --git a/CommonLibF4/include/RE/Scaleform/GFx/GFx_PlayerImpl.h b/CommonLibF4/include/RE/Scaleform/GFx/GFx_PlayerImpl.h new file mode 100644 index 00000000..16cccb08 --- /dev/null +++ b/CommonLibF4/include/RE/Scaleform/GFx/GFx_PlayerImpl.h @@ -0,0 +1,219 @@ +#pragma once + +#include "RE/Scaleform/GFx/GFx_Player.h" +#include "RE/Scaleform/Render/Render_ScreenToWorld.h" + +namespace RE::Scaleform +{ + class AmpStats; +} + +namespace RE::Scaleform::Render +{ + class DrawableImageContext; + class TreeNode; + class TreeShape; +} + +namespace RE::Scaleform::GFx +{ + class CharacterHandle; + class DisplayObjectBase; + class DrawingContext; + class ExternalInterface; + class FontManagerStates; + class FontResource; + class FSCommandHandler; + class IMECandidateListStyle; + class InteractiveObject; + class LoadQueueEntry; + class LoadQueueEntryMT; + class StateBagImpl; + class UserEventHandler; + + class __declspec(novtable) ASIntervalTimerIntf : + public RefCountBase // 00 + { + public: + virtual ~ASIntervalTimerIntf() = default; // 00 + + // add + virtual void Start(MovieImpl* a_root) = 0; // 01 + virtual bool Invoke(MovieImpl* a_root, float a_frameTime) = 0; // 02 + virtual bool IsActive() const = 0; // 03 + virtual void Clear() = 0; // 04 + virtual bool ClearFor(MovieImpl* a_root, MovieDefImpl* a_def) = 0; // 05 + virtual std::uint64_t GetNextInvokeTime() const = 0; // 06 + virtual void SetId(std::int32_t a_id) = 0; // 07 + virtual std::int32_t GetId() const = 0; // 08 + }; + static_assert(sizeof(ASIntervalTimerIntf) == 0x10); + + struct alignas(0x10) FocusGroupDescr + { + enum + { + kTabableArray_Initialized = 0x1, + kTabableArray_WithFocusEnabled = 0x2 + }; + + // members + Ptr focusRectNode; // 00 + ArrayDH, kStatMV_Other_Mem> tabableArray; // 08 + mutable void* lastFocused; // 28 - mutable WeakPtr + Ptr modalClip; // 30 + std::uint32_t lastFocusKeyCode; // 38 + alignas(0x8) RectF lastFocusedRect; // 40 + bool focusRectShown; // 50 + std::uint8_t tabableArrayStatus; // 51 + }; + static_assert(sizeof(FocusGroupDescr) == 0x60); + + class __declspec(novtable) alignas(0x10) MovieImpl : + public Movie // 00 + { + public: + using MultitouchInputMode = MultitouchInterface::MultitouchInputMode; + using GestureMask = MultitouchInterface::GestureMask; + + class DragState + { + public: + constexpr DragState() = default; + + // members + InteractiveObject* character{ nullptr }; // 00 + InteractiveObject* topmostEntity{ nullptr }; // 08 + bool lockCenter{ false }; // 10 + bool bound{ false }; // 11 + PointF boundLT{ 0.0f, 0.0f }; // 14 + PointF boundRB{ 0.0f, 0.0f }; // 1C + PointF centerDelta{ 0.0f, 0.0f }; // 24 + std::uint32_t mouseIndex; // 2C + }; + static_assert(sizeof(DragState) == 0x30); + + struct FontDesc + { + // members + Ptr movieDef; + Ptr font; + }; + static_assert(sizeof(FontDesc) == 0x10); + + struct IndirectTransPair + { + // members + Ptr transformParent; + Ptr obj; + Ptr originalParent; + mutable std::int32_t origParentDepth{ -1 }; + }; + static_assert(sizeof(IndirectTransPair) == 0x20); + + struct LevelInfo + { + // members + std::int32_t level; + Ptr sprite; + }; + static_assert(sizeof(IndirectTransPair) == 0x20); + + struct MDKillListEntry + { + // members + std::uint64_t killFrameId; + Ptr movieDef; + }; + static_assert(sizeof(MDKillListEntry) == 0x10); + + struct ReturnValueHolder : public NewOverrideBase + { + // members + char* charBuffer; // 00 + std::uint32_t charBufferSize; // 08 + ArrayCC stringArray; // 10 + std::uint32_t stringArrayPos; // 30 + }; + static_assert(sizeof(ReturnValueHolder) == 0x38); + + // members + LoadQueueEntry* loadQueueHead; // 0020 + std::uint32_t lastLoadQueueEntryCount; // 0028 + Ptr advanceStats; // 0030 + Value::ObjectInterface* objectInterface; // 0038 + MemoryHeap* heap; // 0040 + Ptr mainMovieDef; // 0048 + InteractiveObject* mainMovie; // 0050 + ArrayLH movieLevels; // 0058 + List rootMovieDefNodes; // 0070 + Ptr stateBag; // 0080 + Ptr renderRoot; // 0088 + MovieDisplayHandle displayRoot; // 0090 + Ptr topMostRoot; // 0098 + GFx::Viewport viewport; // 00A0 + float pixelScale; // 00D4 + float viewScaleX; // 00D8 + float viewScaleY; // 00DC + float viewOffsetX; // 00E8 + float viewOffsetY; // 00E4 + ScaleModeType viewScaleMode; // 00E8 + AlignType viewAlignment; // 00EC + RectF visibleFrameRect; // 00F0 + RectF safeRect; // 0100 + Matrix2F viewportMatrix; // 0110 + Render::ScreenToWorld screenToWorld; // 0130 + mutable Ptr cachedLog; // 0220 + Ptr userEventHandler; // 0228 + Ptr fsCommandHandler; // 0230 + Ptr externalInterfaceHandler; // 0238 + Ptr fontManagerStates; // 0240 + ExternalLibPtr* xmlObjectManager; // 0248 + std::uint64_t timeElapsed; // 0250 + float timeRemainder; // 0258 + float frameTime; // 025C + std::uint32_t forceFrameCatchUp; // 0260 + std::byte pad268[0x1F60]; // 0268 - GFx::InputEventsQueue + Color backgroundColor; // 21C8 + std::byte pad21D0[0x50]; // 21D0 - MouseState[1] + std::uint32_t mouseCursorCount; // 2220 + std::uint32_t controllerCount; // 2224 + void* userData; // 2228 + std::byte pad2230[0x688]; // 2230 - KeyboardState[1] + ReturnValueHolder* returnValueHolder; // 28B8 + std::uint32_t instanceNameCount; // 28C0 + DragState currentDragState; // 28C8 + std::byte pad28F8[0x8]; // 28F8 - ASStringHash + ArrayLH, kStatMV_Other_Mem> topmostLevelCharacters; // 2900 + std::uint64_t startTickMS; // 2918 + std::uint64_t pauseTickMS; // 2920 + ArrayLH, kStatMV_Other_Mem> intervalTimers; // 2928 + std::int32_t lastIntervalTimerId; // 2940 + Ptr focusRectContainerNode; // 2948 + FocusGroupDescr focusGroups[16]; // 2950 + std::uint32_t focusGroupsCount; // 2F50 + std::uint8_t focusGroupIndexes[16]; // 2F54 + bool focusRectChanged; // 2F64 + InteractiveObject* playListHead; // 2F68 + InteractiveObject* playListOptHead; // 2F70 + InteractiveObject* unloadListHead; // 2F78 + std::uint32_t flags; // 2F80 + std::uint32_t flags2; // 2F84 + IMECandidateListStyle* imeCandidateListStyle; // 2F88 + LoadQueueEntryMT* loadQueueMTHead; // 2F90 + ArrayLH registeredFonts; // 2F98 + List drawingContextList; // 2FB0 + Array movieDefKillList; // 2FC0 + Ptr savedASMovieRoot; // 2FD8 + Render::Context renderContext; // 2FE0 + std::int8_t previouslyCaptured; // 30F0 + Ptr drawableImageContext; // 30F8 + Render::ThreadCommandQueue* renderThreadCommandQueue; // 3100 + Ptr multitouchHAL; // 3108 + MultitouchInputMode multitouchMode; // 3110 + Ptr gestureTopMostChar; // 3118 + std::int32_t deviceOrientation; // 3120 - OrientationEvent::OrientationType + ArrayLH indirectTransformPairs; + }; + static_assert(sizeof(MovieImpl) == 0x3140); +} diff --git a/CommonLibF4/include/RE/Scaleform/GFx/GFx_PlayerStats.h b/CommonLibF4/include/RE/Scaleform/GFx/GFx_PlayerStats.h new file mode 100644 index 00000000..f02db78d --- /dev/null +++ b/CommonLibF4/include/RE/Scaleform/GFx/GFx_PlayerStats.h @@ -0,0 +1,101 @@ +#pragma once + +#include "RE/Scaleform/GFx/GFx_Stats.h" + +namespace RE::Scaleform::GFx +{ + enum StatMovieData + { + kStatMD_Default = kStatGroup_GFxMovieData, + + kStatMD_Mem, + kStatMD_CharDefs_Mem, + kStatMD_ShapeData_Mem, + kStatMD_Tags_Mem, + kStatMD_Fonts_Mem, + kStatMD_Images_Mem, + kStatMD_ASBinaryData_Mem, + kStatMD_Other_Mem, + + kStatMD_Time, + kStatMD_Load_Tks, + kStatMD_Bind_Tks + }; + + enum StatMovieView : std::int32_t + { + kStatMV_Default = kStatGroup_GFxMovieView, + + kStatMV_Mem, + kStatMV_MovieClip_Mem, + kStatMV_ActionScript_Mem, + kStatMV_ASString_Mem, + kStatMV_Text_Mem, + kStatMV_XML_Mem, + kStatMV_Other_Mem, + kStatMV_VM, + kStatMV_VM_VM_Mem, + kStatMV_VM_CallFrame_Mem, + kStatMV_VM_VTable_Mem, + kStatMV_VM_SlotInfo_Mem, + kStatMV_VM_SlotInfoHash_Mem, + kStatMV_VM_CTraits_Mem, + kStatMV_VM_Class_Mem, + kStatMV_VM_ITraits_Mem, + kStatMV_VM_Instance_Mem, + kStatMV_VM_AbcFile_Mem, + kStatMV_VM_AbcConstPool_Mem, + kStatMV_VM_VMAbcFile_Mem, + kStatMV_VM_Tracer_Mem, + + kStatMV_Tks, + kStatMV_Advance_Tks, + kStatMV_Action_Tks, + kStatMV_Seek_Tks, + kStatMV_Timeline_Tks, + kStatMV_Input_Tks, + kStatMV_Mouse_Tks, + kStatMV_ScriptCommunication_Tks, + kStatMV_GetVariable_Tks, + kStatMV_SetVariable_Tks, + kStatMV_Invoke_Tks, + kStatMV_InvokeAction_Tks, + kStatMV_Display_Tks, + kStatMV_Tessellate_Tks, + kStatMV_GradientGen_Tks, + + kStatMV_Counters, + kStatMV_Invoke_Cnt, + kStatMV_MCAdvance_Cnt, + kStatMV_Tessellate_Cnt + }; + + enum StatIME + { + kStatIME_Default = kStatGroup_GFxIME, + + kStatIME_Mem + }; + + enum StatFontCache + { + kStatFC_Default = kStatGroup_GFxFontCache, + + kStatFC_Mem, + kStatFC_Batch_Mem, + kStatFC_GlyphCache_Mem, + kStatFC_Other_Mem + }; + + enum StatAmp + { + kStatAmp_Default = kStatGroup_GFxAmp, + + kStatAmp_Mem, + kStatAmp_ProfileFrame, + kStatAmp_Server, + kStatAmp_Message, + kStatAmp_Callstack, + kStatAmp_InstrBuffer, + }; +} diff --git a/CommonLibF4/include/RE/Scaleform/GFx/GFx_Stats.h b/CommonLibF4/include/RE/Scaleform/GFx/GFx_Stats.h new file mode 100644 index 00000000..7a7f4efd --- /dev/null +++ b/CommonLibF4/include/RE/Scaleform/GFx/GFx_Stats.h @@ -0,0 +1,40 @@ +#pragma once + +#include "RE/Scaleform/Kernel/SF_Stats.h" + +namespace RE::Scaleform +{ + enum StatGroup : std::int32_t + { + kStatGroup_Renderer = 1 << 6, + kStatGroup_RenderGen = 2 << 6, + kStatGroup_GFxFontCache = 3 << 6, + kStatGroup_GFxMovieData = 4 << 6, + kStatGroup_GFxMovieView = 5 << 6, + kStatGroup_GFxRenderCache = 6 << 6, + kStatGroup_GFxPlayer = 7 << 6, + kStatGroup_GFxIME = 8 << 6, + kStatGroup_GFxAmp = 9 << 6, + + // General Memory + kStat_Image_Mem = kStat_Default_Mem + 1, + kStat_String_Mem, + + kStat_Debug_Mem, + kStat_DebugHUD_Mem, + kStat_DebugTracker_Mem, + kStat_StatBag_Mem, + }; + + enum HeapId : std::int32_t + { + kHeapId_Global = kHeapId_Default, + kHeapId_MovieDef, + kHeapId_MovieView, + kHeapId_MovieData, + kHeapId_Images, + kHeapId_OtherHeaps, + kHeapId_HUDHeaps, + kHeapId_Video, + }; +} diff --git a/CommonLibF4/include/RE/Scaleform/GFx/GFx_Types.h b/CommonLibF4/include/RE/Scaleform/GFx/GFx_Types.h index 766a6c28..01ce98ae 100644 --- a/CommonLibF4/include/RE/Scaleform/GFx/GFx_Types.h +++ b/CommonLibF4/include/RE/Scaleform/GFx/GFx_Types.h @@ -1,5 +1,6 @@ #pragma once +#include "RE/Scaleform/Kernel/SF_Types.h" #include "RE/Scaleform/Render/Render_Color.h" #include "RE/Scaleform/Render/Render_Matrix2x4.h" #include "RE/Scaleform/Render/Render_Matrix3x4.h" diff --git a/CommonLibF4/include/RE/Scaleform/Kernel/SF_Allocator.h b/CommonLibF4/include/RE/Scaleform/Kernel/SF_Allocator.h index f2ea52a9..049993e4 100644 --- a/CommonLibF4/include/RE/Scaleform/Kernel/SF_Allocator.h +++ b/CommonLibF4/include/RE/Scaleform/Kernel/SF_Allocator.h @@ -4,52 +4,63 @@ namespace RE::Scaleform { - template + template + class AllocatorBaseDH + { + public: + }; + + template class AllocatorBaseGH { public: }; - //static_assert(std::is_empty_v>); - template + template class AllocatorBaseLH { public: }; - //static_assert(std::is_empty_v>); template - class ConstructorMov + class ConstructorPOD { public: }; - //static_assert(std::is_empty_v>); template - class ConstructorPagedMovCC : - public ConstructorMov + class ConstructorMov { public: }; - //static_assert(std::is_empty_v>); - template - class AllocatorPagedCC : - public AllocatorBaseLH, - public ConstructorPagedMovCC + template + class ConstructorCPP { - private: - // members - std::byte gap; // 00 + public: }; - // static_assert(sizeof(AllocatorPagedCC) == 0x01); - template + template struct AllocatorGH : public AllocatorBaseGH, // 0 public ConstructorMov // 1 { public: }; - //static_assert(std::is_empty_v>); + + template + struct AllocatorLH : + public AllocatorBaseLH, // 0 + public ConstructorMov // 1 + { + public: + }; + + template + struct AllocatorDH : + public AllocatorBaseDH, // 0 + public ConstructorMov // 1 + { + public: + }; } diff --git a/CommonLibF4/include/RE/Scaleform/Kernel/SF_Array.h b/CommonLibF4/include/RE/Scaleform/Kernel/SF_Array.h index be535896..0c44cd3e 100644 --- a/CommonLibF4/include/RE/Scaleform/Kernel/SF_Array.h +++ b/CommonLibF4/include/RE/Scaleform/Kernel/SF_Array.h @@ -16,7 +16,7 @@ namespace RE::Scaleform }; static_assert(sizeof(ArrayDefaultPolicy) == 0x8); - template + template struct ArrayConstPolicy { public: @@ -44,40 +44,57 @@ namespace RE::Scaleform public: }; + template + struct ArrayDataDH : + ArrayDataBase + { + public: + // members + const MemoryHeap* pHeap; + }; + + template + struct ArrayDataCC : + public ArrayDataBase + { + public: + T defaultValue; + }; + template class ArrayBase { public: - // membrs + // members ArrayData data; // 0 }; - template + template class Array : public ArrayBase, SizePolicy>> // 0 { public: }; - template > - class ArrayPagedBase : - public Alloc + template + class ArrayLH : + public ArrayBase, SizePolicy>> + { + public: + }; + + template + class ArrayDH : + public ArrayBase, SizePolicy>> { public: - // members - std::uint64_t size; // 08 - std::uint64_t numPages; // 10 - std::uint64_t maxPages; // 18 - T** pages; // 20 }; - static_assert(sizeof(ArrayPagedBase) == 0x28); - template - class ArrayPagedCC : - public ArrayPagedBase> + template + class ArrayCC : + public ArrayBase, SizePolicy>> { public: - T defaultValue; // 28 + }; - static_assert(sizeof(ArrayPagedCC) == 0x30); } diff --git a/CommonLibF4/include/RE/Scaleform/Kernel/SF_ArrayPaged.h b/CommonLibF4/include/RE/Scaleform/Kernel/SF_ArrayPaged.h new file mode 100644 index 00000000..6907f9ef --- /dev/null +++ b/CommonLibF4/include/RE/Scaleform/Kernel/SF_ArrayPaged.h @@ -0,0 +1,78 @@ +#pragma once + +#include "RE/Scaleform/Kernel/SF_Allocator.h" + +namespace RE::Scaleform +{ + template + class ConstructorPagedPOD : public ConstructorPOD + { + public: + }; + + template + class ConstructorPagedMov : public ConstructorMov + { + public: + }; + + template + class ConstructorPagedMovCC : public ConstructorMov + { + public: + }; + + template + struct AllocatorPagedGH_POD : AllocatorBaseGH, ConstructorPagedPOD + {}; + template + struct AllocatorPagedGH : AllocatorBaseGH, ConstructorPagedMov + {}; + + template + struct AllocatorPagedLH_POD : AllocatorBaseLH, ConstructorPagedPOD + {}; + template + struct AllocatorPagedLH : AllocatorBaseLH, ConstructorPagedMov + {}; + + template + struct AllocatorPagedCC : AllocatorBaseLH, ConstructorPagedMovCC + {}; + + template > + class ArrayPagedBase : + public Allocator + { + public: + // members + std::uint64_t size; // 08 + std::uint64_t numPages; // 10 + std::uint64_t maxPages; // 18 + T** pages; // 20 + }; + static_assert(sizeof(ArrayPagedBase) == 0x28); + + template + class ArrayPaged : + public ArrayPagedBase> + { + public: + }; + + template + class ArrayPagedPOD : + public ArrayPagedBase> + { + public: + }; + + template + class ArrayPagedCC : + public ArrayPagedBase> + { + public: + T defaultValue; // 28 + }; + static_assert(sizeof(ArrayPagedCC) == 0x30); +} diff --git a/CommonLibF4/include/RE/Scaleform/Kernel/SF_Stats.h b/CommonLibF4/include/RE/Scaleform/Kernel/SF_Stats.h index 75e32ef4..b1f2b8e7 100644 --- a/CommonLibF4/include/RE/Scaleform/Kernel/SF_Stats.h +++ b/CommonLibF4/include/RE/Scaleform/Kernel/SF_Stats.h @@ -2,6 +2,22 @@ namespace RE::Scaleform { + enum StatBasicValues : std::int32_t + { + kStatGroup_Default = 0, + kStatGroup_Core = 16, + + kStat_Mem = kStatGroup_Default + 1, + kStat_Default_Mem = kStat_Mem + 1, + + kStatHeap_Start = kStatGroup_Core, + + kStat_MaxId = 64 << 6, + kStat_EntryCount = 512, + + kHeapId_Default = 1 + }; + class StatBag { public: diff --git a/CommonLibF4/include/RE/Scaleform/Kernel/SF_Types.h b/CommonLibF4/include/RE/Scaleform/Kernel/SF_Types.h new file mode 100644 index 00000000..fe833567 --- /dev/null +++ b/CommonLibF4/include/RE/Scaleform/Kernel/SF_Types.h @@ -0,0 +1,7 @@ +#pragma once + +namespace RE::Scaleform +{ + template > + using Flags = stl::enumeration; +} diff --git a/CommonLibF4/include/RE/Scaleform/Render/Render_Context.h b/CommonLibF4/include/RE/Scaleform/Render/Render_Context.h index b098eb14..837c1841 100644 --- a/CommonLibF4/include/RE/Scaleform/Render/Render_Context.h +++ b/CommonLibF4/include/RE/Scaleform/Render/Render_Context.h @@ -259,6 +259,10 @@ namespace RE::Scaleform::Render { public: using Entry = ContextImpl::Entry; + using EntryData = ContextImpl::EntryData; + using EntryChange = ContextImpl::EntryChange; + using ChangeBuffer = ContextImpl::ChangeBuffer; + using RenderNotify = ContextImpl::RenderNotify; // members MemoryHeap* heap; // 000 @@ -280,9 +284,19 @@ namespace RE::Scaleform::Render std::uint64_t finalizedFrameID; // 108 }; static_assert(sizeof(Context) == 0x110); + + template + class ContextData_ImplMixin : public B + { + public: + virtual Context::EntryData* ConstructCopy(LinearHeap& heap) const; + virtual void CopyTo(void* pdest) const; + virtual void Destroy(); + }; } using ContextImpl::Context; using ContextImpl::ContextCaptureNotify; + using ContextImpl::ContextData_ImplMixin; using ContextImpl::DisplayHandle; } diff --git a/CommonLibF4/include/RE/Scaleform/Render/Render_ScreenToWorld.h b/CommonLibF4/include/RE/Scaleform/Render/Render_ScreenToWorld.h new file mode 100644 index 00000000..8f569ca9 --- /dev/null +++ b/CommonLibF4/include/RE/Scaleform/Render/Render_ScreenToWorld.h @@ -0,0 +1,23 @@ +#pragma once + +#include "RE/Scaleform/Render/Render_Matrix4x4.h" + +namespace RE::Scaleform::Render +{ + class ScreenToWorld + { + public: + constexpr ScreenToWorld() = default; + + // members + float sx{ std::numeric_limits::max() }; // 00 + float sy{ std::numeric_limits::max() }; // 04 + float lastX{ std::numeric_limits::max() }; // 08 + float lastY{ std::numeric_limits::max() }; // 0C + Matrix4F matProj; // 10 + Matrix3F matView; // 50 + Matrix3F matWorld; // 80 + Matrix4F matInvProj; // B0 + }; + static_assert(sizeof(ScreenToWorld) == 0xF0); +} diff --git a/CommonLibF4/include/RE/Scaleform/Render/Render_TreeShape.h b/CommonLibF4/include/RE/Scaleform/Render/Render_TreeShape.h new file mode 100644 index 00000000..5faa2ae6 --- /dev/null +++ b/CommonLibF4/include/RE/Scaleform/Render/Render_TreeShape.h @@ -0,0 +1,11 @@ +#pragma once + +#include "RE/Scaleform/Render/Render_TreeNode.h" + +namespace RE::Scaleform::Render +{ + class TreeShape : public TreeNode + { + public: + }; +} diff --git a/CommonLibF4/include/REL/IAT.h b/CommonLibF4/include/REL/IAT.h new file mode 100644 index 00000000..1e7049a8 --- /dev/null +++ b/CommonLibF4/include/REL/IAT.h @@ -0,0 +1,31 @@ +#pragma once + +namespace REL +{ + [[nodiscard]] std::uintptr_t GetIATAddr(std::string_view a_dll, std::string_view a_function); + [[nodiscard]] std::uintptr_t GetIATAddr(REX::W32::HMODULE a_module, std::string_view a_dll, std::string_view a_function); + + [[nodiscard]] void* GetIATPtr(std::string_view a_dll, std::string_view a_function); + + template + [[nodiscard]] T* GetIATPtr(std::string_view a_dll, std::string_view a_function) + { + return static_cast(GetIATPtr(std::move(a_dll), std::move(a_function))); + } + + [[nodiscard]] void* GetIATPtr(REX::W32::HMODULE a_module, std::string_view a_dll, std::string_view a_function); + + template + [[nodiscard]] T* GetIATPtr(REX::W32::HMODULE a_module, std::string_view a_dll, std::string_view a_function) + { + return static_cast(GetIATPtr(a_module, std::move(a_dll), std::move(a_function))); + } + + std::uintptr_t PatchIAT(std::uintptr_t a_newFunc, std::string_view a_dll, std::string_view a_function); + + template + std::uintptr_t PatchIAT(F a_newFunc, std::string_view a_dll, std::string_view a_function) + { + return PatchIAT(stl::unrestricted_cast(a_newFunc), a_dll, a_function); + } +} diff --git a/CommonLibF4/include/REL/REL.h b/CommonLibF4/include/REL/REL.h index bf24bee2..bb0dbc11 100644 --- a/CommonLibF4/include/REL/REL.h +++ b/CommonLibF4/include/REL/REL.h @@ -1,5 +1,6 @@ #pragma once +#include "REL/IAT.h" #include "REL/ID.h" #include "REL/IDDB.h" #include "REL/Module.h" diff --git a/CommonLibF4/include/REL/Relocation.h b/CommonLibF4/include/REL/Relocation.h index cd101359..ed975278 100644 --- a/CommonLibF4/include/REL/Relocation.h +++ b/CommonLibF4/include/REL/Relocation.h @@ -278,10 +278,20 @@ namespace REL return stl::unrestricted_cast(_impl); } + void write(const void* a_src, std::size_t a_count) requires(std::same_as) + { + safe_write(address(), a_src, a_count); + } + template void write(const U& a_data) requires(std::same_as) { - safe_write(address(), std::addressof(a_data), sizeof(T)); + safe_write(address(), std::addressof(a_data), sizeof(U)); + } + + void write(const std::initializer_list a_data) requires(std::same_as) + { + safe_write(address(), a_data.begin(), a_data.size()); } template diff --git a/CommonLibF4/src/REL/IAT.cpp b/CommonLibF4/src/REL/IAT.cpp new file mode 100644 index 00000000..4ff9b83c --- /dev/null +++ b/CommonLibF4/src/REL/IAT.cpp @@ -0,0 +1,79 @@ +#include "REL/IAT.h" +#include "REL/Module.h" +#include "REL/Relocation.h" + +#include "F4SE/Logger.h" + +#include "REX/W32/KERNEL32.h" + +namespace REL +{ + std::uintptr_t GetIATAddr(std::string_view a_dll, std::string_view a_function) + { + return reinterpret_cast(GetIATPtr(std::move(a_dll), std::move(a_function))); + } + + std::uintptr_t GetIATAddr(REX::W32::HMODULE a_module, std::string_view a_dll, std::string_view a_function) + { + return reinterpret_cast(GetIATPtr(a_module, std::move(a_dll), std::move(a_function))); + } + + void* GetIATPtr(std::string_view a_dll, std::string_view a_function) + { + const auto mod = static_cast(REL::Module::get().pointer()); + return GetIATPtr(mod, std::move(a_dll), std::move(a_function)); + } + + // https://guidedhacking.com/attachments/pe_imptbl_headers-jpg.2241/ + void* GetIATPtr(REX::W32::HMODULE a_module, std::string_view a_dll, std::string_view a_function) + { + assert(a_module); + const auto dosHeader = reinterpret_cast(a_module); + if (dosHeader->magic != REX::W32::IMAGE_DOS_SIGNATURE) { + F4SE::log::error("Invalid DOS header"); + return nullptr; + } + + const auto ntHeader = stl::adjust_pointer(dosHeader, dosHeader->lfanew); + const auto& dataDir = ntHeader->optionalHeader.dataDirectory[REX::W32::IMAGE_DIRECTORY_ENTRY_IMPORT]; + const auto importDesc = stl::adjust_pointer(dosHeader, dataDir.virtualAddress); + + for (auto import = importDesc; import->characteristics != 0; ++import) { + auto name = stl::adjust_pointer(dosHeader, import->name); + if (a_dll.size() == strlen(name) && _strnicmp(a_dll.data(), name, a_dll.size()) != 0) { + continue; + } + + const auto thunk = stl::adjust_pointer(dosHeader, import->firstThunkOriginal); + for (std::size_t i = 0; thunk[i].ordinal; ++i) { + if (REX::W32::IMAGE_SNAP_BY_ORDINAL64(thunk[i].ordinal)) { + continue; + } + + const auto importByName = stl::adjust_pointer(dosHeader, thunk[i].address); + if (a_function.size() == strlen(importByName->name) && + _strnicmp(a_function.data(), importByName->name, a_function.size()) == 0) { + return stl::adjust_pointer(dosHeader, import->firstThunk) + i; + } + } + } + + F4SE::log::warn("Failed to find {} ({})", a_dll, a_function); + return nullptr; + } + + std::uintptr_t PatchIAT(std::uintptr_t a_newFunc, std::string_view a_dll, std::string_view a_function) + { + std::uintptr_t origAddr = 0; + + const auto oldFunc = GetIATAddr(a_dll, a_function); + if (oldFunc) { + origAddr = *reinterpret_cast(oldFunc); + REL::safe_write(oldFunc, a_newFunc); + } else { + F4SE::log::warn("Failed to patch {} ({})", a_dll, a_function); + } + + return origAddr; + } +} diff --git a/xmake.lua b/xmake.lua index 25ac8dbc..6627ef28 100644 --- a/xmake.lua +++ b/xmake.lua @@ -8,7 +8,7 @@ set_warnings("allextra") set_encodings("utf-8") -- add rules -add_rules("mode.debug", "mode.release") +add_rules("mode.debug", "mode.releasedbg") -- require packages add_requires("rsm-binary-io", "rsm-mmio", "xbyak")