mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
This change was planned for a long time. This moves all REGISTER calls to a single translation unit, this is required as we currently added a very dirty workaround for not registering duplicates by checking if VFTable pointer was already present in the vector... Registering from single translation unit prevents duplicate instances that gets created if header is included by more cpp files. Reworking this reduced 100kb+ of compiled code. This commit also reworked the way functions/variables/constant gets logged with their addresses; the new code formats them on the fly, and allows for resize at any time. Formatting is no longer required by programmer. TODO: currently there are some compile errors for dedicated and client dll's. These will be resolved very soon as they need to be properly worked out still (server & client only stuff needs to be properly split). Use the 'main' (stable) branch for the time being if you need to compile these dll's.
821 lines
30 KiB
C++
821 lines
30 KiB
C++
#include "core/stdafx.h"
|
|
#include "tier1/cvar.h"
|
|
#include "rtech/rtech_utils.h"
|
|
#ifndef DEDICATED
|
|
#include "windows/id3dx.h"
|
|
#include "materialsystem/cshaderglue.h"
|
|
#include "public/rendersystem/schema/texture.g.h"
|
|
#endif // !DEDICATED
|
|
|
|
/******************************************************************************
|
|
-------------------------------------------------------------------------------
|
|
File : rtech.cpp
|
|
Date : 18:07:2021
|
|
Author : Kawe Mazidjatari
|
|
Purpose: Implements the 'rtech_game' core utilities
|
|
-------------------------------------------------------------------------------
|
|
History:
|
|
- 18:07:2021 | 13:02 : Created by Kawe Mazidjatari
|
|
- 10:09:2021 | 18:22 : Implement 'StringToGuid' method
|
|
- 12:11:2021 | 14:41 : Add decompression method to ConCommand callback
|
|
- 25:12:2021 | 23:20 : Made everything more readable thanks to bezdna5-rs
|
|
- 28:03:2022 | 18:00 : Added getting pak info by PakID.
|
|
|
|
******************************************************************************/
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: calculate 'GUID' from input data
|
|
//-----------------------------------------------------------------------------
|
|
uint64_t __fastcall RTech::StringToGuid(const char* pData)
|
|
{
|
|
uint32_t* v1; // r8
|
|
uint64_t v2; // r10
|
|
int32_t v3; // er11
|
|
uint32_t v4; // er9
|
|
uint32_t i; // edx
|
|
uint64_t v6; // rcx
|
|
int32_t v7; // er9
|
|
int32_t v8; // edx
|
|
int32_t v9; // eax
|
|
uint32_t v10; // er8
|
|
int32_t v12; // ecx
|
|
uint32_t* a1 = (uint32_t*)pData;
|
|
|
|
v1 = a1;
|
|
v2 = 0i64;
|
|
v3 = 0;
|
|
v4 = (*a1 - 45 * ((~(*a1 ^ 0x5C5C5C5Cu) >> 7) & (((*a1 ^ 0x5C5C5C5Cu) - 0x1010101) >> 7) & 0x1010101)) & 0xDFDFDFDF;
|
|
for (i = ~*a1 & (*a1 - 0x1010101) & 0x80808080; !i; i = v8 & 0x80808080)
|
|
{
|
|
v6 = v4;
|
|
v7 = v1[1];
|
|
++v1;
|
|
v3 += 4;
|
|
v2 = ((((uint64_t)(0xFB8C4D96501i64 * v6) >> 24) + 0x633D5F1 * v2) >> 61) ^ (((uint64_t)(0xFB8C4D96501i64 * v6) >> 24)
|
|
+ 0x633D5F1 * v2);
|
|
v8 = ~v7 & (v7 - 0x1010101);
|
|
v4 = (v7 - 45 * ((~(v7 ^ 0x5C5C5C5Cu) >> 7) & (((v7 ^ 0x5C5C5C5Cu) - 0x1010101) >> 7) & 0x1010101)) & 0xDFDFDFDF;
|
|
}
|
|
v9 = -1;
|
|
v10 = (i & -(signed)i) - 1;
|
|
if (_BitScanReverse((unsigned long*)&v12, v10))
|
|
{
|
|
v9 = v12;
|
|
}
|
|
return 0x633D5F1 * v2 + ((0xFB8C4D96501i64 * (uint64_t)(v4 & v10)) >> 24) - 0xAE502812AA7333i64 * (uint32_t)(v3 + v9 / 8);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: calculate 'decompressed' size and commit parameters
|
|
//-----------------------------------------------------------------------------
|
|
uint64_t __fastcall RTech::DecompressPakFileInit(RPakDecompState_t* state, uint8_t* fileBuffer, uint64_t fileSize, uint64_t offNoHeader, uint64_t headerSize)
|
|
{
|
|
int64_t input_byte_pos_init; // r9
|
|
uint64_t byte_init; // r11
|
|
int32_t decompressed_size_bits; // ecx
|
|
int64_t byte_1_low; // rdi
|
|
uint64_t input_byte_pos_1; // r10
|
|
uint32_t bit_pos_final; // ebp
|
|
uint64_t byte_1; // rdi
|
|
uint32_t brih_bits; // er11
|
|
uint64_t inv_mask_in; // r8
|
|
uint64_t byte_final_full; // rbx
|
|
uint64_t bit_pos_final_1; // rax
|
|
int32_t byte_bit_offset_final; // ebp
|
|
uint64_t input_byte_pos_final; // r10
|
|
uint64_t byte_final; // rbx
|
|
uint32_t brih_bytes; // er11
|
|
uint64_t byte_tmp; // rdx
|
|
uint64_t stream_len_needed; // r14
|
|
uint64_t result; // rax
|
|
uint64_t inv_mask_out; // r8
|
|
uint64_t qw70; // rcx
|
|
uint64_t stream_compressed_size_new; // rdx
|
|
|
|
const uintptr_t mask = UINT64_MAX;
|
|
const uintptr_t file_buf = uintptr_t(fileBuffer);
|
|
|
|
state->m_nInputBuf = file_buf;
|
|
state->m_nOut = 0i64;
|
|
state->m_nOutMask = 0i64;
|
|
state->dword44 = 0;
|
|
state->m_nTotalFileLen = fileSize + offNoHeader;
|
|
state->m_nMask = mask;
|
|
input_byte_pos_init = offNoHeader + headerSize + 8;
|
|
byte_init = *(uint64_t*)((mask & (offNoHeader + headerSize)) + file_buf);
|
|
state->m_nDecompPosition = headerSize;
|
|
decompressed_size_bits = byte_init & 0x3F;
|
|
byte_init >>= 6;
|
|
state->m_nInputBytePos = input_byte_pos_init;
|
|
state->m_nDecompSize = byte_init & ((1i64 << decompressed_size_bits) - 1) | (1i64 << decompressed_size_bits);
|
|
byte_1_low = *(uint64_t*)((mask & input_byte_pos_init) + file_buf) << (64
|
|
- ((uint8_t)decompressed_size_bits
|
|
+ 6));
|
|
input_byte_pos_1 = input_byte_pos_init + ((uint64_t)(uint32_t)(decompressed_size_bits + 6) >> 3);
|
|
state->m_nInputBytePos = input_byte_pos_1;
|
|
bit_pos_final = ((decompressed_size_bits + 6) & 7) + 13;
|
|
byte_1 = (0xFFFFFFFFFFFFFFFFui64 >> ((decompressed_size_bits + 6) & 7)) & ((byte_init >> decompressed_size_bits) | byte_1_low);
|
|
brih_bits = (((uint8_t)byte_1 - 1) & 0x3F) + 1;
|
|
inv_mask_in = 0xFFFFFFFFFFFFFFFFui64 >> (64 - (uint8_t)brih_bits);
|
|
state->m_nInvMaskIn = inv_mask_in;
|
|
state->m_nInvMaskOut = 0xFFFFFFFFFFFFFFFFui64 >> (63 - (((byte_1 >> 6) - 1) & 0x3F));
|
|
byte_final_full = (byte_1 >> 13) | (*(uint64_t*)((mask & input_byte_pos_1) + file_buf) << (64
|
|
- (uint8_t)bit_pos_final));
|
|
bit_pos_final_1 = bit_pos_final;
|
|
byte_bit_offset_final = bit_pos_final & 7;
|
|
input_byte_pos_final = (bit_pos_final_1 >> 3) + input_byte_pos_1;
|
|
byte_final = (0xFFFFFFFFFFFFFFFFui64 >> byte_bit_offset_final) & byte_final_full;
|
|
state->m_nInputBytePos = input_byte_pos_final;
|
|
if (inv_mask_in == -1i64)
|
|
{
|
|
state->m_nHeaderOffset = 0;
|
|
stream_len_needed = fileSize;
|
|
}
|
|
else
|
|
{
|
|
brih_bytes = brih_bits >> 3;
|
|
state->m_nHeaderOffset = brih_bytes + 1;
|
|
byte_tmp = *(uint64_t*)((mask & input_byte_pos_final) + file_buf);
|
|
state->m_nInputBytePos = input_byte_pos_final + brih_bytes + 1;
|
|
stream_len_needed = byte_tmp & ((1i64 << (8 * ((uint8_t)brih_bytes + 1))) - 1);
|
|
}
|
|
result = state->m_nDecompSize;
|
|
inv_mask_out = state->m_nInvMaskOut;
|
|
qw70 = offNoHeader + state->m_nInvMaskIn - 6i64;
|
|
state->m_nLengthNeeded = stream_len_needed + offNoHeader;
|
|
state->qword70 = qw70;
|
|
state->byte = byte_final;
|
|
state->m_nByteBitOffset = byte_bit_offset_final;
|
|
state->dword6C = 0;
|
|
state->m_nCompressedStreamSize = stream_len_needed + offNoHeader;
|
|
state->m_nDecompStreamSize = result;
|
|
if (result - 1 > inv_mask_out)
|
|
{
|
|
stream_compressed_size_new = stream_len_needed + offNoHeader - state->m_nHeaderOffset;
|
|
state->m_nDecompStreamSize = inv_mask_out + 1;
|
|
state->m_nCompressedStreamSize = stream_compressed_size_new;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: decompress input data
|
|
//-----------------------------------------------------------------------------
|
|
uint8_t __fastcall RTech::DecompressPakFile(RPakDecompState_t* state, uint64_t inLen, uint64_t outLen)
|
|
{
|
|
uint64_t decompressed_position; // r15
|
|
uint32_t byte_bit_offset; // ebp
|
|
uint64_t byte; // rsi
|
|
uint64_t input_byte_pos; // rdi
|
|
uint64_t some_size; // r12
|
|
uint32_t dword6C; // ecx MAPDST
|
|
uint64_t v12; // rsi
|
|
uint64_t i; // rax
|
|
uint64_t dword6c_shl8; // r8
|
|
int64_t dword6c_old; // r9
|
|
int32_t LUT_200_val; // ecx
|
|
uint64_t v17; // rax
|
|
uint64_t byte_new; // rsi
|
|
int64_t LUT_0_VAL; // r14
|
|
int32_t byte_4bits_1; // ecx
|
|
uint64_t v21; // r11
|
|
int32_t v22; // edx
|
|
uint64_t out_mask; // rax
|
|
int32_t v24; // er8
|
|
uint32_t LUT_400_seek_backwards; // er13
|
|
uint64_t out_seek_back; // r10
|
|
uint64_t out_seekd_1; // rax
|
|
uint64_t* out_seekd_back; // r10
|
|
uint64_t decompressed_size; // r9
|
|
uint64_t inv_mask_in; // r10
|
|
uint64_t header_skip_bytes_bs; // r8
|
|
uint64_t v32; // rax
|
|
uint64_t v33; // rax
|
|
uint64_t v34; // rax
|
|
uint64_t stream_decompressed_size_new; // rcx
|
|
int64_t v36; // rdx
|
|
uint64_t len_needed_new; // r14
|
|
uint64_t stream_compressed_size_new; // r11
|
|
char v39; // cl MAPDST
|
|
uint64_t v40; // rsi MAPDST
|
|
uint64_t v46; // rcx
|
|
int64_t v47; // r9
|
|
int64_t m; // r8
|
|
uint32_t v49; // er9
|
|
int64_t v50; // r8
|
|
int64_t v51; // rdx
|
|
int64_t k; // r8
|
|
char* v53; // r10
|
|
int64_t v54; // rdx
|
|
uint32_t lut0_val_abs; // er14
|
|
int64_t* in_seekd; // rdx
|
|
int64_t* out_seekd; // r8
|
|
int64_t byte_3bits; // rax MAPDST
|
|
uint64_t byte_new_tmp; // r9 MAPDST
|
|
int32_t LUT_4D0_480; // er10 MAPDST
|
|
uint8_t LUT_4D8_4C0_nBits; // cl MAPDST
|
|
uint64_t byte_4bits; // rax MAPDST
|
|
uint32_t copy_bytes_ammount; // er14
|
|
uint32_t j; // ecx
|
|
int64_t v67; // rax
|
|
uint64_t v68; // rcx
|
|
uint8_t result; // al
|
|
|
|
if (inLen < state->m_nLengthNeeded)
|
|
return 0;
|
|
|
|
decompressed_position = state->m_nDecompPosition;
|
|
if (outLen < state->m_nInvMaskOut + (decompressed_position & ~state->m_nInvMaskOut) + 1 && outLen < state->m_nDecompSize)
|
|
return 0;
|
|
|
|
byte_bit_offset = state->m_nByteBitOffset; // Keeping copy since we increment it down below.
|
|
byte = state->byte; // Keeping copy since its getting overwritten down below.
|
|
input_byte_pos = state->m_nInputBytePos; // Keeping copy since we increment it down below.
|
|
some_size = state->qword70;
|
|
if (state->m_nCompressedStreamSize < some_size)
|
|
some_size = state->m_nCompressedStreamSize;
|
|
dword6C = state->dword6C;
|
|
|
|
if (!byte_bit_offset)
|
|
goto LABEL_9;
|
|
|
|
v12 = (*(uint64_t*)((input_byte_pos & state->m_nMask) + state->m_nInputBuf) << (64 - (uint8_t)byte_bit_offset)) | byte;
|
|
for (i = byte_bit_offset; ; i = byte_bit_offset)
|
|
{
|
|
byte_bit_offset &= 7u;
|
|
input_byte_pos += i >> 3;
|
|
byte = (0xFFFFFFFFFFFFFFFFui64 >> byte_bit_offset) & v12;
|
|
LABEL_9:
|
|
dword6c_shl8 = (uint64_t)dword6C << 8;
|
|
dword6c_old = dword6C;
|
|
LUT_200_val = LUT_200[(uint8_t)byte + dword6c_shl8];// LUT_200 - u8 - amount of bits
|
|
v17 = (uint8_t)byte + dword6c_shl8;
|
|
byte_bit_offset += LUT_200_val;
|
|
byte_new = byte >> LUT_200_val;
|
|
LUT_0_VAL = LUT_0[v17];// LUT_0 - i32 - signed, amount of bytes
|
|
|
|
if (LUT_0_VAL < 0)
|
|
{
|
|
lut0_val_abs = -(int32_t)LUT_0_VAL;
|
|
in_seekd = (int64_t*)(state->m_nInputBuf + (input_byte_pos & state->m_nMask));
|
|
dword6C = 1;
|
|
out_seekd = (int64_t*)(state->m_nOut + (decompressed_position & state->m_nOutMask));
|
|
if (lut0_val_abs == LUT_4E0[dword6c_old])
|
|
{
|
|
if ((~input_byte_pos & state->m_nInvMaskIn) < 0xF
|
|
|| (state->m_nInvMaskOut & ~decompressed_position) < 0xF
|
|
|| state->m_nDecompSize - decompressed_position < 0x10)
|
|
{
|
|
lut0_val_abs = 1;
|
|
}
|
|
|
|
v39 = byte_new;
|
|
v40 = byte_new >> 3;
|
|
byte_3bits = v39 & 7;
|
|
byte_new_tmp = v40;
|
|
|
|
if (byte_3bits)
|
|
{
|
|
LUT_4D0_480 = LUT_4D0[byte_3bits];// LUT_4D0 - u8
|
|
LUT_4D8_4C0_nBits = LUT_4D8[byte_3bits];// LUT_4D8 - u8 - amount of bits
|
|
}
|
|
else
|
|
{
|
|
byte_new_tmp = v40 >> 4;
|
|
byte_4bits = v40 & 15;
|
|
byte_bit_offset += 4;
|
|
LUT_4D0_480 = LUT_480[byte_4bits];// LUT_480 - u32
|
|
LUT_4D8_4C0_nBits = LUT_4C0[byte_4bits]; // LUT_4C0 - u8 - amount of bits???
|
|
}
|
|
|
|
byte_bit_offset += LUT_4D8_4C0_nBits + 3;
|
|
byte_new = byte_new_tmp >> LUT_4D8_4C0_nBits;
|
|
copy_bytes_ammount = LUT_4D0_480 + (byte_new_tmp & ((1 << LUT_4D8_4C0_nBits) - 1)) + lut0_val_abs;
|
|
|
|
for (j = copy_bytes_ammount >> 3; j; --j)// copy by 8 bytes
|
|
{
|
|
v67 = *in_seekd++;
|
|
*out_seekd++ = v67;
|
|
}
|
|
|
|
if ((copy_bytes_ammount & 4) != 0) // copy by 4
|
|
{
|
|
*(uint32_t*)out_seekd = *(uint32_t*)in_seekd;
|
|
out_seekd = (int64_t*)((char*)out_seekd + 4);
|
|
in_seekd = (int64_t*)((char*)in_seekd + 4);
|
|
}
|
|
|
|
if ((copy_bytes_ammount & 2) != 0) // copy by 2
|
|
{
|
|
*(uint16_t*)out_seekd = *(uint16_t*)in_seekd;
|
|
out_seekd = (int64_t*)((char*)out_seekd + 2);
|
|
in_seekd = (int64_t*)((char*)in_seekd + 2);
|
|
}
|
|
|
|
if ((copy_bytes_ammount & 1) != 0) // copy by 1
|
|
*(uint8_t*)out_seekd = *(uint8_t*)in_seekd;
|
|
|
|
input_byte_pos += copy_bytes_ammount;
|
|
decompressed_position += copy_bytes_ammount;
|
|
}
|
|
else
|
|
{
|
|
*out_seekd = *in_seekd;
|
|
out_seekd[1] = in_seekd[1];
|
|
input_byte_pos += lut0_val_abs;
|
|
decompressed_position += lut0_val_abs;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
byte_4bits_1 = byte_new & 0xF;
|
|
dword6C = 0;
|
|
v21 = ((uint64_t)(uint32_t)byte_new >> (((uint32_t)(byte_4bits_1 + 0xFFFFFFE1) >> 3) & 6)) & 0x3F;// 6 bits after shift for who knows how much???
|
|
v22 = 1 << (byte_4bits_1 + ((byte_new >> 4) & ((24 * (((uint32_t)(byte_4bits_1 + 0xFFFFFFE1) >> 3) & 2)) >> 4)));// amount of bits to read???
|
|
byte_bit_offset += (((uint32_t)(byte_4bits_1 + 0xFFFFFFE1) >> 3) & 6)// shit shit gets shifted by amount of bits it read or something
|
|
+ LUT_440[v21]
|
|
+ byte_4bits_1
|
|
+ ((byte_new >> 4) & ((24 * (((uint32_t)(byte_4bits_1 + 0xFFFFFFE1) >> 3) & 2)) >> 4));
|
|
out_mask = state->m_nOutMask;
|
|
v24 = 16
|
|
* (v22
|
|
+ ((v22 - 1) & (byte_new >> ((((uint32_t)(byte_4bits_1 + 0xFFFFFFE1) >> 3) & 6)
|
|
+ LUT_440[v21]))));
|
|
byte_new >>= (((uint32_t)(byte_4bits_1 + 0xFFFFFFE1) >> 3) & 6)
|
|
+ LUT_440[v21]
|
|
+ byte_4bits_1
|
|
+ ((byte_new >> 4) & ((24 * (((uint32_t)(byte_4bits_1 + 0xFFFFFFE1) >> 3) & 2)) >> 4));
|
|
LUT_400_seek_backwards = v24 + LUT_400[v21] - 16;// LUT_400 - u8 - seek backwards
|
|
out_seek_back = out_mask & (decompressed_position - LUT_400_seek_backwards);
|
|
out_seekd_1 = state->m_nOut + (decompressed_position & out_mask);
|
|
out_seekd_back = (uint64_t*)(state->m_nOut + out_seek_back);
|
|
if ((int32_t)LUT_0_VAL == 17)
|
|
{
|
|
v39 = byte_new;
|
|
v40 = byte_new >> 3;
|
|
byte_3bits = v39 & 7;
|
|
byte_new_tmp = v40;
|
|
if (byte_3bits)
|
|
{
|
|
LUT_4D0_480 = LUT_4D0[byte_3bits];
|
|
LUT_4D8_4C0_nBits = LUT_4D8[byte_3bits];
|
|
}
|
|
else
|
|
{
|
|
byte_bit_offset += 4;
|
|
byte_4bits = v40 & 0xF;
|
|
byte_new_tmp = v40 >> 4;
|
|
LUT_4D0_480 = LUT_480[byte_4bits];
|
|
LUT_4D8_4C0_nBits = LUT_4C0[byte_4bits];
|
|
if (state->m_nInputBuf && byte_bit_offset + LUT_4D8_4C0_nBits >= 0x3D)
|
|
{
|
|
v46 = input_byte_pos++ & state->m_nMask;
|
|
byte_new_tmp |= (uint64_t) * (uint8_t*)(v46 + state->m_nInputBuf) << (61
|
|
- (uint8_t)byte_bit_offset);
|
|
byte_bit_offset -= 8;
|
|
}
|
|
}
|
|
byte_bit_offset += LUT_4D8_4C0_nBits + 3;
|
|
byte_new = byte_new_tmp >> LUT_4D8_4C0_nBits;
|
|
v47 = ((uint32_t)byte_new_tmp & ((1 << LUT_4D8_4C0_nBits) - 1)) + LUT_4D0_480 + 17;
|
|
decompressed_position += v47;
|
|
if (LUT_400_seek_backwards < 8)
|
|
{
|
|
v49 = v47 - 13;
|
|
decompressed_position -= 13i64;
|
|
if (LUT_400_seek_backwards == 1) // 1 means copy v49 qwords?
|
|
{
|
|
v50 = *(uint8_t*)out_seekd_back;
|
|
v51 = 0i64;
|
|
for (k = 0x101010101010101i64 * v50; (uint32_t)v51 < v49; v51 = (uint32_t)(v51 + 8))
|
|
*(uint64_t*)(v51 + out_seekd_1) = k;
|
|
}
|
|
else
|
|
{
|
|
if (v49)
|
|
{
|
|
v53 = (char*)out_seekd_back - out_seekd_1;
|
|
v54 = v49;
|
|
do
|
|
{
|
|
*(uint8_t*)out_seekd_1 = v53[out_seekd_1];// seeked = seek_back; increment ptrs
|
|
++out_seekd_1;
|
|
--v54;
|
|
} while (v54);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (m = 0i64; (uint32_t)m < (uint32_t)v47; m = (uint32_t)(m + 8))
|
|
*(uint64_t*)(m + out_seekd_1) = *(uint64_t*)((char*)out_seekd_back + m);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
decompressed_position += LUT_0_VAL;
|
|
*(uint64_t*)out_seekd_1 = *out_seekd_back;
|
|
*(uint64_t*)(out_seekd_1 + 8) = out_seekd_back[1];
|
|
}
|
|
}
|
|
if (input_byte_pos >= some_size)
|
|
break;
|
|
|
|
LABEL_26:
|
|
v12 = (*(uint64_t*)((input_byte_pos & state->m_nMask) + state->m_nInputBuf) << (64 - (uint8_t)byte_bit_offset)) | byte_new;
|
|
}
|
|
|
|
if (decompressed_position != state->m_nDecompStreamSize)
|
|
goto LABEL_22;
|
|
|
|
decompressed_size = state->m_nDecompSize;
|
|
if (decompressed_position == decompressed_size)
|
|
{
|
|
state->m_nInputBytePos = input_byte_pos;
|
|
result = 1;
|
|
state->m_nDecompPosition = decompressed_position;
|
|
return result;
|
|
}
|
|
|
|
inv_mask_in = state->m_nInvMaskIn;
|
|
header_skip_bytes_bs = state->m_nHeaderOffset;
|
|
v32 = inv_mask_in & -(int64_t)input_byte_pos;
|
|
byte_new >>= 1;
|
|
++byte_bit_offset;
|
|
|
|
if (header_skip_bytes_bs > v32)
|
|
{
|
|
input_byte_pos += v32;
|
|
v33 = state->qword70;
|
|
if (input_byte_pos > v33)
|
|
state->qword70 = inv_mask_in + v33 + 1;
|
|
}
|
|
|
|
v34 = input_byte_pos & state->m_nMask;
|
|
input_byte_pos += header_skip_bytes_bs;
|
|
stream_decompressed_size_new = decompressed_position + state->m_nInvMaskOut + 1;
|
|
v36 = *(uint64_t*)(v34 + state->m_nInputBuf) & ((1LL << (8 * (uint8_t)header_skip_bytes_bs)) - 1);
|
|
len_needed_new = v36 + state->m_nLengthNeeded;
|
|
stream_compressed_size_new = v36 + state->m_nCompressedStreamSize;
|
|
state->m_nLengthNeeded = len_needed_new;
|
|
state->m_nCompressedStreamSize = stream_compressed_size_new;
|
|
|
|
if (stream_decompressed_size_new >= decompressed_size)
|
|
{
|
|
stream_decompressed_size_new = decompressed_size;
|
|
state->m_nCompressedStreamSize = header_skip_bytes_bs + stream_compressed_size_new;
|
|
}
|
|
|
|
state->m_nDecompStreamSize = stream_decompressed_size_new;
|
|
|
|
if (inLen >= len_needed_new && outLen >= stream_decompressed_size_new)
|
|
{
|
|
LABEL_22:
|
|
some_size = state->qword70;
|
|
if (input_byte_pos >= some_size)
|
|
{
|
|
input_byte_pos = ~state->m_nInvMaskIn & (input_byte_pos + 7);
|
|
some_size += state->m_nInvMaskIn + 1;
|
|
state->qword70 = some_size;
|
|
}
|
|
if (state->m_nCompressedStreamSize < some_size)
|
|
some_size = state->m_nCompressedStreamSize;
|
|
goto LABEL_26;
|
|
}
|
|
|
|
v68 = state->qword70;
|
|
|
|
if (input_byte_pos >= v68)
|
|
{
|
|
input_byte_pos = ~inv_mask_in & (input_byte_pos + 7);
|
|
state->qword70 = v68 + inv_mask_in + 1;
|
|
}
|
|
|
|
state->dword6C = dword6C;
|
|
result = 0;
|
|
state->m_nInputBytePos = input_byte_pos;
|
|
state->m_nDecompPosition = decompressed_position;
|
|
state->byte = byte_new;
|
|
state->m_nByteBitOffset = byte_bit_offset;
|
|
|
|
return result;
|
|
}
|
|
|
|
#if not defined DEDICATED
|
|
|
|
#pragma warning( push )
|
|
// Disable stack warning, tells us to move more data to the heap instead. Not really possible with 'initialData' here. Since its parallel processed.
|
|
// Also disable 6378, complains that there is no control path where it would use 'nullptr', if that happens 'Error' will be called though.
|
|
#pragma warning( disable : 6262 6387)
|
|
constexpr uint32_t ALIGNMENT_SIZE = 15; // Used by the game in CreateDXTexture.
|
|
//----------------------------------------------------------------------------------
|
|
// Purpose: creates 2D texture and shader resource from textureHeader and imageData.
|
|
//----------------------------------------------------------------------------------
|
|
void RTech::CreateDXTexture(TextureHeader_t* textureHeader, int64_t imageData)
|
|
{
|
|
if (textureHeader->m_nDepth && !textureHeader->m_nHeight) // Return never gets hit. Maybe its some debug check?
|
|
return;
|
|
|
|
__int64 initialData[4096]{};
|
|
textureHeader->m_nTextureMipLevels = textureHeader->m_nPermanentMipCount;
|
|
|
|
const int totalStreamedMips = textureHeader->m_nOptStreamedMipCount + textureHeader->m_nStreamedMipCount;
|
|
uint32_t mipLevel = textureHeader->m_nPermanentMipCount + totalStreamedMips;
|
|
if (mipLevel != totalStreamedMips)
|
|
{
|
|
do
|
|
{
|
|
--mipLevel;
|
|
if (textureHeader->m_nArraySize)
|
|
{
|
|
int mipWidth = 0;
|
|
if (textureHeader->m_nWidth >> mipLevel > 1)
|
|
mipWidth = (textureHeader->m_nWidth >> mipLevel) - 1;
|
|
|
|
int mipHeight = 0;
|
|
if (textureHeader->m_nHeight >> mipLevel > 1)
|
|
mipHeight = (textureHeader->m_nHeight >> mipLevel) - 1;
|
|
|
|
uint8_t x = s_pBytesPerPixel[textureHeader->m_nImageFormat].first;
|
|
uint8_t y = s_pBytesPerPixel[textureHeader->m_nImageFormat].second;
|
|
|
|
uint32_t bppWidth = (y + mipWidth) >> (y >> 1);
|
|
uint32_t bppHeight = (y + mipHeight) >> (y >> 1);
|
|
uint32_t sliceWidth = x * (y >> (y >> 1));
|
|
|
|
uint32_t rowPitch = sliceWidth * bppWidth;
|
|
uint32_t slicePitch = x * bppWidth * bppHeight;
|
|
|
|
uint32_t subResourceEntry = mipLevel;
|
|
for (int i = 0; i < textureHeader->m_nArraySize; i++)
|
|
{
|
|
uint32_t offsetCurrentResourceData = subResourceEntry << 4u;
|
|
|
|
*(int64_t*)((uint8_t*)initialData + offsetCurrentResourceData) = imageData;
|
|
*(uint32_t*)((uint8_t*)&initialData[1] + offsetCurrentResourceData) = rowPitch;
|
|
*(uint32_t*)((uint8_t*)&initialData[1] + offsetCurrentResourceData + 4) = slicePitch;
|
|
|
|
imageData += (slicePitch + ALIGNMENT_SIZE) & ~ALIGNMENT_SIZE;
|
|
subResourceEntry += textureHeader->m_nPermanentMipCount;
|
|
}
|
|
}
|
|
} while (mipLevel != totalStreamedMips);
|
|
}
|
|
|
|
const DXGI_FORMAT dxgiFormat = s_TxtrToDxgiTable.at(textureHeader->m_nImageFormat); // Get dxgi format
|
|
|
|
D3D11_TEXTURE2D_DESC textureDesc{};
|
|
textureDesc.Width = textureHeader->m_nWidth >> mipLevel;
|
|
textureDesc.Height = textureHeader->m_nHeight >> mipLevel;
|
|
textureDesc.MipLevels = textureHeader->m_nPermanentMipCount;
|
|
textureDesc.ArraySize = textureHeader->m_nArraySize;
|
|
textureDesc.Format = dxgiFormat;
|
|
textureDesc.SampleDesc.Count = 1;
|
|
textureDesc.SampleDesc.Quality = 0;
|
|
textureDesc.Usage = textureHeader->m_nCPUAccessFlag != 2 ? D3D11_USAGE_IMMUTABLE : D3D11_USAGE_DEFAULT;
|
|
textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
|
textureDesc.MiscFlags = 0;
|
|
|
|
const uint32_t offsetStartResourceData = mipLevel << 4u;
|
|
const D3D11_SUBRESOURCE_DATA* subResData = (D3D11_SUBRESOURCE_DATA*)((uint8_t*)initialData + offsetStartResourceData);
|
|
const HRESULT createTextureRes = (*g_ppGameDevice)->CreateTexture2D(&textureDesc, subResData, &textureHeader->m_ppTexture);
|
|
if (createTextureRes < S_OK)
|
|
Error(eDLL_T::RTECH, EXIT_FAILURE, "Couldn't create texture \"%s\": error code = %08x\n", textureHeader->m_pDebugName, createTextureRes);
|
|
|
|
D3D11_SHADER_RESOURCE_VIEW_DESC shaderResource{};
|
|
shaderResource.Format = dxgiFormat;
|
|
shaderResource.Texture2D.MipLevels = textureHeader->m_nTextureMipLevels;
|
|
if (textureHeader->m_nArraySize > 1) // Do we have a texture array?
|
|
{
|
|
shaderResource.Texture2DArray.FirstArraySlice = 0;
|
|
shaderResource.Texture2DArray.ArraySize = textureHeader->m_nArraySize;
|
|
shaderResource.ViewDimension = D3D_SRV_DIMENSION_TEXTURE2DARRAY;
|
|
}
|
|
else
|
|
{
|
|
shaderResource.ViewDimension = D3D_SRV_DIMENSION_TEXTURE2D;
|
|
}
|
|
|
|
const HRESULT createShaderResourceRes = (*g_ppGameDevice)->CreateShaderResourceView(textureHeader->m_ppTexture, &shaderResource, &textureHeader->m_ppShaderResourceView);
|
|
if (createShaderResourceRes < S_OK)
|
|
Error(eDLL_T::RTECH, EXIT_FAILURE, "Couldn't create shader resource view for texture \"%s\": error code = %08x\n", textureHeader->m_pDebugName, createShaderResourceRes);
|
|
}
|
|
#pragma warning( pop )
|
|
#endif
|
|
|
|
#ifndef DEDICATED
|
|
//----------------------------------------------------------------------------------
|
|
// Purpose: start loading shader sets, assign vftable pointer
|
|
//----------------------------------------------------------------------------------
|
|
void** RTech::LoadShaderSet(void** VTablePtr)
|
|
{
|
|
*VTablePtr = &g_pShaderGlueVFTable;
|
|
return &g_pShaderGlueVFTable;
|
|
}
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------------------
|
|
// Purpose: open a file and add it to m_FileHandles.
|
|
//----------------------------------------------------------------------------------
|
|
int32_t RTech::OpenFile(const CHAR* szFilePath, void* unused, LONGLONG* fileSizeOut)
|
|
{
|
|
string svModFile = szFilePath;
|
|
string svBaseFile = szFilePath;
|
|
const string svModDir = "paks\\Win32\\";
|
|
const string svBaseDir = "paks\\Win64\\";
|
|
|
|
if (strstr(ConvertToWinPath(szFilePath).c_str(), svBaseDir.c_str()))
|
|
{
|
|
svBaseFile.erase(0, 11); // Erase 'base_dir'.
|
|
svModFile = svModDir + svBaseFile; // Prepend 'mod_dir'.
|
|
|
|
if (!FileExists(svModFile))
|
|
{
|
|
svModFile = szFilePath;
|
|
}
|
|
}
|
|
|
|
const HANDLE hFile = CreateFileA(svModFile.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_SUPPORTS_GHOSTING, 0);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
return -1;
|
|
|
|
if (rtech_debug->GetBool())
|
|
DevMsg(eDLL_T::RTECH, "Opened file: '%s'\n", svModFile.c_str());
|
|
|
|
if (fileSizeOut)
|
|
{
|
|
LARGE_INTEGER fileSize{};
|
|
if (GetFileSizeEx(hFile, &fileSize))
|
|
*fileSizeOut = fileSize.QuadPart;
|
|
}
|
|
|
|
AcquireSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&*g_pPakFileSlotLock));
|
|
const int32_t fileIdx = RTech_FindFreeSlotInFiles(s_pFileArray);
|
|
ReleaseSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&*g_pPakFileSlotLock));
|
|
|
|
const int32_t fileHandleIdx = (fileIdx & 0x3FF); // Something with ArraySize.
|
|
|
|
m_FileHandles->self[fileHandleIdx].m_nFileNumber = fileIdx;
|
|
m_FileHandles->self[fileHandleIdx].m_hFileHandle = hFile;
|
|
m_FileHandles->self[fileHandleIdx].m_nCurOfs = 1;
|
|
|
|
return fileIdx;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: gets information about loaded pak file via pak ID
|
|
//-----------------------------------------------------------------------------
|
|
RPakLoadedInfo_t* RTech::GetPakLoadedInfo(RPakHandle_t nHandle)
|
|
{
|
|
for (int16_t i = 0; i < *s_pLoadedPakCount; ++i)
|
|
{
|
|
RPakLoadedInfo_t* info = &g_pLoadedPakInfo[i];
|
|
if (!info)
|
|
continue;
|
|
|
|
if (info->m_nHandle != nHandle)
|
|
continue;
|
|
|
|
return info;
|
|
}
|
|
|
|
Warning(eDLL_T::RTECH, "%s - Failed to retrieve pak info for handle '%d'\n", __FUNCTION__, nHandle);
|
|
return nullptr;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: gets information about loaded pak file via pak name
|
|
//-----------------------------------------------------------------------------
|
|
RPakLoadedInfo_t* RTech::GetPakLoadedInfo(const char* szPakName)
|
|
{
|
|
for (int16_t i = 0; i < *s_pLoadedPakCount; ++i)
|
|
{
|
|
RPakLoadedInfo_t* info = &g_pLoadedPakInfo[i];
|
|
if (!info)
|
|
continue;
|
|
|
|
if (!info->m_pszFileName || !*info->m_pszFileName)
|
|
continue;
|
|
|
|
if (strcmp(szPakName, info->m_pszFileName) != 0)
|
|
continue;
|
|
|
|
return info;
|
|
}
|
|
|
|
Warning(eDLL_T::RTECH, "%s - Failed to retrieve pak info for name '%s'\n", __FUNCTION__, szPakName);
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: process guid relations for asset
|
|
//-----------------------------------------------------------------------------
|
|
void RTech::PakProcessGuidRelationsForAsset(PakFile_t* pPak, RPakAssetEntry_t* pAsset)
|
|
{
|
|
RPakDescriptor_t* pGuidDescriptors = &pPak->m_pGuidDescriptors[pAsset->m_nUsesStartIdx];
|
|
volatile uint32_t* v5 = reinterpret_cast<volatile uint32_t*>(*(reinterpret_cast<uint64_t*>(g_pUnknownPakStruct) + 0x17 * (pPak->qword578 & 0x1FF) + 0x160212));
|
|
const bool bDebug = rtech_debug->GetBool();
|
|
|
|
if (bDebug)
|
|
DevMsg(eDLL_T::RTECH, "Processing GUID relations for asset '0x%-16llX' in pak '%-32s'. Uses: %-4i\n", pAsset->m_Guid, pPak->m_pszFileName, pAsset->m_nUsesCount);
|
|
|
|
for (uint32_t i = 0; i < pAsset->m_nUsesCount; i++)
|
|
{
|
|
void** pCurrentGuid = reinterpret_cast<void**>(pPak->m_ppPagePointers[pGuidDescriptors[i].m_Index] + pGuidDescriptors[i].m_Offset);
|
|
|
|
// Get current guid.
|
|
const uint64_t currentGuid = reinterpret_cast<uint64_t>(*pCurrentGuid);
|
|
|
|
// Get asset index.
|
|
int assetIdx = currentGuid & 0x3FFFF;
|
|
uint64_t assetIdxEntryGuid = g_pUnknownPakStruct->m_Assets[assetIdx].m_Guid;
|
|
|
|
const int64_t v9 = 2i64 * InterlockedExchangeAdd(v5, 1u);
|
|
*reinterpret_cast<uint64_t*>(const_cast<uint32_t*>(&v5[2 * v9 + 2])) = currentGuid;
|
|
*reinterpret_cast<uint64_t*>(const_cast<uint32_t*>(&v5[2 * v9 + 4])) = pAsset->m_Guid;
|
|
|
|
std::function<bool(bool)> fnCheckAsset = [&](bool shouldCheckTwo)
|
|
{
|
|
while (true)
|
|
{
|
|
if (shouldCheckTwo && assetIdxEntryGuid == 2)
|
|
{
|
|
if (pPak->m_PakHdr.m_nAssetEntryCount)
|
|
return false;
|
|
}
|
|
|
|
assetIdx++;
|
|
|
|
// Check if we have a deadlock and report it if we have rtech_debug enabled.
|
|
if (bDebug && assetIdx >= 0x40000)
|
|
{
|
|
Warning(eDLL_T::RTECH, "Possible deadlock detected while processing asset '0x%-16llX' in pak '%-32s'. Uses: %-4i | assetIdxEntryGuid: '0x%-16llX' | currentGuid: '0x%-16llX'\n", pAsset->m_Guid, pPak->m_pszFileName, pAsset->m_nUsesCount, assetIdxEntryGuid, currentGuid);
|
|
if (IsDebuggerPresent())
|
|
DebugBreak();
|
|
}
|
|
|
|
assetIdx &= 0x3FFFF;
|
|
assetIdxEntryGuid = g_pUnknownPakStruct->m_Assets[assetIdx].m_Guid;
|
|
|
|
if (assetIdxEntryGuid == currentGuid)
|
|
return true;
|
|
}
|
|
};
|
|
|
|
if (assetIdxEntryGuid != currentGuid)
|
|
{
|
|
// Are we some special asset with the guid 2?
|
|
if (!fnCheckAsset(true))
|
|
{
|
|
RPakAssetEntry_t* assetEntries = pPak->m_pAssetEntries;
|
|
uint64_t a = 0;
|
|
|
|
for (; assetEntries->m_Guid != currentGuid; a++, assetEntries++)
|
|
{
|
|
if (a >= pPak->m_PakHdr.m_nAssetEntryCount)
|
|
{
|
|
fnCheckAsset(false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
assetIdx = pPak->qword580[a];
|
|
}
|
|
}
|
|
|
|
// Finally write the pointer to the guid entry.
|
|
*pCurrentGuid = g_pUnknownPakStruct->m_Assets[assetIdx].m_pHead;
|
|
}
|
|
}
|
|
|
|
void V_RTechUtils::Attach() const
|
|
{
|
|
DetourAttach(&RTech_OpenFile, &RTech::OpenFile);
|
|
|
|
#ifdef GAMEDLL_S3
|
|
DetourAttach(&RTech_Pak_ProcessGuidRelationsForAsset, &RTech::PakProcessGuidRelationsForAsset);
|
|
#endif
|
|
|
|
#if not defined DEDICATED && defined GAMEDLL_S3
|
|
DetourAttach(&RTech_CreateDXTexture, &RTech::CreateDXTexture);
|
|
#endif // !DEDICATED
|
|
}
|
|
|
|
void V_RTechUtils::Detach() const
|
|
{
|
|
DetourDetach(&RTech_OpenFile, &RTech::OpenFile);
|
|
|
|
#ifdef GAMEDLL_S3
|
|
DetourDetach(&RTech_Pak_ProcessGuidRelationsForAsset, &RTech::PakProcessGuidRelationsForAsset);
|
|
#endif
|
|
|
|
#if not defined DEDICATED && defined GAMEDLL_S3
|
|
DetourDetach(&RTech_CreateDXTexture, &RTech::CreateDXTexture);
|
|
#endif // !DEDICATED
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
RTech* g_pRTech = new RTech();
|