Various materialsystem things (#919)

* various materialsystem things

* Update nscustomdxbuffer.cpp

formatter maybe

* Update nscustomdxbuffer.cpp

Buy minecraft

* move comment

move comment

* Update nscustomdxbuffer.cpp

* more slots slots go brrrt

more slots slots go brrrt
This commit is contained in:
FourthVolt 2026-05-18 21:17:06 +02:00 committed by GitHub
parent 39d5570c76
commit fad19af919
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 349 additions and 61 deletions

View file

@ -19,26 +19,46 @@ static void __fastcall h_CC_mat_crosshair_printmaterial_f(const CCommand& args)
if (!pGlue)
{
spdlog::info("|-- {} is NULL", szName);
spdlog::info("├ No reference material for {}", szName);
return;
}
spdlog::info("|-- Name: {}", szName);
spdlog::info("|-- GUID: {:#x}", pGlue->m_GUID);
spdlog::info("|-- Name: {}", pGlue->m_pszName);
spdlog::info("|-- Width : {}", pGlue->m_iWidth);
spdlog::info("|-- Height: {}", pGlue->m_iHeight);
spdlog::info("├ {}", szName);
spdlog::info("│├── GUID: {:#x}", pGlue->material.guid);
spdlog::info("│└── Name: {}", pGlue->material.name);
};
spdlog::info("|- GUID: {:#x}", pMat->m_GUID);
spdlog::info("|- Name: {}", pMat->m_pszName);
spdlog::info("|- Width : {}", pMat->m_iWidth);
spdlog::info("|- Height: {}", pMat->m_iHeight);
spdlog::info("────────────────────────────────────────────────────────────");
spdlog::info("┌ Name: {}", pMat->material.name);
spdlog::info("├ GUID: {:#x}", pMat->material.guid);
spdlog::info("├ Width : {}", pMat->material.width);
spdlog::info("├ Height: {}", pMat->material.height);
spdlog::info("├ Shaderset: {}", pMat->material.shaderSet->inner.name);
fnPrintGlue(pMat->m_pDepthShadow, "DepthShadow");
fnPrintGlue(pMat->m_pDepthPrepass, "DepthPrepass");
fnPrintGlue(pMat->m_pDepthVSM, "DepthVSM");
fnPrintGlue(pMat->m_pColPass, "ColPass");
fnPrintGlue(pMat->material.DepthShadow_ref, "DepthShadow");
fnPrintGlue(pMat->material.DepthPrepass_ref, "DepthPrepass");
fnPrintGlue(pMat->material.DepthVSM_ref, "DepthVSM");
fnPrintGlue(pMat->material.Colpass_ref, "Colpass");
if (pMat && pMat->material.shaderSet && pMat->material.shaderSet->inner.textureInputCount >= 1 && pMat->material.textureHandles)
{
spdlog::info("├ Textures");
for (size_t slot = 0; slot < pMat->material.shaderSet->inner.textureInputCount + 1; ++slot)
{
RpakTextureHeader* currentTexture = pMat->material.textureHandles[slot];
if (currentTexture && currentTexture->name)
{
if (slot == pMat->material.shaderSet->inner.textureInputCount)
spdlog::info("│└[{}][{:#x}]{}", slot, currentTexture->guid, currentTexture->name);
else
spdlog::info("│├[{}][{:#x}]{}", slot, currentTexture->guid, currentTexture->name);
}
}
}
spdlog::info("├ Glueflags: {:#x}", pMat->material.flags);
spdlog::info("└ Glueflags2: {:#x}", pMat->material.flags2);
spdlog::info("────────────────────────────────────────────────────────────");
}
ON_DLL_LOAD("engine.dll", GlMatSysIFace, (CModule module))

View file

