Короче по поводу добавления новых текстурок в редукс. Я чё-то это не доделал и не выложил этот хак, надо наверное всё-таки выложить.
Нажмите для просмотра прикрепленного файлаНу и наверно нужно небольшое пояснение о том как это работает. Во первых нам потребуется сконструировать str_shared, т.к. функция загрузки опций текстуры принимает её в качестве параметра.
CODE
LPVOID p4 = LPBYTE(hMetro2033) + 0x0063CC50; // str_container::do_dock
memcpy(&str_container_do_dock, &p4, sizeof(void*));
g_string_container = (void**)(LPBYTE(hMetro2033) + 0x00D00C10);
CODE
struct shared_string;
void **g_string_container;
shared_string * (*str_container_do_dock)(void *_arg1, const void *data, int length, int type);
shared_string * mk_shared_string(const char *str)
{
return str_container_do_dock(*g_string_container, str, strlen(str), 0);
}
Работают эти общие строчки вроде так же как и в сталкире, за исключением того что добавился ещё тип строки (последний параметр str_container_do_dock, который тут равен 0).
Дальше нужны ещё две функции из движка, первая, которая перебирает все опции текстур в content.vfs и загружает их, и вторая которая загружает один файл с опциями.
CODE
LPVOID p1 = LPBYTE(hMetro2033) + 0x000DE404; // texture_manager::load_all_handles
LPVOID p2 = SetHookEx(p1, LPVOID(override_texture_manager_load_all_handles), 15);
memcpy(&real_texture_manager_load_all_handles, &p2, sizeof(void*));
LPVOID p3 = LPBYTE(hMetro2033) + 0x000DE550; // texture_manager::load_handle
memcpy(&texture_manager_load_handle, &p3, sizeof(void*));
g_texture_manager = (void**)(LPBYTE(hMetro2033) + 0x00D00DE8);
CODE
void **g_texture_manager;
void (*real_texture_manager_load_all_handles)(void);
void (*texture_manager_load_handle)(void *_arg1, shared_string **name);
void process_dir(const char *dir)
{
WIN32_FIND_DATA fd;
HANDLE hFind;
char str[MAX_PATH];
char *ext;
shared_string *s;
// 1. Process subsequent directories
strcpy(str, "content\\textures\\");
if(dir[0] != '\0') {
strcat(str, dir);
strcat(str, "\\*");
} else {
strcat(str, "*");
}
hFind = FindFirstFile(str, &fd);
if(hFind != INVALID_HANDLE_VALUE) {
do {
if(strcmp(fd.cFileName, ".") == 0)
continue;
if(strcmp(fd.cFileName, "..") == 0)
continue;
if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
if(dir[0] != '\0') {
strcpy(str, dir);
strcat(str, "\\");
strcat(str, fd.cFileName);
} else {
strcpy(str, fd.cFileName);
}
process_dir(str);
}
} while(FindNextFile(hFind, &fd));
FindClose(hFind);
}
// 2. Process .bin files
strcpy(str, "content\\textures\\");
if(dir[0] != '\0') {
strcat(str, dir);
strcat(str, "\\*.bin");
} else {
strcat(str, "*.bin");
}
hFind = FindFirstFile(str, &fd);
if(hFind != INVALID_HANDLE_VALUE) {
do {
if(strcmp(fd.cFileName, ".") == 0)
continue;
if(strcmp(fd.cFileName, "..") == 0)
continue;
if((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
if(dir[0] != '\0') {
strcpy(str, dir);
strcat(str, "\\");
strcat(str, fd.cFileName);
} else {
strcpy(str, fd.cFileName);
}
// cut the extension
// string is always end with ".bin", so it's safe
ext = str + strlen(str) - 4;
*ext = '\0';
// make shared string and load texture options
s = mk_shared_string(str);
texture_manager_load_handle(*g_texture_manager, &s);
}
} while(FindNextFile(hFind, &fd));
FindClose(hFind);
}
}
void override_texture_manager_load_all_handles(void)
{
// 1. call original function (load all handles in archives)
real_texture_manager_load_all_handles();
// 2. add handles fom content folder
process_dir("");
}
Честно говоря я уже не помню как я нашел эти функции. Первую толи по коллстеку из функции загрузки опций одной текстуры, толи по тому что там используется строка "*.bin". Вторая функция в оригинальном движке (в PDBшке точнее) имеет какое-то аццкое имя чуть ли не тысячу символов длинной, потому что там очень интенсивно используются всякие шаблоны, и я даже не хочу ничего об этом вспоминать.
Короче первая функция нужна нам только для того чтобы на неё повесить хук, и сразу после перебора файлов в content.vfs вызвать перебор файлов в распакованной папке. Вторая нужна по прямому назначению, для загрузки опций. Перебор файлов делается стандартными виндовыми функциями, ничего удивительного в этом нет.
У меня в такому решению есть пара вопросов. Во первых возможно тут утекает общая строка с именем текстуры, т.к. в оригинальном движке этот класс с автоматическим счётчиком ссылок, чего я не сделал. А может и не утекает, я во всех этих хитросплетениях C++ плохо ориентируюсь. Во вторых тут получается так что если вы подменяете опции текстур которые уже есть в content.vfs то они будут загружены два раза (оба раза изменённый файл из папки content). Не знаю на сколько это плохо, но у меня вроде ничего не крашится, хотя я только с один файлом проверял.
С другой стороны для того чтобы избежать повторной загрузки нужно проверять есть ли файл с таким именем в архиве прежде чем загружать, а как это сделать аккуратно я не знаю, т.к. функции vfs::exist как в арктике в редаксе ещё вроде нет, ну или я её не нашел, а если проверять функцией открытия файла то потом непонятно как его закрыть, т.к. этот момент я не исследовал.