filesystem: reverse properly a lot of stuff
This commit is contained in:
parent
cec72268b0
commit
395e27bbe4
@ -8,10 +8,14 @@ namespace dvars
|
|||||||
|
|
||||||
const game::native::dvar_t** sv_maxclients;
|
const game::native::dvar_t** sv_maxclients;
|
||||||
|
|
||||||
|
const game::native::dvar_t** loc_language;
|
||||||
|
|
||||||
void initialize()
|
void initialize()
|
||||||
{
|
{
|
||||||
com_sv_running = reinterpret_cast<const game::native::dvar_t**>(SELECT_VALUE(0x1769F50, 0x1CEF588));
|
com_sv_running = reinterpret_cast<const game::native::dvar_t**>(SELECT_VALUE(0x1769F50, 0x1CEF588));
|
||||||
|
|
||||||
sv_maxclients = reinterpret_cast<const game::native::dvar_t**>(SELECT_VALUE(0x0, 0x21223C0));
|
sv_maxclients = reinterpret_cast<const game::native::dvar_t**>(SELECT_VALUE(0x0, 0x21223C0));
|
||||||
|
|
||||||
|
loc_language = reinterpret_cast<const game::native::dvar_t**>(SELECT_VALUE(0x1BF6938, 0x58D5A90));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,5 +6,7 @@ namespace dvars
|
|||||||
|
|
||||||
extern const game::native::dvar_t** sv_maxclients;
|
extern const game::native::dvar_t** sv_maxclients;
|
||||||
|
|
||||||
|
extern const game::native::dvar_t** loc_language;
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ namespace game
|
|||||||
{
|
{
|
||||||
namespace native
|
namespace native
|
||||||
{
|
{
|
||||||
Cmd_AddCommand_t Cmd_AddCommand;
|
Cmd_AddCommandInternal_t Cmd_AddCommandInternal;
|
||||||
Cmd_RemoveCommand_t Cmd_RemoveCommand;
|
Cmd_RemoveCommand_t Cmd_RemoveCommand;
|
||||||
|
|
||||||
Cbuf_AddText_t Cbuf_AddText;
|
Cbuf_AddText_t Cbuf_AddText;
|
||||||
@ -63,6 +63,8 @@ namespace game
|
|||||||
Sys_Error_t Sys_Error;
|
Sys_Error_t Sys_Error;
|
||||||
Sys_Milliseconds_t Sys_Milliseconds;
|
Sys_Milliseconds_t Sys_Milliseconds;
|
||||||
Sys_Sleep_t Sys_Sleep;
|
Sys_Sleep_t Sys_Sleep;
|
||||||
|
Sys_FreeFileList_t Sys_FreeFileList;
|
||||||
|
Sys_MessageBox_t Sys_MessageBox;
|
||||||
|
|
||||||
PMem_AllocFromSource_NoDebug_t PMem_AllocFromSource_NoDebug;
|
PMem_AllocFromSource_NoDebug_t PMem_AllocFromSource_NoDebug;
|
||||||
|
|
||||||
@ -86,6 +88,7 @@ namespace game
|
|||||||
XUIDToString_t XUIDToString;
|
XUIDToString_t XUIDToString;
|
||||||
|
|
||||||
SEH_LocalizeTextMessage_t SEH_LocalizeTextMessage;
|
SEH_LocalizeTextMessage_t SEH_LocalizeTextMessage;
|
||||||
|
SEH_GetLanguageName_t SEH_GetLanguageName;
|
||||||
|
|
||||||
CM_TransformedCapsuleTrace_t CM_TransformedCapsuleTrace;
|
CM_TransformedCapsuleTrace_t CM_TransformedCapsuleTrace;
|
||||||
|
|
||||||
@ -103,11 +106,17 @@ namespace game
|
|||||||
|
|
||||||
FS_Printf_t FS_Printf;
|
FS_Printf_t FS_Printf;
|
||||||
FS_ReadFile_t FS_ReadFile;
|
FS_ReadFile_t FS_ReadFile;
|
||||||
|
FS_CreatePath_t FS_CreatePath;
|
||||||
|
FS_HandleForFile_t FS_HandleForFile;
|
||||||
|
FS_FCloseFile_t FS_FCloseFile;
|
||||||
|
FS_ListFilteredFiles_t FS_ListFilteredFiles;
|
||||||
|
|
||||||
player_die_t player_die;
|
player_die_t player_die;
|
||||||
|
|
||||||
LargeLocalResetToMark_t LargeLocalResetToMark;
|
LargeLocalResetToMark_t LargeLocalResetToMark;
|
||||||
|
|
||||||
|
Win_LocalizeRef_t Win_LocalizeRef;
|
||||||
|
|
||||||
decltype(longjmp)* _longjmp;
|
decltype(longjmp)* _longjmp;
|
||||||
|
|
||||||
CmdArgs* sv_cmd_args;
|
CmdArgs* sv_cmd_args;
|
||||||
@ -143,6 +152,9 @@ namespace game
|
|||||||
searchpath_s** fs_searchpaths;
|
searchpath_s** fs_searchpaths;
|
||||||
char* fs_gamedir;
|
char* fs_gamedir;
|
||||||
fileHandleData_t* fsh;
|
fileHandleData_t* fsh;
|
||||||
|
int* fs_numServerIwds;
|
||||||
|
int* fs_serverIwds;
|
||||||
|
int* fs_iwdFileCount;
|
||||||
int* com_fileAccessed;
|
int* com_fileAccessed;
|
||||||
|
|
||||||
// DS does not have MJPEG thread
|
// DS does not have MJPEG thread
|
||||||
@ -186,6 +198,23 @@ namespace game
|
|||||||
gclient_s* g_clients;
|
gclient_s* g_clients;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Cmd_Argc()
|
||||||
|
{
|
||||||
|
assert(cmd_args->nesting < CMD_MAX_NESTING);
|
||||||
|
return cmd_args->argc[cmd_args->nesting];
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* Cmd_Argv(int argIndex)
|
||||||
|
{
|
||||||
|
assert(cmd_args->nesting < CMD_MAX_NESTING);
|
||||||
|
assert(argIndex >= 0);
|
||||||
|
if (argIndex < cmd_args->argc[cmd_args->nesting])
|
||||||
|
{
|
||||||
|
return cmd_args->argv[cmd_args->nesting][argIndex];
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
void AddRefToValue(VariableValue* value)
|
void AddRefToValue(VariableValue* value)
|
||||||
{
|
{
|
||||||
if (value->type == VAR_POINTER)
|
if (value->type == VAR_POINTER)
|
||||||
@ -524,9 +553,16 @@ namespace game
|
|||||||
InterlockedDecrement(&critSect->readCount);
|
InterlockedDecrement(&critSect->readCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FS_FCloseFile(int h)
|
void Sys_OutOfMemErrorInternal(const char* filename, int line)
|
||||||
{
|
{
|
||||||
reinterpret_cast<void(*)(int)>(SELECT_VALUE(0x415160, 0x5AF170))(h);
|
Sys_EnterCriticalSection(CRITSECT_FATAL_ERROR);
|
||||||
|
|
||||||
|
printf("Out of memory: filename \'%s\', line %d\n", filename, line);
|
||||||
|
const auto* title = Win_LocalizeRef("WIN_OUT_OF_MEM_TITLE");
|
||||||
|
const auto* body = Win_LocalizeRef("WIN_OUT_OF_MEM_BODY");
|
||||||
|
|
||||||
|
Sys_MessageBox(body, title, MB_ICONERROR, 0);
|
||||||
|
std::exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FS_Initialized()
|
bool FS_Initialized()
|
||||||
@ -534,11 +570,6 @@ namespace game
|
|||||||
return (*fs_searchpaths != nullptr);
|
return (*fs_searchpaths != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int FS_HandleForFile(FsThread thread)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<int(*)(FsThread)>(SELECT_VALUE(0x46B1C0, 0x5AEE50))(thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fs_fopen_file_read_for_thread_singleplayer(const char* filename, int* file, FsThread thread)
|
int fs_fopen_file_read_for_thread_singleplayer(const char* filename, int* file, FsThread thread)
|
||||||
{
|
{
|
||||||
static DWORD func = 0x627F20;
|
static DWORD func = 0x627F20;
|
||||||
@ -593,11 +624,6 @@ namespace game
|
|||||||
return fs_fopen_file_read_for_thread_multiplayer(filename, file, thread);
|
return fs_fopen_file_read_for_thread_multiplayer(filename, file, thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
int FS_CreatePath(char* OSPath)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<int(*)(char*)>(SELECT_VALUE(0x4F5AB0, 0x5AF060))(OSPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FS_CheckFileSystemStarted()
|
void FS_CheckFileSystemStarted()
|
||||||
{
|
{
|
||||||
assert(*fs_searchpaths);
|
assert(*fs_searchpaths);
|
||||||
@ -634,6 +660,34 @@ namespace game
|
|||||||
Sys_UnlockRead(db_hashCritSect);
|
Sys_UnlockRead(db_hashCritSect);
|
||||||
return asset_entry != nullptr;
|
return asset_entry != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SEH_GetCurrentLanguage()
|
||||||
|
{
|
||||||
|
return (*dvars::loc_language)->current.integer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* Z_Malloc(std::size_t size)
|
||||||
|
{
|
||||||
|
void* buf = std::malloc(size);
|
||||||
|
if (buf)
|
||||||
|
{
|
||||||
|
std::memset(buf, 0, size);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Failed to Z_Malloc %u bytes\n", size);
|
||||||
|
Sys_OutOfMemError();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool I_islower(int c)
|
||||||
|
{
|
||||||
|
return c >= 'a' && c <= 'z';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool I_isupper(int c)
|
||||||
|
{
|
||||||
|
return c >= 'A' && c <= 'Z';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
launcher::mode mode = launcher::mode::none;
|
launcher::mode mode = launcher::mode::none;
|
||||||
@ -664,7 +718,7 @@ namespace game
|
|||||||
|
|
||||||
dvars::initialize();
|
dvars::initialize();
|
||||||
|
|
||||||
native::Cmd_AddCommand = native::Cmd_AddCommand_t(SELECT_VALUE(0x558820, 0x545DF0));
|
native::Cmd_AddCommandInternal = native::Cmd_AddCommandInternal_t(SELECT_VALUE(0x558820, 0x545DF0));
|
||||||
native::Cmd_RemoveCommand = native::Cmd_RemoveCommand_t(SELECT_VALUE(0x443A30, 0x545E20));
|
native::Cmd_RemoveCommand = native::Cmd_RemoveCommand_t(SELECT_VALUE(0x443A30, 0x545E20));
|
||||||
|
|
||||||
native::Cbuf_AddText = native::Cbuf_AddText_t(SELECT_VALUE(0x457C90, 0x545680));
|
native::Cbuf_AddText = native::Cbuf_AddText_t(SELECT_VALUE(0x457C90, 0x545680));
|
||||||
@ -722,6 +776,8 @@ namespace game
|
|||||||
native::Sys_Error = native::Sys_Error_t(SELECT_VALUE(0x490D90, 0x5CC3B0));
|
native::Sys_Error = native::Sys_Error_t(SELECT_VALUE(0x490D90, 0x5CC3B0));
|
||||||
native::Sys_Milliseconds = native::Sys_Milliseconds_t(SELECT_VALUE(0x4A1610, 0x5CE740));
|
native::Sys_Milliseconds = native::Sys_Milliseconds_t(SELECT_VALUE(0x4A1610, 0x5CE740));
|
||||||
native::Sys_Sleep = native::Sys_Sleep_t(SELECT_VALUE(0x438600, 0x55F460));
|
native::Sys_Sleep = native::Sys_Sleep_t(SELECT_VALUE(0x438600, 0x55F460));
|
||||||
|
native::Sys_FreeFileList = native::Sys_FreeFileList_t(SELECT_VALUE(0x486380, 0x5C4F90));
|
||||||
|
native::Sys_MessageBox = native::Sys_MessageBox_t(SELECT_VALUE(0x4664D0, 0x5CD180));
|
||||||
|
|
||||||
native::PMem_AllocFromSource_NoDebug = native::PMem_AllocFromSource_NoDebug_t(SELECT_VALUE(0x449E50, 0x5C15C0));
|
native::PMem_AllocFromSource_NoDebug = native::PMem_AllocFromSource_NoDebug_t(SELECT_VALUE(0x449E50, 0x5C15C0));
|
||||||
|
|
||||||
@ -753,6 +809,7 @@ namespace game
|
|||||||
native::XUIDToString = native::XUIDToString_t(SELECT_VALUE(0x4FAA30, 0x55CC20));
|
native::XUIDToString = native::XUIDToString_t(SELECT_VALUE(0x4FAA30, 0x55CC20));
|
||||||
|
|
||||||
native::SEH_LocalizeTextMessage = native::SEH_LocalizeTextMessage_t(SELECT_VALUE(0x41EA20, 0x57E240));
|
native::SEH_LocalizeTextMessage = native::SEH_LocalizeTextMessage_t(SELECT_VALUE(0x41EA20, 0x57E240));
|
||||||
|
native::SEH_GetLanguageName = native::SEH_GetLanguageName_t(SELECT_VALUE(0x533650, 0x57E5A0));
|
||||||
|
|
||||||
native::CM_TransformedCapsuleTrace = native::CM_TransformedCapsuleTrace_t(SELECT_VALUE(0x4F9B80, 0x541340));
|
native::CM_TransformedCapsuleTrace = native::CM_TransformedCapsuleTrace_t(SELECT_VALUE(0x4F9B80, 0x541340));
|
||||||
|
|
||||||
@ -770,11 +827,17 @@ namespace game
|
|||||||
|
|
||||||
native::FS_Printf = native::FS_Printf_t(SELECT_VALUE(0x421E90, 0x5AF7C0));
|
native::FS_Printf = native::FS_Printf_t(SELECT_VALUE(0x421E90, 0x5AF7C0));
|
||||||
native::FS_ReadFile = native::FS_ReadFile_t(SELECT_VALUE(0x4D8DF0, 0x5B1FB0));
|
native::FS_ReadFile = native::FS_ReadFile_t(SELECT_VALUE(0x4D8DF0, 0x5B1FB0));
|
||||||
|
native::FS_CreatePath = native::FS_CreatePath_t(SELECT_VALUE(0x4F5AB0, 0x5AF060));
|
||||||
|
native::FS_HandleForFile = native::FS_HandleForFile_t(SELECT_VALUE(0x46B1C0, 0x5AEE50));
|
||||||
|
native::FS_FCloseFile = native::FS_FCloseFile_t(SELECT_VALUE(0x415160, 0x5AF170));
|
||||||
|
native::FS_ListFilteredFiles = native::FS_ListFilteredFiles_t(SELECT_VALUE(0x41D910, 0x5AFF10));
|
||||||
|
|
||||||
native::player_die = native::player_die_t(SELECT_VALUE(0x0, 0x503460));
|
native::player_die = native::player_die_t(SELECT_VALUE(0x0, 0x503460));
|
||||||
|
|
||||||
native::LargeLocalResetToMark = native::LargeLocalResetToMark_t(SELECT_VALUE(0x524350, 0x5B7150));
|
native::LargeLocalResetToMark = native::LargeLocalResetToMark_t(SELECT_VALUE(0x524350, 0x5B7150));
|
||||||
|
|
||||||
|
native::Win_LocalizeRef = native::Win_LocalizeRef_t(SELECT_VALUE(0x49D7E0, 0x5CBE90));
|
||||||
|
|
||||||
native::_longjmp = reinterpret_cast<decltype(longjmp)*>(SELECT_VALUE(0x73AC20, 0x7363BC));
|
native::_longjmp = reinterpret_cast<decltype(longjmp)*>(SELECT_VALUE(0x73AC20, 0x7363BC));
|
||||||
|
|
||||||
native::sv_cmd_args = reinterpret_cast<native::CmdArgs*>(SELECT_VALUE(0x1757218, 0x1CAA998));
|
native::sv_cmd_args = reinterpret_cast<native::CmdArgs*>(SELECT_VALUE(0x1757218, 0x1CAA998));
|
||||||
@ -817,9 +880,12 @@ namespace game
|
|||||||
native::fs_searchpaths = reinterpret_cast<native::searchpath_s**>(SELECT_VALUE(0x1C2FE78, 0x59BA858));
|
native::fs_searchpaths = reinterpret_cast<native::searchpath_s**>(SELECT_VALUE(0x1C2FE78, 0x59BA858));
|
||||||
native::fs_gamedir = reinterpret_cast<char*>(SELECT_VALUE(0x1C2B220, 0x59A98F8));
|
native::fs_gamedir = reinterpret_cast<char*>(SELECT_VALUE(0x1C2B220, 0x59A98F8));
|
||||||
native::fsh = reinterpret_cast<native::fileHandleData_t*>(SELECT_VALUE(0x1C2B540, 0x59B5F20));
|
native::fsh = reinterpret_cast<native::fileHandleData_t*>(SELECT_VALUE(0x1C2B540, 0x59B5F20));
|
||||||
|
native::fs_numServerIwds = reinterpret_cast<int*>(SELECT_VALUE(0x1C2FE84, 0x59BA864));
|
||||||
|
native::fs_serverIwds = reinterpret_cast<int*>(SELECT_VALUE(0x0, 0x59AAB18));
|
||||||
|
native::fs_iwdFileCount = reinterpret_cast<int*>(SELECT_VALUE(0x1C2fE7C, 0x59BA85C));
|
||||||
native::com_fileAccessed = reinterpret_cast<int*>(SELECT_VALUE(0x1C2B328, 0x59A9A04));
|
native::com_fileAccessed = reinterpret_cast<int*>(SELECT_VALUE(0x1C2B328, 0x59A9A04));
|
||||||
|
|
||||||
native::threadId = reinterpret_cast<unsigned(*)[native::THREAD_CONTEXT_COUNT]>(SELECT_VALUE(0x18576C8, 0x1D6E448));
|
native::threadId = reinterpret_cast<unsigned int(*)[native::THREAD_CONTEXT_COUNT]>(SELECT_VALUE(0x18576C8, 0x1D6E448));
|
||||||
|
|
||||||
native::initialized_0 = reinterpret_cast<int*>(SELECT_VALUE(0x1CE1CA0, 0x5AA3058));
|
native::initialized_0 = reinterpret_cast<int*>(SELECT_VALUE(0x1CE1CA0, 0x5AA3058));
|
||||||
native::sys_timeBase = reinterpret_cast<int*>(SELECT_VALUE(0x1CE1C98, 0x5AA3050));
|
native::sys_timeBase = reinterpret_cast<int*>(SELECT_VALUE(0x1CE1C98, 0x5AA3050));
|
||||||
|
@ -11,8 +11,8 @@ namespace game
|
|||||||
{
|
{
|
||||||
namespace native
|
namespace native
|
||||||
{
|
{
|
||||||
typedef void (*Cmd_AddCommand_t)(const char* cmdName, void (*function)(), cmd_function_t* allocedCmd);
|
typedef void (*Cmd_AddCommandInternal_t)(const char* cmdName, void (*function)(), cmd_function_s* allocedCmd);
|
||||||
extern Cmd_AddCommand_t Cmd_AddCommand;
|
extern Cmd_AddCommandInternal_t Cmd_AddCommandInternal;
|
||||||
|
|
||||||
typedef void (*Cmd_RemoveCommand_t)(const char* cmdName);
|
typedef void (*Cmd_RemoveCommand_t)(const char* cmdName);
|
||||||
extern Cmd_RemoveCommand_t Cmd_RemoveCommand;
|
extern Cmd_RemoveCommand_t Cmd_RemoveCommand;
|
||||||
@ -137,6 +137,12 @@ namespace game
|
|||||||
typedef void (*Sys_Sleep_t)(int msec);
|
typedef void (*Sys_Sleep_t)(int msec);
|
||||||
extern Sys_Sleep_t Sys_Sleep;
|
extern Sys_Sleep_t Sys_Sleep;
|
||||||
|
|
||||||
|
typedef void (*Sys_FreeFileList_t)(char** list);
|
||||||
|
extern Sys_FreeFileList_t Sys_FreeFileList;
|
||||||
|
|
||||||
|
typedef int (*Sys_MessageBox_t)(const char* lpText, const char* lpCaption, unsigned int uType, int defaultValue);
|
||||||
|
extern Sys_MessageBox_t Sys_MessageBox;
|
||||||
|
|
||||||
typedef void* (*PMem_AllocFromSource_NoDebug_t)(unsigned int size, unsigned int alignment, unsigned int type, int source);
|
typedef void* (*PMem_AllocFromSource_NoDebug_t)(unsigned int size, unsigned int alignment, unsigned int type, int source);
|
||||||
extern PMem_AllocFromSource_NoDebug_t PMem_AllocFromSource_NoDebug;
|
extern PMem_AllocFromSource_NoDebug_t PMem_AllocFromSource_NoDebug;
|
||||||
|
|
||||||
@ -182,6 +188,9 @@ namespace game
|
|||||||
typedef char* (*SEH_LocalizeTextMessage_t)(const char* pszInputBuffer, const char* pszMessageType, msgLocErrType_t errType);
|
typedef char* (*SEH_LocalizeTextMessage_t)(const char* pszInputBuffer, const char* pszMessageType, msgLocErrType_t errType);
|
||||||
extern SEH_LocalizeTextMessage_t SEH_LocalizeTextMessage;
|
extern SEH_LocalizeTextMessage_t SEH_LocalizeTextMessage;
|
||||||
|
|
||||||
|
typedef const char* (*SEH_GetLanguageName_t)(int iLanguage);
|
||||||
|
extern SEH_GetLanguageName_t SEH_GetLanguageName;
|
||||||
|
|
||||||
typedef void (*CM_TransformedCapsuleTrace_t)(trace_t* results, const float* start, const float* end,
|
typedef void (*CM_TransformedCapsuleTrace_t)(trace_t* results, const float* start, const float* end,
|
||||||
const Bounds* bounds, const Bounds* capsule, int contents,
|
const Bounds* bounds, const Bounds* capsule, int contents,
|
||||||
const float* origin, const float* angles);
|
const float* origin, const float* angles);
|
||||||
@ -216,12 +225,27 @@ namespace game
|
|||||||
typedef int (*FS_ReadFile_t)(const char* qpath, char** buffer);
|
typedef int (*FS_ReadFile_t)(const char* qpath, char** buffer);
|
||||||
extern FS_ReadFile_t FS_ReadFile;
|
extern FS_ReadFile_t FS_ReadFile;
|
||||||
|
|
||||||
|
typedef int (*FS_CreatePath_t)(char* OSPath);
|
||||||
|
extern FS_CreatePath_t FS_CreatePath;
|
||||||
|
|
||||||
|
typedef int (*FS_HandleForFile_t)(FsThread thread);
|
||||||
|
extern FS_HandleForFile_t FS_HandleForFile;
|
||||||
|
|
||||||
|
typedef void (*FS_FCloseFile_t)(int h);
|
||||||
|
extern FS_FCloseFile_t FS_FCloseFile;
|
||||||
|
|
||||||
|
typedef char** (*FS_ListFilteredFiles_t)(searchpath_s* searchPath, const char* path, const char* extension, const char* filter, FsListBehavior_e behavior, int* numfiles, int allocTrackType);
|
||||||
|
extern FS_ListFilteredFiles_t FS_ListFilteredFiles;
|
||||||
|
|
||||||
typedef void (*player_die_t)(gentity_s* self, const gentity_s* inflictor, gentity_s* attacker, int damage, int meansOfDeath, const Weapon* iWeapon, bool isAlternate, const float* vDir, const hitLocation_t hitLoc, int psTimeOffset);
|
typedef void (*player_die_t)(gentity_s* self, const gentity_s* inflictor, gentity_s* attacker, int damage, int meansOfDeath, const Weapon* iWeapon, bool isAlternate, const float* vDir, const hitLocation_t hitLoc, int psTimeOffset);
|
||||||
extern player_die_t player_die;
|
extern player_die_t player_die;
|
||||||
|
|
||||||
typedef void (*LargeLocalResetToMark_t)(int markPos);
|
typedef void (*LargeLocalResetToMark_t)(int markPos);
|
||||||
extern LargeLocalResetToMark_t LargeLocalResetToMark;
|
extern LargeLocalResetToMark_t LargeLocalResetToMark;
|
||||||
|
|
||||||
|
typedef const char* (*Win_LocalizeRef_t)(const char* ref);
|
||||||
|
extern Win_LocalizeRef_t Win_LocalizeRer;
|
||||||
|
|
||||||
extern decltype(longjmp)* _longjmp;
|
extern decltype(longjmp)* _longjmp;
|
||||||
|
|
||||||
constexpr auto CMD_MAX_NESTING = 8;
|
constexpr auto CMD_MAX_NESTING = 8;
|
||||||
@ -261,6 +285,9 @@ namespace game
|
|||||||
extern searchpath_s** fs_searchpaths;
|
extern searchpath_s** fs_searchpaths;
|
||||||
extern char* fs_gamedir;
|
extern char* fs_gamedir;
|
||||||
extern fileHandleData_t* fsh;
|
extern fileHandleData_t* fsh;
|
||||||
|
extern int* fs_numServerIwds;
|
||||||
|
extern int* fs_serverIwds;
|
||||||
|
extern int* fs_iwdFileCount;
|
||||||
extern int* com_fileAccessed;
|
extern int* com_fileAccessed;
|
||||||
|
|
||||||
extern unsigned int(*threadId)[THREAD_CONTEXT_COUNT];
|
extern unsigned int(*threadId)[THREAD_CONTEXT_COUNT];
|
||||||
@ -322,6 +349,9 @@ namespace game
|
|||||||
extern gclient_s* g_clients;
|
extern gclient_s* g_clients;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Cmd_Argc();
|
||||||
|
const char* Cmd_Argv(int argIndex);
|
||||||
|
|
||||||
void AddRefToValue(VariableValue* value);
|
void AddRefToValue(VariableValue* value);
|
||||||
|
|
||||||
void* MT_Alloc(int numBytes, int type);
|
void* MT_Alloc(int numBytes, int type);
|
||||||
@ -361,16 +391,23 @@ namespace game
|
|||||||
bool Sys_IsStreamThread();
|
bool Sys_IsStreamThread();
|
||||||
bool Sys_IsRenderThread();
|
bool Sys_IsRenderThread();
|
||||||
bool Sys_IsServerThread();
|
bool Sys_IsServerThread();
|
||||||
|
void Sys_LockRead(FastCriticalSection* critSect);
|
||||||
|
void Sys_UnlockRead(FastCriticalSection* critSect);
|
||||||
|
void Sys_OutOfMemErrorInternal(const char* filename, int line);
|
||||||
|
|
||||||
void FS_FCloseFile(int h);
|
|
||||||
bool FS_Initialized();
|
bool FS_Initialized();
|
||||||
int FS_HandleForFile(FsThread thread);
|
|
||||||
int FS_FOpenFileReadForThread(const char* filename, int* file, FsThread thread);
|
int FS_FOpenFileReadForThread(const char* filename, int* file, FsThread thread);
|
||||||
int FS_CreatePath(char* OSPath);
|
|
||||||
void FS_CheckFileSystemStarted();
|
void FS_CheckFileSystemStarted();
|
||||||
|
|
||||||
XAssetEntry* DB_FindXAssetEntry(XAssetType type, const char* name);
|
XAssetEntry* DB_FindXAssetEntry(XAssetType type, const char* name);
|
||||||
int DB_XAssetExists(XAssetType type, const char* name);
|
int DB_XAssetExists(XAssetType type, const char* name);
|
||||||
|
|
||||||
|
int SEH_GetCurrentLanguage();
|
||||||
|
|
||||||
|
void* Z_Malloc(std::size_t size);
|
||||||
|
|
||||||
|
bool I_islower(int c);
|
||||||
|
bool I_isupper(int c);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_mp();
|
bool is_mp();
|
||||||
@ -378,3 +415,5 @@ namespace game
|
|||||||
|
|
||||||
void initialize(launcher::mode mode);
|
void initialize(launcher::mode mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define Sys_OutOfMemError() game::native::Sys_OutOfMemErrorInternal(__FILE__, __LINE__)
|
||||||
|
@ -483,9 +483,15 @@ namespace game
|
|||||||
PMEM_SOURCE_SCRIPT,
|
PMEM_SOURCE_SCRIPT,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cmd_function_t
|
enum FsListBehavior_e
|
||||||
{
|
{
|
||||||
cmd_function_t* next;
|
FS_LIST_PURE_ONLY,
|
||||||
|
FS_LIST_ALL,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cmd_function_s
|
||||||
|
{
|
||||||
|
cmd_function_s* next;
|
||||||
const char* name;
|
const char* name;
|
||||||
const char* autoCompleteDir;
|
const char* autoCompleteDir;
|
||||||
const char* autoCompleteExt;
|
const char* autoCompleteExt;
|
||||||
@ -1289,6 +1295,7 @@ namespace game
|
|||||||
enum CriticalSection
|
enum CriticalSection
|
||||||
{
|
{
|
||||||
CRITSECT_CONSOLE = 0x0,
|
CRITSECT_CONSOLE = 0x0,
|
||||||
|
CRITSECT_FATAL_ERROR = 0x12,
|
||||||
CRITSECT_CBUF = 0x1F,
|
CRITSECT_CBUF = 0x1F,
|
||||||
CRITSECT_COUNT = 0x27,
|
CRITSECT_COUNT = 0x27,
|
||||||
};
|
};
|
||||||
|
@ -1,95 +1,94 @@
|
|||||||
#include <std_include.hpp>
|
#include <std_include.hpp>
|
||||||
#include <loader/module_loader.hpp>
|
#include <loader/module_loader.hpp>
|
||||||
#include <utils/hook.hpp>
|
|
||||||
|
|
||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
|
|
||||||
class ceg final : public module
|
#include "ceg.hpp"
|
||||||
|
|
||||||
|
#include <utils/hook.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
void ceg::post_load()
|
||||||
{
|
{
|
||||||
public:
|
// Only SP has CEG
|
||||||
void post_load() override
|
// CEG in MP has accidentally been removed due to CVE-2018-10718
|
||||||
{
|
if (!game::is_sp()) return;
|
||||||
// Only SP has CEG
|
|
||||||
// CEG in MP has accidentally been removed due to CVE-2018-10718
|
|
||||||
if (!game::is_sp()) return;
|
|
||||||
|
|
||||||
utils::hook::signature signature(0x401000, 0x3E1000);
|
utils::hook::signature signature(0x401000, 0x3E1000);
|
||||||
|
|
||||||
signature.add({
|
signature.add({
|
||||||
"\x56\xE8\x00\x00\x00\x00\x8B\xF0\xE8\x00\x00\x00\x00\x50\x56\xE8", "xx????xxx????xxx", [](char* address)
|
"\x56\xE8\x00\x00\x00\x00\x8B\xF0\xE8\x00\x00\x00\x00\x50\x56\xE8", "xx????xxx????xxx", [](char* address)
|
||||||
{
|
{
|
||||||
utils::hook::set<DWORD>(address, 0xC301B0);
|
utils::hook::set<std::uint32_t>(address, 0xC301B0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Generic killer caller.
|
// Generic killer caller.
|
||||||
signature.add({
|
signature.add({
|
||||||
"\x55\x8B\xEC\x80\x7D\x08\x00\x75\x55", "xxxxxx?xx", [](char* address)
|
"\x55\x8B\xEC\x80\x7D\x08\x00\x75\x55", "xxxxxx?xx", [](char* address)
|
||||||
{
|
{
|
||||||
utils::hook::set<DWORD>(address, 0xC301B0);
|
utils::hook::set<std::uint32_t>(address, 0xC301B0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// CEG initialization.
|
// CEG initialization.
|
||||||
signature.add({
|
signature.add({
|
||||||
"\x55\x8B\xEC\x83\xEC\x18\x53\x56\x57\xE8\x00\x00\x00\x00", "xxxxxxxxxx????", [](char* address)
|
"\x55\x8B\xEC\x83\xEC\x18\x53\x56\x57\xE8\x00\x00\x00\x00", "xxxxxxxxxx????", [](char* address)
|
||||||
{
|
{
|
||||||
utils::hook::set<BYTE>(address, 0xC3);
|
utils::hook::set<std::uint8_t>(address, 0xC3);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Some odd trap.
|
// Some odd trap.
|
||||||
signature.add({
|
signature.add({
|
||||||
"\x55\x8B\xEC\x81\xEC\x00\x00\x00\x00\x53\x56\x57\x8B\x3D", "xxxxx??xxxxxxx", [](char* address)
|
"\x55\x8B\xEC\x81\xEC\x00\x00\x00\x00\x53\x56\x57\x8B\x3D", "xxxxx??xxxxxxx", [](char* address)
|
||||||
{
|
{
|
||||||
utils::hook::set<DWORD>(address, 0xC301B0);
|
utils::hook::set<std::uint32_t>(address, 0xC301B0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Custom shit
|
// Custom shit
|
||||||
signature.add({
|
signature.add({
|
||||||
"\x55\x8B\xEC\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x64\xFF\x35\x00\x00\x00\x00\x64\x89\x25\x00\x00\x00\x00\xE8",
|
"\x55\x8B\xEC\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x64\xFF\x35\x00\x00\x00\x00\x64\x89\x25\x00\x00\x00\x00\xE8",
|
||||||
"xxxx????x????xxx????xxx????x", [](char* address)
|
"xxxx????x????xxx????xxx????x", [](char* address)
|
||||||
{
|
{
|
||||||
utils::hook::set<BYTE>(address, 0xC3);
|
utils::hook::set<std::uint8_t>(address, 0xC3);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// hkcr guid check
|
// hkcr guid check
|
||||||
signature.add({
|
signature.add({
|
||||||
"\x55\x8B\xEC\xB8\x00\x00\x00\x00\xE8\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x84\xC0\x75\x06",
|
"\x55\x8B\xEC\xB8\x00\x00\x00\x00\xE8\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x84\xC0\x75\x06",
|
||||||
"xxxx????x????x????xxxx", [](char* address)
|
"xxxx????x????x????xxxx", [](char* address)
|
||||||
{
|
{
|
||||||
utils::hook::nop(address + 0xD, 5); // Call
|
utils::hook::nop(address + 0xD, 5); // Call
|
||||||
utils::hook::nop(address + 0x14, 2); // Jump
|
utils::hook::nop(address + 0x14, 2); // Jump
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// hkcr guid check 2
|
// hkcr guid check 2
|
||||||
signature.add({
|
signature.add({
|
||||||
"\x55\x8B\xEC\x81\xEC\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x84\xC0\x75\x06", "xxxxx????x????xxxx", [
|
"\x55\x8B\xEC\x81\xEC\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x84\xC0\x75\x06",
|
||||||
](char* address)
|
"xxxxx????x????xxxx", [](char* address)
|
||||||
{
|
{
|
||||||
utils::hook::nop(address + 0x9, 5); // Call
|
utils::hook::nop(address + 0x9, 5); // Call
|
||||||
utils::hook::nop(address + 0x10, 2); // Jump
|
utils::hook::nop(address + 0x10, 2); // Jump
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
signature.process();
|
signature.process();
|
||||||
|
|
||||||
// Checks on startup
|
// Checks on startup
|
||||||
utils::hook::set<DWORD>(0x402ED0, 0xC301B0);
|
utils::hook::set<std::uint32_t>(0x402ED0, 0xC301B0);
|
||||||
utils::hook::set<DWORD>(0x4b9280, 0xC301B0);
|
utils::hook::set<std::uint32_t>(0x4b9280, 0xC301B0);
|
||||||
|
|
||||||
// Function fixup
|
// Function fixup
|
||||||
utils::hook(0x4CA310, game::native::DB_LoadXAssets, HOOK_JUMP).install()->quick();
|
utils::hook(0x4CA310, game::native::DB_LoadXAssets, HOOK_JUMP).install()->quick();
|
||||||
|
|
||||||
// Some value obfuscation
|
// Some value obfuscation
|
||||||
utils::hook(0x493B81, 0x493BFC, HOOK_JUMP).install()->quick();
|
utils::hook(0x493B81, 0x493BFC, HOOK_JUMP).install()->quick();
|
||||||
|
|
||||||
// CEG uninitialization
|
// CEG uninitialization
|
||||||
utils::hook::set<BYTE>(0x527110, 0xC3);
|
utils::hook::set<std::uint8_t>(0x527110, 0xC3);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
REGISTER_MODULE(ceg)
|
REGISTER_MODULE(ceg)
|
||||||
|
7
src/module/ceg.hpp
Normal file
7
src/module/ceg.hpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class ceg final : public module
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void post_load() override;
|
||||||
|
};
|
@ -85,7 +85,7 @@ std::string command::params_sv::join(const int index) const
|
|||||||
|
|
||||||
void command::add_raw(const char* name, void (*callback)())
|
void command::add_raw(const char* name, void (*callback)())
|
||||||
{
|
{
|
||||||
game::native::Cmd_AddCommand(name, callback, allocator.allocate<game::native::cmd_function_t>());
|
game::native::Cmd_AddCommandInternal(name, callback, allocator.allocate<game::native::cmd_function_s>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void command::add(const char* name, const std::function<void(const params&)>& callback)
|
void command::add(const char* name, const std::function<void(const params&)>& callback)
|
||||||
|
@ -64,3 +64,9 @@ private:
|
|||||||
|
|
||||||
static void add_sp_commands();
|
static void add_sp_commands();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define Cmd_AddCommand(cmd_name, function) \
|
||||||
|
{ \
|
||||||
|
static game::native::cmd_function_s function##_VAR; \
|
||||||
|
game::native::Cmd_AddCommandInternal(cmd_name, function, &function##_VAR); \
|
||||||
|
}
|
||||||
|
@ -133,7 +133,7 @@ std::string console::format(va_list* ap, const char* message)
|
|||||||
const auto count = vsnprintf_s(buffer, _TRUNCATE, message, *ap);
|
const auto count = vsnprintf_s(buffer, _TRUNCATE, message, *ap);
|
||||||
|
|
||||||
if (count < 0) return {};
|
if (count < 0) return {};
|
||||||
return {buffer, static_cast<size_t>(count)};
|
return {buffer, static_cast<std::size_t>(count)};
|
||||||
}
|
}
|
||||||
|
|
||||||
REGISTER_MODULE(console)
|
REGISTER_MODULE(console)
|
||||||
|
@ -4,234 +4,540 @@
|
|||||||
|
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
|
|
||||||
|
#include "command.hpp"
|
||||||
#include "file_system.hpp"
|
#include "file_system.hpp"
|
||||||
#include "log_file.hpp"
|
#include "log_file.hpp"
|
||||||
|
|
||||||
static utils::hook::detour sys_default_install_path_hook;
|
namespace
|
||||||
|
|
||||||
static const game::native::dvar_t** fs_homepath;
|
|
||||||
static const game::native::dvar_t** fs_debug;
|
|
||||||
|
|
||||||
static FILE* file_for_handle(const int f)
|
|
||||||
{
|
{
|
||||||
assert(!game::native::fsh[f].zipFile);
|
utils::hook::detour sys_default_install_path_hook;
|
||||||
assert(game::native::fsh[f].handleFiles.file.o);
|
|
||||||
|
|
||||||
return game::native::fsh[f].handleFiles.file.o;
|
const game::native::dvar_t** fs_homepath;
|
||||||
}
|
const game::native::dvar_t** fs_debug;
|
||||||
|
const game::native::dvar_t** fs_ignoreLocalized;
|
||||||
|
|
||||||
static unsigned int file_write(const void* ptr, const unsigned int len, FILE* stream)
|
FILE* file_for_handle(const int f)
|
||||||
{
|
|
||||||
return std::fwrite(ptr, sizeof(char), len, stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FILE* file_open_append_text(const char* filename)
|
|
||||||
{
|
|
||||||
errno = 0;
|
|
||||||
auto* file = std::fopen(filename, "at");
|
|
||||||
if (file)
|
|
||||||
{
|
{
|
||||||
return file;
|
assert(!game::native::fsh[f].zipFile);
|
||||||
|
assert(game::native::fsh[f].handleFiles.file.o);
|
||||||
|
|
||||||
|
return game::native::fsh[f].handleFiles.file.o;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_file::info("Couldn't open file: %s %s\n", filename, std::strerror(errno));
|
unsigned int file_write(const void* ptr, const unsigned int len, FILE* stream)
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static FILE* file_open_write_binary(const char* filename)
|
|
||||||
{
|
|
||||||
errno = 0;
|
|
||||||
auto* file = std::fopen(filename, "wb");
|
|
||||||
if (file)
|
|
||||||
{
|
{
|
||||||
return file;
|
return std::fwrite(ptr, sizeof(char), len, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
log_file::info("Couldn't open file: %s %s\n", filename, std::strerror(errno));
|
FILE* file_open_append_text(const char* filename)
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void replace_separators(char* path)
|
|
||||||
{
|
|
||||||
char* src, * dst;
|
|
||||||
|
|
||||||
bool was_sep = false;
|
|
||||||
|
|
||||||
for (src = path, dst = path; *src; ++src)
|
|
||||||
{
|
{
|
||||||
if (*src == '/' || *src == '\\')
|
errno = 0;
|
||||||
|
auto* file = std::fopen(filename, "at");
|
||||||
|
if (file)
|
||||||
{
|
{
|
||||||
if (!was_sep)
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_file::info("Couldn't open file: %s %s\n", filename, std::strerror(errno));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* file_open_write_binary(const char* filename)
|
||||||
|
{
|
||||||
|
errno = 0;
|
||||||
|
auto* file = std::fopen(filename, "wb");
|
||||||
|
if (file)
|
||||||
|
{
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_file::info("Couldn't open file: %s %s\n", filename, std::strerror(errno));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void replace_separators(char* path)
|
||||||
|
{
|
||||||
|
char* src, * dst;
|
||||||
|
|
||||||
|
bool was_sep = false;
|
||||||
|
|
||||||
|
for (src = path, dst = path; *src; ++src)
|
||||||
|
{
|
||||||
|
if (*src == '/' || *src == '\\')
|
||||||
{
|
{
|
||||||
was_sep = true;
|
if (!was_sep)
|
||||||
*dst++ = '\\';
|
{
|
||||||
|
was_sep = true;
|
||||||
|
*dst++ = '\\';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
was_sep = false;
|
||||||
|
*dst++ = *src;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
*dst = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void build_os_path_for_thread(const char* base, const char* game, const char* qpath, char* ospath, game::native::FsThread thread)
|
||||||
|
{
|
||||||
|
assert(base);
|
||||||
|
assert(qpath);
|
||||||
|
assert(ospath);
|
||||||
|
|
||||||
|
if (!game)
|
||||||
{
|
{
|
||||||
was_sep = false;
|
game = "";
|
||||||
*dst++ = *src;
|
}
|
||||||
|
else if (!game[0])
|
||||||
|
{
|
||||||
|
game = game::native::fs_gamedir;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto len_base = std::strlen(base);
|
||||||
|
auto len_game = std::strlen(game);
|
||||||
|
auto len_qpath = std::strlen(qpath);
|
||||||
|
if (len_game + 1 + len_base + len_qpath + 1 >= game::native::MAX_OSPATH)
|
||||||
|
{
|
||||||
|
if (thread)
|
||||||
|
{
|
||||||
|
*ospath = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
game::native::Com_Error(game::native::ERR_FATAL, "\x15" "FS_BuildOSPath: os path length exceeded\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(ospath, base, len_base);
|
||||||
|
ospath[len_base] = '/';
|
||||||
|
|
||||||
|
std::memcpy(&ospath[len_base + 1], game, len_game);
|
||||||
|
ospath[len_base + 1 + len_game] = '/';
|
||||||
|
|
||||||
|
std::memcpy(ospath + len_base + 2 + len_game, qpath, len_qpath + 1);
|
||||||
|
replace_separators(ospath);
|
||||||
|
}
|
||||||
|
|
||||||
|
game::native::FsThread get_current_thread()
|
||||||
|
{
|
||||||
|
if (game::native::Sys_IsMainThread())
|
||||||
|
{
|
||||||
|
return game::native::FS_THREAD_MAIN;
|
||||||
|
}
|
||||||
|
if (game::native::Sys_IsDatabaseThread())
|
||||||
|
{
|
||||||
|
return game::native::FS_THREAD_DATABASE;
|
||||||
|
}
|
||||||
|
if (game::native::Sys_IsStreamThread())
|
||||||
|
{
|
||||||
|
return game::native::FS_THREAD_STREAM;
|
||||||
|
}
|
||||||
|
if (game::native::Sys_IsRenderThread())
|
||||||
|
{
|
||||||
|
return game::native::FS_THREAD_BACKEND;
|
||||||
|
}
|
||||||
|
if (game::native::Sys_IsServerThread())
|
||||||
|
{
|
||||||
|
return game::native::FS_THREAD_SERVER;
|
||||||
|
}
|
||||||
|
return game::native::FS_THREAD_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle_for_file_current_thread()
|
||||||
|
{
|
||||||
|
return game::native::FS_HandleForFile(get_current_thread());
|
||||||
|
}
|
||||||
|
|
||||||
|
int open_file_append(const char* filename)
|
||||||
|
{
|
||||||
|
char ospath[game::native::MAX_OSPATH]{};
|
||||||
|
|
||||||
|
game::native::FS_CheckFileSystemStarted();
|
||||||
|
const auto* basepath = (*fs_homepath)->current.string;
|
||||||
|
build_os_path_for_thread(basepath, game::native::fs_gamedir, filename, ospath, game::native::FS_THREAD_MAIN);
|
||||||
|
if ((*fs_debug)->current.integer)
|
||||||
|
{
|
||||||
|
log_file::info("FS_FOpenFileAppend: %s\n", ospath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (game::native::FS_CreatePath(ospath))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* f = file_open_append_text(ospath);
|
||||||
|
if (!f)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto h = handle_for_file_current_thread();
|
||||||
|
game::native::fsh[h].zipFile = nullptr;
|
||||||
|
strncpy_s(game::native::fsh[h].name, filename, _TRUNCATE);
|
||||||
|
game::native::fsh[h].handleFiles.file.o = f;
|
||||||
|
game::native::fsh[h].handleSync = 0;
|
||||||
|
|
||||||
|
if (!game::native::fsh[h].handleFiles.file.o)
|
||||||
|
{
|
||||||
|
game::native::FS_FCloseFile(h);
|
||||||
|
h = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_handle_and_open_file(const char* filename, const char* ospath, game::native::FsThread thread)
|
||||||
|
{
|
||||||
|
auto* fp = file_open_write_binary(ospath);
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto f = game::native::FS_HandleForFile(thread);
|
||||||
|
game::native::fsh[f].zipFile = nullptr;
|
||||||
|
game::native::fsh[f].handleFiles.file.o = fp;
|
||||||
|
|
||||||
|
strncpy_s(game::native::fsh[f].name, filename, _TRUNCATE);
|
||||||
|
game::native::fsh[f].handleSync = 0;
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
int open_file_write_to_dir_for_thread(const char* filename, const char* dir, const char* osbasepath, game::native::FsThread thread)
|
||||||
|
{
|
||||||
|
char ospath[game::native::MAX_OSPATH]{};
|
||||||
|
|
||||||
|
game::native::FS_CheckFileSystemStarted();
|
||||||
|
|
||||||
|
const char* basepath = (*fs_homepath)->current.string;
|
||||||
|
build_os_path_for_thread(basepath, dir, filename, ospath, game::native::FS_THREAD_MAIN);
|
||||||
|
|
||||||
|
if ((*fs_debug)->current.integer)
|
||||||
|
{
|
||||||
|
log_file::info("FS_FOpenFileWriteToDirForThread: %s\n", ospath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (game::native::FS_CreatePath(ospath))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return get_handle_and_open_file(filename, ospath, thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
int open_file_write(const char* filename)
|
||||||
|
{
|
||||||
|
return open_file_write_to_dir_for_thread(filename, game::native::fs_gamedir, "", game::native::FS_THREAD_MAIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void convert_path(char* s)
|
||||||
|
{
|
||||||
|
while (*s)
|
||||||
|
{
|
||||||
|
if (*s == '\\' || *s == ':')
|
||||||
|
{
|
||||||
|
*s = '/';
|
||||||
|
}
|
||||||
|
++s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*dst = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void build_os_path_for_thread(const char* base, const char* game, const char* qpath, char* ospath, game::native::FsThread thread)
|
int path_cmp(const char* s1, const char* s2)
|
||||||
{
|
{
|
||||||
assert(base);
|
int c1;
|
||||||
assert(qpath);
|
|
||||||
assert(ospath);
|
|
||||||
|
|
||||||
if (!game)
|
do
|
||||||
{
|
|
||||||
game = "";
|
|
||||||
}
|
|
||||||
else if (!game[0])
|
|
||||||
{
|
|
||||||
game = game::native::fs_gamedir;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto len_base = std::strlen(base);
|
|
||||||
auto len_game = std::strlen(game);
|
|
||||||
auto len_qpath = std::strlen(qpath);
|
|
||||||
if (len_game + 1 + len_base + len_qpath + 1 >= game::native::MAX_OSPATH)
|
|
||||||
{
|
|
||||||
if (thread)
|
|
||||||
{
|
{
|
||||||
*ospath = '\0';
|
c1 = *s1++;
|
||||||
|
int c2 = *s2++;
|
||||||
|
|
||||||
|
if (game::native::I_islower(c1))
|
||||||
|
{
|
||||||
|
c1 -= ('a' - 'A');
|
||||||
|
}
|
||||||
|
if (game::native::I_islower(c2))
|
||||||
|
{
|
||||||
|
c2 -= ('a' - 'A');
|
||||||
|
}
|
||||||
|
if (c1 == '\\' || c1 == ':')
|
||||||
|
{
|
||||||
|
c1 = '/';
|
||||||
|
}
|
||||||
|
if (c2 == '\\' || c2 == ':')
|
||||||
|
{
|
||||||
|
c2 = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c1 < c2)
|
||||||
|
{
|
||||||
|
return -1; // strings not equal
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c1 > c2)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} while (c1);
|
||||||
|
|
||||||
|
return 0; // strings are equal
|
||||||
|
}
|
||||||
|
|
||||||
|
void sort_file_list(char** filelist, int numfiles)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
|
||||||
|
const char** sortedlist = static_cast<const char**>(game::native::Z_Malloc((numfiles * sizeof(*sortedlist)) + 4));
|
||||||
|
sortedlist[0] = nullptr;
|
||||||
|
auto numsortedfiles = 0;
|
||||||
|
for (auto i = 0; i < numfiles; ++i)
|
||||||
|
{
|
||||||
|
for (j = 0; j < numsortedfiles; j++)
|
||||||
|
{
|
||||||
|
if (path_cmp(filelist[i], sortedlist[j]) < 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto k = numsortedfiles; k > j; --k)
|
||||||
|
{
|
||||||
|
sortedlist[k] = sortedlist[k - 1];
|
||||||
|
}
|
||||||
|
sortedlist[j] = filelist[i];
|
||||||
|
++numsortedfiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(filelist, sortedlist, numfiles * sizeof(*filelist));
|
||||||
|
std::free(sortedlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
int use_search_path(game::native::searchpath_s* pSearch)
|
||||||
|
{
|
||||||
|
if (pSearch->bLocalized && (*fs_ignoreLocalized)->current.enabled)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pSearch->bLocalized && pSearch->language != game::native::SEH_GetCurrentLanguage())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iwd_is_pure(game::native::iwd_t* iwd)
|
||||||
|
{
|
||||||
|
if (*game::native::fs_numServerIwds)
|
||||||
|
{
|
||||||
|
for (auto i = 0; i < *game::native::fs_numServerIwds; ++i)
|
||||||
|
{
|
||||||
|
if (iwd->checksum == game::native::fs_serverIwds[i])
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char** list_files(const char* path, const char* extension, game::native::FsListBehavior_e behavior, int* numfiles, int allocTrackType)
|
||||||
|
{
|
||||||
|
return game::native::FS_ListFilteredFiles(*game::native::fs_searchpaths, path, extension, nullptr, behavior, numfiles, allocTrackType);
|
||||||
|
}
|
||||||
|
|
||||||
|
void display_path(bool b_language_cull)
|
||||||
|
{
|
||||||
|
auto i_language = game::native::SEH_GetCurrentLanguage();
|
||||||
|
const auto* psz_language_name = game::native::SEH_GetLanguageName(i_language);
|
||||||
|
log_file::info("Current language: %s\n", psz_language_name);
|
||||||
|
if ((*fs_ignoreLocalized)->current.enabled)
|
||||||
|
{
|
||||||
|
log_file::info(" localized assets are being ignored\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
log_file::info("Current search path:\n");
|
||||||
|
for (auto* s = *game::native::fs_searchpaths; s; s = s->next)
|
||||||
|
{
|
||||||
|
if (b_language_cull && !use_search_path(s))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->iwd)
|
||||||
|
{
|
||||||
|
log_file::info("%s (%i files)\n", s->iwd->iwdFilename, s->iwd->numfiles);
|
||||||
|
if (s->bLocalized)
|
||||||
|
{
|
||||||
|
log_file::info(" localized assets iwd file for %s\n", game::native::SEH_GetLanguageName(s->language));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*game::native::fs_numServerIwds)
|
||||||
|
{
|
||||||
|
if (iwd_is_pure(s->iwd))
|
||||||
|
{
|
||||||
|
log_file::info(" on the pure list\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_file::info(" not on the pure list\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_file::info("%s/%s\n", s->dir->path, s->dir->gamedir);
|
||||||
|
if (s->bLocalized)
|
||||||
|
{
|
||||||
|
log_file::info(" localized assets game folder for %s\n", game::native::SEH_GetLanguageName(s->language));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log_file::info("\nFile Handles:\n");
|
||||||
|
for (int i = 1; i < 64; ++i)
|
||||||
|
{
|
||||||
|
if (game::native::fsh[i].handleFiles.file.o)
|
||||||
|
{
|
||||||
|
log_file::info("handle %i: %s\n", i, game::native::fsh[i].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool touch_file(const char* name)
|
||||||
|
{
|
||||||
|
*game::native::com_fileAccessed = 1;
|
||||||
|
auto ret = game::native::FS_FOpenFileReadForThread(name, nullptr, game::native::FS_THREAD_MAIN);
|
||||||
|
return ret != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void path_f()
|
||||||
|
{
|
||||||
|
display_path(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void full_path_f()
|
||||||
|
{
|
||||||
|
display_path(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dir_f()
|
||||||
|
{
|
||||||
|
const char* path;
|
||||||
|
const char* extension;
|
||||||
|
int ndirs;
|
||||||
|
|
||||||
|
if (game::native::Cmd_Argc() < 2 || game::native::Cmd_Argc() > 3)
|
||||||
|
{
|
||||||
|
log_file::info("usage: dir <directory> [extension]\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
game::native::Com_Error(game::native::ERR_FATAL, "\x15" "FS_BuildOSPath: os path length exceeded\n");
|
if (game::native::Cmd_Argc() == 2)
|
||||||
|
{
|
||||||
|
path = game::native::Cmd_Argv(1);
|
||||||
|
extension = "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
path = game::native::Cmd_Argv(1);
|
||||||
|
extension = game::native::Cmd_Argv(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_file::info("Directory of %s %s\n", path, extension);
|
||||||
|
log_file::info("---------------\n");
|
||||||
|
|
||||||
|
auto** dirnames = list_files(path, extension, game::native::FS_LIST_PURE_ONLY, &ndirs, 3);
|
||||||
|
|
||||||
|
for (int i = 0; i < ndirs; ++i)
|
||||||
|
{
|
||||||
|
log_file::info("%s\n", dirnames[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
game::native::Sys_FreeFileList(dirnames);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::memcpy(ospath, base, len_base);
|
void new_dir_f()
|
||||||
ospath[len_base] = '/';
|
|
||||||
|
|
||||||
std::memcpy(&ospath[len_base + 1], game, len_game);
|
|
||||||
ospath[len_base + 1 + len_game] = '/';
|
|
||||||
|
|
||||||
std::memcpy(ospath + len_base + 2 + len_game, qpath, len_qpath + 1);
|
|
||||||
replace_separators(ospath);
|
|
||||||
}
|
|
||||||
|
|
||||||
static game::native::FsThread get_current_thread()
|
|
||||||
{
|
|
||||||
if (game::native::Sys_IsMainThread())
|
|
||||||
{
|
{
|
||||||
return game::native::FS_THREAD_MAIN;
|
int ndirs;
|
||||||
|
|
||||||
|
if (game::native::Cmd_Argc() < 2)
|
||||||
|
{
|
||||||
|
log_file::info("usage: fdir <filter>\n");
|
||||||
|
log_file::info("example: fdir *q3dm*.bsp\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* filter = game::native::Cmd_Argv(1);
|
||||||
|
|
||||||
|
log_file::info("---------------\n");
|
||||||
|
|
||||||
|
auto** dirnames = game::native::FS_ListFilteredFiles(*game::native::fs_searchpaths, "", "", filter, game::native::FS_LIST_PURE_ONLY, &ndirs, 3);
|
||||||
|
sort_file_list(dirnames, ndirs);
|
||||||
|
|
||||||
|
for (auto i = 0; i < ndirs; ++i)
|
||||||
|
{
|
||||||
|
convert_path(dirnames[i]);
|
||||||
|
log_file::info("%s\n", dirnames[i]);
|
||||||
|
}
|
||||||
|
log_file::info("%d files listed\n", ndirs);
|
||||||
|
game::native::Sys_FreeFileList(dirnames);
|
||||||
}
|
}
|
||||||
if (game::native::Sys_IsDatabaseThread())
|
|
||||||
|
void touch_file_f()
|
||||||
{
|
{
|
||||||
return game::native::FS_THREAD_DATABASE;
|
if (game::native::Cmd_Argc() != 2)
|
||||||
|
{
|
||||||
|
log_file::info("Usage: touchFile <file>\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
touch_file(game::native::Cmd_Argv(1));
|
||||||
}
|
}
|
||||||
if (game::native::Sys_IsStreamThread())
|
|
||||||
|
void add_commands()
|
||||||
{
|
{
|
||||||
return game::native::FS_THREAD_STREAM;
|
Cmd_AddCommand("path", path_f);
|
||||||
|
Cmd_AddCommand("fullpath", full_path_f);
|
||||||
|
Cmd_AddCommand("dir", dir_f);
|
||||||
|
Cmd_AddCommand("fdir", new_dir_f);
|
||||||
|
Cmd_AddCommand("touchFile", touch_file_f);
|
||||||
}
|
}
|
||||||
if (game::native::Sys_IsRenderThread())
|
|
||||||
|
void fs_startup_stub(char* game_name)
|
||||||
{
|
{
|
||||||
return game::native::FS_THREAD_BACKEND;
|
log_file::info("----- FS_Startup -----\n");
|
||||||
|
|
||||||
|
utils::hook::invoke<void>(0x5B1070, game_name);
|
||||||
|
|
||||||
|
add_commands();
|
||||||
|
display_path(true);
|
||||||
|
|
||||||
|
log_file::info("----------------------\n");
|
||||||
|
log_file::info("%d files in iwd files\n", *game::native::fs_iwdFileCount);
|
||||||
}
|
}
|
||||||
if (game::native::Sys_IsServerThread())
|
|
||||||
|
void fs_shutdown_stub(int closemfp)
|
||||||
{
|
{
|
||||||
return game::native::FS_THREAD_SERVER;
|
utils::hook::invoke<void>(0x5B0D30, closemfp);
|
||||||
|
|
||||||
|
game::native::Cmd_RemoveCommand("path");
|
||||||
|
game::native::Cmd_RemoveCommand("fullpath");
|
||||||
|
game::native::Cmd_RemoveCommand("dir");
|
||||||
|
game::native::Cmd_RemoveCommand("fdir");
|
||||||
|
game::native::Cmd_RemoveCommand("touchFile");
|
||||||
}
|
}
|
||||||
return game::native::FS_THREAD_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int handle_for_file_current_thread()
|
const char* sys_default_install_path_stub()
|
||||||
{
|
|
||||||
return game::native::FS_HandleForFile(get_current_thread());
|
|
||||||
}
|
|
||||||
|
|
||||||
static int open_file_append(const char* filename)
|
|
||||||
{
|
|
||||||
char ospath[game::native::MAX_OSPATH]{};
|
|
||||||
|
|
||||||
game::native::FS_CheckFileSystemStarted();
|
|
||||||
const auto* basepath = (*fs_homepath)->current.string;
|
|
||||||
build_os_path_for_thread(basepath, game::native::fs_gamedir, filename, ospath, game::native::FS_THREAD_MAIN);
|
|
||||||
if ((*fs_debug)->current.integer)
|
|
||||||
{
|
{
|
||||||
log_file::info("FS_FOpenFileAppend: %s\n", ospath);
|
static auto current_path = std::filesystem::current_path().string();
|
||||||
|
return current_path.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game::native::FS_CreatePath(ospath))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* f = file_open_append_text(ospath);
|
|
||||||
if (!f)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto h = handle_for_file_current_thread();
|
|
||||||
game::native::fsh[h].zipFile = nullptr;
|
|
||||||
strncpy_s(game::native::fsh[h].name, filename, _TRUNCATE);
|
|
||||||
game::native::fsh[h].handleFiles.file.o = f;
|
|
||||||
game::native::fsh[h].handleSync = 0;
|
|
||||||
|
|
||||||
if (!game::native::fsh[h].handleFiles.file.o)
|
|
||||||
{
|
|
||||||
game::native::FS_FCloseFile(h);
|
|
||||||
h = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_handle_and_open_file(const char* filename, const char* ospath, game::native::FsThread thread)
|
|
||||||
{
|
|
||||||
auto* fp = file_open_write_binary(ospath);
|
|
||||||
if (!fp)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto f = game::native::FS_HandleForFile(thread);
|
|
||||||
game::native::fsh[f].zipFile = nullptr;
|
|
||||||
game::native::fsh[f].handleFiles.file.o = fp;
|
|
||||||
|
|
||||||
strncpy_s(game::native::fsh[f].name, filename, _TRUNCATE);
|
|
||||||
game::native::fsh[f].handleSync = 0;
|
|
||||||
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int open_file_write_to_dir_for_thread(const char* filename, const char* dir, const char* osbasepath, game::native::FsThread thread)
|
|
||||||
{
|
|
||||||
char ospath[game::native::MAX_OSPATH]{};
|
|
||||||
|
|
||||||
game::native::FS_CheckFileSystemStarted();
|
|
||||||
|
|
||||||
const char* basepath = (*fs_homepath)->current.string;
|
|
||||||
build_os_path_for_thread(basepath, dir, filename, ospath, game::native::FS_THREAD_MAIN);
|
|
||||||
|
|
||||||
if ((*fs_debug)->current.integer)
|
|
||||||
{
|
|
||||||
log_file::info("FS_FOpenFileWriteToDirForThread: %s\n", ospath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (game::native::FS_CreatePath(ospath))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return get_handle_and_open_file(filename, ospath, thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int open_file_write(const char* filename)
|
|
||||||
{
|
|
||||||
return open_file_write_to_dir_for_thread(filename, game::native::fs_gamedir, "", game::native::FS_THREAD_MAIN);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char* sys_default_install_path_stub()
|
|
||||||
{
|
|
||||||
static auto current_path = std::filesystem::current_path().string();
|
|
||||||
return current_path.data();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int file_system::open_file_by_mode(const char* qpath, int* f, game::native::fsMode_t mode)
|
int file_system::open_file_by_mode(const char* qpath, int* f, game::native::fsMode_t mode)
|
||||||
@ -329,6 +635,16 @@ void file_system::post_load()
|
|||||||
{
|
{
|
||||||
fs_homepath = reinterpret_cast<const game::native::dvar_t**>(SELECT_VALUE(0x1C2B538, 0x59ADD18));
|
fs_homepath = reinterpret_cast<const game::native::dvar_t**>(SELECT_VALUE(0x1C2B538, 0x59ADD18));
|
||||||
fs_debug = reinterpret_cast<const game::native::dvar_t**>(SELECT_VALUE(0x1C2B32C, 0x59A9A08));
|
fs_debug = reinterpret_cast<const game::native::dvar_t**>(SELECT_VALUE(0x1C2B32C, 0x59A9A08));
|
||||||
|
fs_ignoreLocalized = reinterpret_cast<const game::native::dvar_t**>(SELECT_VALUE(0x1C2B21C, 0x59A99F8));
|
||||||
|
|
||||||
|
if (game::is_mp())
|
||||||
|
{
|
||||||
|
utils::hook(0x5B20AA, fs_startup_stub, HOOK_CALL).install()->quick(); // FS_InitFilesystem
|
||||||
|
utils::hook(0x5B2148, fs_startup_stub, HOOK_CALL).install()->quick(); // FS_Restart
|
||||||
|
|
||||||
|
utils::hook(0x5557CC, fs_shutdown_stub, HOOK_CALL).install()->quick(); // Com_Quit_f
|
||||||
|
utils::hook(0x5B2115, fs_shutdown_stub, HOOK_CALL).install()->quick(); // FS_Restart
|
||||||
|
}
|
||||||
|
|
||||||
// Make open-iw5 work outside of the game directory
|
// Make open-iw5 work outside of the game directory
|
||||||
sys_default_install_path_hook.create(SELECT_VALUE(0x487E50, 0x5C4A80), &sys_default_install_path_stub);
|
sys_default_install_path_hook.create(SELECT_VALUE(0x487E50, 0x5C4A80), &sys_default_install_path_stub);
|
||||||
|
Loading…
Reference in New Issue
Block a user