@ -1,47 +1,124 @@
#pragma once
#include "materialsystem/cshaderglue.h"
#include <d3d11.h>
class RpakTextureHeader // Expected size: 0x130
{
public:
uint64_t guid;
const char* name;
uint16_t width;
uint16_t height;
int16_t depth;
uint16_t dxgiFormat;
uint32_t dataSize;
uint8_t compressionType;
uint8_t optStreamedMipCount;
uint8_t arraySize;
uint8_t layerCount;
uint8_t mipFlags;
uint8_t permanentMipCount;
uint8_t streamedMipCount;
uint8_t unk[13];
int64_t numPixels;
uint16_t unknownWord38;
uint8_t unknownByte3A;
uint8_t unknownByte3B;
uint32_t unknownDword3C;
uint32_t unknownDword40;
uint32_t unknownDword44;
float transform[16];
uint64_t unknownQword88;
uint64_t unknownQword90;
uint32_t unknownArray98[16];
uint32_t unknownArrayD8[16];
ID3D11Resource* d3d11Resource;
ID3D11ShaderResourceView* shaderResourceView;
uint8_t unknownByte128;
uint8_t padding[7];
};
struct CBufUberStatic // sizeof = 0xE0
{
float c_uv1RotScaleX[2]; // 0x00
float c_uv1RotScaleY[2]; // 0x08
float c_uv1Translate[2]; // 0x10
float c_uv2RotScaleX[2]; // 0x18
float c_uv2RotScaleY[2]; // 0x20
float c_uv2Translate[2]; // 0x28
float c_uv3RotScaleX[2]; // 0x30
float c_uv3RotScaleY[2]; // 0x38
float c_uv3Translate[2]; // 0x40
float c_uvDistortionIntensity[2]; // 0x48
float c_uvDistortion2Intensity[2]; // 0x50
float c_fogColorFactor; // 0x58
float c_layerBlendRamp; // 0x5C
float c_albedoTint[3]; // 0x60
float c_opacity; // 0x6C
float c_useAlphaModulateSpecular; // 0x70
float c_alphaEdgeFadeExponent; // 0x74
float c_alphaEdgeFadeInner; // 0x78
float c_alphaEdgeFadeOuter; // 0x7C
float c_useAlphaModulateEmissive; // 0x80
float c_emissiveEdgeFadeExponent; // 0x84
float c_emissiveEdgeFadeInner; // 0x88
float c_emissiveEdgeFadeOuter; // 0x8C
float c_alphaDistanceFadeScale; // 0x90
float c_alphaDistanceFadeBias; // 0x94
float c_alphaTestReference; // 0x98
float c_aspectRatioMulV; // 0x9C
float c_emissiveTint[3]; // 0xA0
float c_shadowBias; // 0xAC
float c_tsaaDepthAlphaThreshold; // 0xB0
float c_tsaaMotionAlphaThreshold; // 0xB4
float c_tsaaMotionAlphaRamp; // 0xB8
uint32_t c_tsaaResponsiveFlag; // 0xBC
float c_dofOpacityLuminanceScale; // 0xC0
float c_glitchStrength; // 0xC4
float c_padding[2]; // 0xC8
float c_perfGloss; // 0xD0
float c_perfSpecColor[3]; // 0xD4
};
class CMaterialGlue;
class CMaterialGlue_short
{
public:
uint64_t guid;
const char* name;
uint64_t* surfaceProps[2];
CMaterialGlue* DepthShadow_ref;
CMaterialGlue* DepthPrepass_ref;
CMaterialGlue* DepthVSM_ref;
CMaterialGlue* Colpass_ref;
uint8_t gap_50[64];
ShaderGlue* shaderSet;
RpakTextureHeader** textureHandles;
RpakTextureHeader** streamingTextures;
int16_t streamingTextureCount;
uint8_t samplersIndices[4];
int16_t unknown;
uint8_t gap_B0[12];
uint16_t unknownWord[2];
uint32_t flags;
uint32_t flags2;
uint16_t width;
uint16_t height;
uint8_t gap_CC[2];
uint16_t word_CE;
void** pointer_D0;
CBufUberStatic* cbufUberStatic;
ID3D11Buffer* buffer;
uint32_t* atlasBufferIndices;
uint32_t dword_F0;
uint8_t gap_F4[12];
};
class CMaterialGlue
{
public:
void* m_pVFTable;
char m_unk[8];
uint64_t m_GUID;
const char* m_pszName;
const char* m_pszSurfaceProp;
const char* m_pszSurfaceProp2;
CMaterialGlue* m_pDepthShadow;
CMaterialGlue* m_pDepthPrepass;
CMaterialGlue* m_pDepthVSM;
CMaterialGlue* m_pColPass;
char gap_50[64];
CShaderGlue* m_pShaderGlue;
void** m_pTextureHandles;
void** m_pStreamingTextures;
int16_t m_iStreamingTextureCount;
uint8_t m_iSamplersIndices[4];
int16_t m_iUnknown0;
char gap_B0[12];
int16_t aword_BC[2];
int32_t flags2;
int32_t flags3;
int16_t m_iWidth;
int16_t m_iHeight;
int16_t m_iUnknown1;
int16_t m_iUnknown2;
void** m_pUnkD3D11Ptr;
void* m_pD3D11Buffer;
void* qword_E0;
void* pointer_E8;
int32_t dword_F0;
char gap_F4[12];
CMaterialGlue_short material;
};

