Support custom imagefiles
This commit is contained in:
parent
e90f0a2343
commit
d42f36af50
151
src/client/component/imagefiles.cpp
Normal file
151
src/client/component/imagefiles.cpp
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "loader/component_loader.hpp"
|
||||||
|
|
||||||
|
#include "images.hpp"
|
||||||
|
#include "console.hpp"
|
||||||
|
#include "filesystem.hpp"
|
||||||
|
#include "fastfiles.hpp"
|
||||||
|
#include "scheduler.hpp"
|
||||||
|
|
||||||
|
#include "game/game.hpp"
|
||||||
|
|
||||||
|
#include <utils/hook.hpp>
|
||||||
|
#include <utils/string.hpp>
|
||||||
|
#include <utils/io.hpp>
|
||||||
|
#include <utils/concurrency.hpp>
|
||||||
|
|
||||||
|
#define CUSTOM_IMAGE_FILE_INDEX 96
|
||||||
|
|
||||||
|
namespace imagefiles
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct image_file_unk
|
||||||
|
{
|
||||||
|
char __pad0[120];
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<std::string, image_file_unk*> image_file_unk_map;
|
||||||
|
std::unordered_map<std::string, game::DB_IFileSysFile*> image_file_handles;
|
||||||
|
|
||||||
|
std::string get_image_file_name()
|
||||||
|
{
|
||||||
|
return fastfiles::get_current_fastfile();
|
||||||
|
}
|
||||||
|
|
||||||
|
image_file_unk* get_image_file_unk(unsigned int index)
|
||||||
|
{
|
||||||
|
if (index != CUSTOM_IMAGE_FILE_INDEX)
|
||||||
|
{
|
||||||
|
return &reinterpret_cast<image_file_unk*>(
|
||||||
|
SELECT_VALUE(0x4802090_b, 0x6306770_b))[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto name = get_image_file_name();
|
||||||
|
if (image_file_unk_map.find(name) == image_file_unk_map.end())
|
||||||
|
{
|
||||||
|
const auto unk = utils::memory::get_allocator()->allocate<image_file_unk>();
|
||||||
|
image_file_unk_map[name] = unk;
|
||||||
|
return unk;
|
||||||
|
}
|
||||||
|
|
||||||
|
return image_file_unk_map[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
game::DB_IFileSysFile* get_image_file_handle(unsigned int index)
|
||||||
|
{
|
||||||
|
if (index != CUSTOM_IMAGE_FILE_INDEX)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<game::DB_IFileSysFile**>(
|
||||||
|
SELECT_VALUE(0x4801D80_b, 0x6306180_b))[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto name = get_image_file_name();
|
||||||
|
return image_file_handles[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
void db_create_gfx_image_stream_stub(utils::hook::assembler& a)
|
||||||
|
{
|
||||||
|
const auto check_image_file_handle = a.newLabel();
|
||||||
|
const auto handle_is_open = a.newLabel();
|
||||||
|
|
||||||
|
a.movzx(eax, cx);
|
||||||
|
a.push(rax);
|
||||||
|
a.push(rax);
|
||||||
|
a.pushad64();
|
||||||
|
a.mov(rcx, rax);
|
||||||
|
a.call_aligned(get_image_file_unk);
|
||||||
|
a.mov(qword_ptr(rsp, 0x80), rax);
|
||||||
|
a.popad64();
|
||||||
|
a.pop(rax);
|
||||||
|
a.mov(rsi, rax);
|
||||||
|
a.pop(rax);
|
||||||
|
|
||||||
|
a.push(rax);
|
||||||
|
a.push(rax);
|
||||||
|
a.pushad64();
|
||||||
|
a.mov(rcx, rax);
|
||||||
|
a.call_aligned(get_image_file_handle);
|
||||||
|
a.mov(qword_ptr(rsp, 0x80), rax);
|
||||||
|
a.popad64();
|
||||||
|
a.pop(rax);
|
||||||
|
a.mov(r12, rax);
|
||||||
|
a.pop(rax);
|
||||||
|
|
||||||
|
a.cmp(r12, r13);
|
||||||
|
a.jnz(handle_is_open);
|
||||||
|
a.jmp(SELECT_VALUE(0x1FAD49_b, 0x3A0CA5_b));
|
||||||
|
|
||||||
|
a.bind(handle_is_open);
|
||||||
|
a.jmp(SELECT_VALUE(0x1FAD99_b, 0x3A0CF5_b));
|
||||||
|
}
|
||||||
|
|
||||||
|
void* pakfile_open_stub(void* /*handles*/, unsigned int count, int is_imagefile,
|
||||||
|
unsigned int index, int is_localized)
|
||||||
|
{
|
||||||
|
if (index != CUSTOM_IMAGE_FILE_INDEX)
|
||||||
|
{
|
||||||
|
return utils::hook::invoke<void*>(
|
||||||
|
SELECT_VALUE(0x42BC00_b, 0x5B2030_b),
|
||||||
|
SELECT_VALUE(0x4801D80_b, 0x6306180_b),
|
||||||
|
count, is_imagefile, index, is_localized
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto name = get_image_file_name();
|
||||||
|
const auto db_fs = *game::db_fs;
|
||||||
|
const auto handle = db_fs->vftbl->OpenFile(db_fs,
|
||||||
|
game::SF_PAKFILE, utils::string::va("%s.pak", name.data()));
|
||||||
|
if (handle != nullptr)
|
||||||
|
{
|
||||||
|
image_file_handles[name] = handle;
|
||||||
|
}
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
int com_sprintf_stub(char* buffer, const int len, const char* fmt, unsigned int index)
|
||||||
|
{
|
||||||
|
if (index != CUSTOM_IMAGE_FILE_INDEX)
|
||||||
|
{
|
||||||
|
return game::Com_sprintf(buffer, len, fmt, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto name = get_image_file_name();
|
||||||
|
return game::Com_sprintf(buffer, len, "%s.pak", name.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class component final : public component_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void post_unpack() override
|
||||||
|
{
|
||||||
|
utils::hook::jump(SELECT_VALUE(0x1FAD35_b, 0x3A0C95_b),
|
||||||
|
utils::hook::assemble(db_create_gfx_image_stream_stub), true);
|
||||||
|
utils::hook::call(SELECT_VALUE(0x1FAD7B_b, 0x3A0CD7_b), pakfile_open_stub);
|
||||||
|
utils::hook::call(SELECT_VALUE(0x1FAD5D_b, 0x3A0CB9_b), com_sprintf_stub);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_COMPONENT(imagefiles::component)
|
@ -223,6 +223,40 @@ namespace game
|
|||||||
SF_COUNT = 0x6,
|
SF_COUNT = 0x6,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum FileSysResult : std::int32_t
|
||||||
|
{
|
||||||
|
FILESYSRESULT_SUCCESS = 0x0,
|
||||||
|
FILESYSRESULT_EOF = 0x1,
|
||||||
|
FILESYSRESULT_ERROR = 0x2,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DB_IFileSysFile
|
||||||
|
{
|
||||||
|
void* file;
|
||||||
|
uint64_t last_read;
|
||||||
|
uint64_t bytes_read;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(DB_IFileSysFile) == 24);
|
||||||
|
|
||||||
|
struct DB_FileSysInterface;
|
||||||
|
|
||||||
|
// this is a best guess, interface doesn't match up exactly w/other games (IW8, T9)
|
||||||
|
struct DB_FileSysInterface_vtbl
|
||||||
|
{
|
||||||
|
DB_IFileSysFile* (__fastcall* OpenFile)(DB_FileSysInterface* _this, Sys_Folder folder, const char* filename);
|
||||||
|
FileSysResult(__fastcall* Read)(DB_FileSysInterface* _this, DB_IFileSysFile* handle, unsigned __int64 offset, unsigned __int64 size, void* dest);
|
||||||
|
FileSysResult(__fastcall* Tell)(DB_FileSysInterface* _this, DB_IFileSysFile* handle, unsigned __int64* bytesRead);
|
||||||
|
__int64(__fastcall* Size)(DB_FileSysInterface* _this, DB_IFileSysFile* handle);
|
||||||
|
void(__fastcall* Close)(DB_FileSysInterface* _this, DB_IFileSysFile* handle);
|
||||||
|
bool(__fastcall* Exists)(DB_FileSysInterface* _this, Sys_Folder folder, const char* filename);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DB_FileSysInterface
|
||||||
|
{
|
||||||
|
DB_FileSysInterface_vtbl* vftbl;
|
||||||
|
};
|
||||||
|
|
||||||
enum CodPlayMode
|
enum CodPlayMode
|
||||||
{
|
{
|
||||||
CODPLAYMODE_NONE = 0x0,
|
CODPLAYMODE_NONE = 0x0,
|
||||||
|
@ -315,6 +315,8 @@ namespace game
|
|||||||
WEAK symbol<void*> DB_XAssetPool{0xEC9FB0, 0x10B4460};
|
WEAK symbol<void*> DB_XAssetPool{0xEC9FB0, 0x10B4460};
|
||||||
WEAK symbol<const char*> g_assetNames{0x991BA0, 0x10B30D0};
|
WEAK symbol<const char*> g_assetNames{0x991BA0, 0x10B30D0};
|
||||||
|
|
||||||
|
WEAK symbol< DB_FileSysInterface*> db_fs{0x25C1168, 0x1566C08};
|
||||||
|
|
||||||
WEAK symbol<int> keyCatchers{0x252AF70, 0x2EC82C4};
|
WEAK symbol<int> keyCatchers{0x252AF70, 0x2EC82C4};
|
||||||
WEAK symbol<PlayerKeyState> playerKeys{0x2395B0C, 0x2999E1C};
|
WEAK symbol<PlayerKeyState> playerKeys{0x2395B0C, 0x2999E1C};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user