View file

@ -5,3 +5,28 @@ class CShaderGlue
public:
void* vftable;
};
struct ShaderGlue_inner
{
const char* name;
uint64_t flagsMaybe;
uint16_t resourceBindingSlot;
uint16_t textureInputCount;
int16_t shadowSamplerCount;
uint16_t unkBindingSlot;
uint16_t unkBindingCount;
uint8_t bytes_22[6];
uint64_t unk3[4];
void* vertexShader;
void* pixelShader;
};
struct ShaderGlue
{
void* vtable;
ShaderGlue_inner inner;
};

View file

@ -6,6 +6,8 @@
#include <cctype>
#include <string>
#include <cstdint>
#include "core/filesystem/rpakfilesystem.h"
#include "cmaterialglue.h"
static ID3D11DeviceContext** DeviceContext;
static ID3D11Device** D3D11Device_14E8DD0;
@ -15,6 +17,12 @@ struct Ns_Constant_Buffer
float data[320];
};
struct MaterialTextureMappings
{
std::array<uint64_t, 60> slots;
};
AUTOHOOK_INIT()
static Ns_Constant_Buffer NSCustomDXBuffer;
@ -22,15 +30,48 @@ static std::mutex NSCustomDXBufferMutex;
// map to later on associate guid > buffer
static std::map<uint64_t, Ns_Constant_Buffer> NSCustomBuffersPerMaterial = {};
static std::map<uint64_t, MaterialTextureMappings> NSMaterialTextureSlotBindings = {};
static std::unordered_set<uint64_t> NSRegisteredCustomBufferMaterials = {};
static std::unordered_set<uint64_t> NSRegisteredTextureOverrides = {};
AUTOHOOK(SUB_511D0, materialsystem_dx11.dll + 0x511D0, __int64, __fastcall, (__int64 a1, __int64 a2, __int64 a3, __int64 a4))
AUTOHOOK(SUB_511D0, materialsystem_dx11.dll + 0x511D0, __int64, __fastcall, (__int64 a1, __int64 a2, __int64 a3, CMaterialGlue_short* a4))
{
int64_t subResult = SUB_511D0(a1, a2, a3, a4);
CMaterialGlue_short* internal_logic_material = a4;
uint32_t glueFlags = *(uint32_t*)((uint8_t*)a4 + 176);
int64_t subResult = SUB_511D0(a1, a2, a3, internal_logic_material);
if (!DeviceContext || !D3D11Device_14E8DD0 || !*DeviceContext || !*D3D11Device_14E8DD0)
return subResult;
// bind textures to slots if existing
if (NSMaterialTextureSlotBindings.contains(internal_logic_material->guid))
{
auto& mappings = NSMaterialTextureSlotBindings[internal_logic_material->guid];
for (size_t slot = 0; slot < mappings.slots.size(); ++slot)
{
uint64_t textureGUID = mappings.slots[slot];
if (textureGUID == 0)
continue;
__int64 texturePointer = g_pakLoadApi->GetAssetByHash(textureGUID);
if (!texturePointer)
continue;
RpakTextureHeader* TextureHeader = (RpakTextureHeader*)texturePointer;
ID3D11ShaderResourceView* TextureSRV = TextureHeader->shaderResourceView;
if (!TextureSRV)
continue;
(*DeviceContext)->PSSetShaderResources(slot, 1, &TextureSRV);
}
}
// bind custom buffer when flag is 0x04089901 in rpak mat
if ((glueFlags & 0x04089901) == 0x04089901)
if (NSRegisteredCustomBufferMaterials.contains(internal_logic_material->guid))
{
D3D11_BUFFER_DESC desc {};
@ -62,7 +103,7 @@ AUTOHOOK(SUB_511D0, materialsystem_dx11.dll + 0x511D0, __int64, __fastcall, (__i
std::lock_guard<std::mutex> lock(NSCustomDXBufferMutex);
memcpy(pData, &NSCustomBuffersPerMaterial[*(uint64_t*)a4], sizeof(Ns_Constant_Buffer));
memcpy(pData, &NSCustomBuffersPerMaterial[internal_logic_material->guid], sizeof(Ns_Constant_Buffer));
(*DeviceContext)->Unmap(resource, 0);
(*DeviceContext)->PSSetConstantBuffers(4, 1, &resource);
@ -86,7 +127,73 @@ bool isValidMaterialGUID(const std::string& str)
return true;
}
template <ScriptContext context> SQRESULT NSSetCustomDXBuffer(HSQUIRRELVM sqvm)
SQRESULT NSRegisterCustomDXBufferForGUID(HSQUIRRELVM sqvm)
{
auto rPakMaterialGUIDString = (g_pSquirrel[ScriptContext::CLIENT]->getstring(sqvm, 1));
uint64_t rPakMaterialGUID = std::stoull(rPakMaterialGUIDString, nullptr, 16);
__int64 AssetFromGUID = g_pakLoadApi->GetAssetByHash(rPakMaterialGUID);
if (!AssetFromGUID)
{
g_pSquirrel[ScriptContext::CLIENT]->raiseerror(
sqvm, fmt::format("Asset with GUID {} Doesnt Exist", rPakMaterialGUIDString).c_str());
return SQRESULT_ERROR;
}
// we need to add 16 to the pointer, matglueshort is matglue without the first 16 bytes. GetAssetByHash returns a pointer to the full
auto* base = reinterpret_cast<uint8_t*>(AssetFromGUID);
auto* GUIDMaterialGlue_short = reinterpret_cast<CMaterialGlue_short*>(base + 16);
if (!NSRegisteredCustomBufferMaterials.contains(GUIDMaterialGlue_short->guid))
{
NS::log::SCRIPT_CL->info("Registered GUID: {} to use the NSCustomDXBuffer system", GUIDMaterialGlue_short->guid);
NSRegisteredCustomBufferMaterials.insert(GUIDMaterialGlue_short->guid);
}
else
{
NS::log::SCRIPT_CL->warn(
"Attempted to register GUID: {} to the NSCustomDXBuffer system, GUID was already registered", GUIDMaterialGlue_short->guid);
}
return SQRESULT_NULL;
}
SQRESULT NSDeregisterCustomDXBufferForGUID(HSQUIRRELVM sqvm)
{
auto rPakMaterialGUIDString = (g_pSquirrel[ScriptContext::CLIENT]->getstring(sqvm, 1));
uint64_t rPakMaterialGUID = std::stoull(rPakMaterialGUIDString, nullptr, 16);
__int64 AssetFromGUID = g_pakLoadApi->GetAssetByHash(rPakMaterialGUID);
if (!AssetFromGUID)
{
g_pSquirrel[ScriptContext::CLIENT]->raiseerror(
sqvm, fmt::format("Asset with GUID {} Doesnt Exist", rPakMaterialGUIDString).c_str());
return SQRESULT_ERROR;
}
// we need to add 16 to the pointer, matglueshort is matglue without the first 16 bytes. GetAssetByHash returns a pointer to the full
auto* base = reinterpret_cast<uint8_t*>(AssetFromGUID);
auto* GUIDMaterialGlue_short = reinterpret_cast<CMaterialGlue_short*>(base + 16);
if (NSRegisteredCustomBufferMaterials.contains(GUIDMaterialGlue_short->guid))
{
NS::log::SCRIPT_CL->info("Deregistered GUID: {} from the NSCustomDXBuffer system", GUIDMaterialGlue_short->guid);
NSRegisteredCustomBufferMaterials.erase(GUIDMaterialGlue_short->guid);
}
else
{
NS::log::SCRIPT_CL->warn(
"Attempted to deregister GUID: {} from the NSCustomDXBuffer system, GUID was not registered", GUIDMaterialGlue_short->guid);
}
return SQRESULT_NULL;
}
SQRESULT NSUpdateCustomDXBufferForGUID(HSQUIRRELVM sqvm)
{
// get the guid as a string to later conv
@ -107,7 +214,7 @@ template <ScriptContext context> SQRESULT NSSetCustomDXBuffer(HSQUIRRELVM sqvm)
if (!isValidMaterialGUID(guidString))
{
g_pSquirrel[ScriptContext::SERVER]->raiseerror(
g_pSquirrel[ScriptContext::CLIENT]->raiseerror(
sqvm, fmt::format("Malformed Material GUID", (NSCustomBufferDataArray->_usedSlots) * 4, sizeof(Ns_Constant_Buffer)).c_str());
return SQRESULT_ERROR;
}
@ -118,7 +225,7 @@ template <ScriptContext context> SQRESULT NSSetCustomDXBuffer(HSQUIRRELVM sqvm)
if ((NSCustomBufferDataArray->_usedSlots) * 4 > sizeof(Ns_Constant_Buffer))
{
g_pSquirrel[ScriptContext::SERVER]->raiseerror(
g_pSquirrel[ScriptContext::CLIENT]->raiseerror(
sqvm,
fmt::format(
"Size of Squirrel array exceeds NSCustomDXBuffer size\n\nSquirrel "
@ -136,16 +243,75 @@ template <ScriptContext context> SQRESULT NSSetCustomDXBuffer(HSQUIRRELVM sqvm)
return SQRESULT_NULL;
}
SQRESULT NSBindTextureToMaterial(HSQUIRRELVM sqvm)
{
auto rPakMaterialGUIDString = (g_pSquirrel[ScriptContext::CLIENT]->getstring(sqvm, 1));
auto rPakTextureGUIDString = (g_pSquirrel[ScriptContext::CLIENT]->getstring(sqvm, 2));
auto rPakShaderSlotBindingInt = (g_pSquirrel[ScriptContext::CLIENT]->getinteger(sqvm, 3));
uint64_t rPakMaterialGUID = std::stoull(rPakMaterialGUIDString, nullptr, 16);
__int64 MatAssetFromGUID = g_pakLoadApi->GetAssetByHash(rPakMaterialGUID);
if (rPakShaderSlotBindingInt > 60)
{
g_pSquirrel[ScriptContext::CLIENT]->raiseerror(sqvm, fmt::format("TextureOverrides only support 30 custom bindings").c_str());
return SQRESULT_ERROR;
}
if (!MatAssetFromGUID)
{
g_pSquirrel[ScriptContext::CLIENT]->raiseerror(
sqvm, fmt::format("Material with GUID {} Doesnt Exist", rPakMaterialGUIDString).c_str());
return SQRESULT_ERROR;
}
auto* base = reinterpret_cast<uint8_t*>(MatAssetFromGUID);
auto* GUIDMaterialGlue_short = reinterpret_cast<CMaterialGlue_short*>(base + 16);
if (!rPakTextureGUIDString == 0)
{
uint64_t rPakTextureGUID = std::stoull(rPakTextureGUIDString, nullptr, 16);
__int64 TexAssetFromGUID = g_pakLoadApi->GetAssetByHash(rPakTextureGUID);
if (!TexAssetFromGUID)
{
g_pSquirrel[ScriptContext::CLIENT]->raiseerror(
sqvm, fmt::format("Texture with GUID {} Doesnt Exist", rPakTextureGUIDString).c_str());
return SQRESULT_ERROR;
}
NSMaterialTextureSlotBindings[GUIDMaterialGlue_short->guid].slots[rPakShaderSlotBindingInt] = rPakTextureGUID;
}
else
NSMaterialTextureSlotBindings[GUIDMaterialGlue_short->guid].slots[rPakShaderSlotBindingInt] = 0;
return SQRESULT_NULL;
}
ON_DLL_LOAD_CLIENT("materialsystem_dx11.dll", SUB_511D0, (CModule module))
{
AUTOHOOK_DISPATCH_MODULE(materialsystem_dx11.dll)
DeviceContext = module.Offset(0x14E8DD8).RCast<ID3D11DeviceContext**>();
D3D11Device_14E8DD0 = module.Offset(0x14E8DD0).RCast<ID3D11Device**>();
g_pSquirrel[ScriptContext::CLIENT]->AddFuncRegistration(
"void",
"NSSetCustomDXBuffer",
"NSUpdateCustomDXBufferForGUID",
"string rPakMaterialGUID array NSCustomBufferPerMaterialData",
"",
NSSetCustomDXBuffer<ScriptContext::CLIENT>);
NSUpdateCustomDXBufferForGUID);
g_pSquirrel[ScriptContext::CLIENT]->AddFuncRegistration(
"void", "NSRegisterCustomDXBufferForGUID", "string rPakMaterialGUID", "", NSRegisterCustomDXBufferForGUID);
g_pSquirrel[ScriptContext::CLIENT]->AddFuncRegistration(
"void", "NSDeregisterCustomDXBufferForGUID", "string rPakMaterialGUID", "", NSDeregisterCustomDXBufferForGUID);
g_pSquirrel[ScriptContext::CLIENT]->AddFuncRegistration(
"void",
"NSBindTextureToMaterial",
"string rPakMaterialGUID string rPakTextureGUID int shaderBindingSlot",
"",
NSBindTextureToMaterial);
}