mirror of
https://github.com/JezuzLizard/T4SP-Server-Plugin.git
synced 2025-06-21 20:05:36 +00:00
fix line endings and tabs
This commit is contained in:
parent
b17a56a7fd
commit
bb216441bf
@ -3,434 +3,434 @@
|
|||||||
|
|
||||||
namespace codsrc
|
namespace codsrc
|
||||||
{
|
{
|
||||||
// Restored inlined function
|
// Restored inlined function
|
||||||
int Scr_IsInOpcodeMemory(game::scriptInstance_t inst, const char* pos)
|
int Scr_IsInOpcodeMemory(game::scriptInstance_t inst, const char* pos)
|
||||||
{
|
{
|
||||||
assert(game::gScrVarPub[inst].programBuffer);
|
assert(game::gScrVarPub[inst].programBuffer);
|
||||||
assert(pos);
|
assert(pos);
|
||||||
|
|
||||||
return (unsigned int)(pos - game::gScrVarPub[inst].programBuffer) < game::gScrCompilePub[inst].programLen;
|
return (unsigned int)(pos - game::gScrVarPub[inst].programBuffer) < game::gScrCompilePub[inst].programLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decomp Status: Completed
|
// Decomp Status: Completed
|
||||||
bool Scr_IsIdentifier(char* token)
|
bool Scr_IsIdentifier(char* token)
|
||||||
{
|
{
|
||||||
while ( *token )
|
while ( *token )
|
||||||
{
|
{
|
||||||
if (!iscsym(*token))
|
if (!iscsym(*token))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
++token;
|
++token;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decomp Status: Completed
|
// Decomp Status: Completed
|
||||||
unsigned int Scr_GetFunctionHandle(const char* file, game::scriptInstance_t inst, const char* handle)
|
unsigned int Scr_GetFunctionHandle(const char* file, game::scriptInstance_t inst, const char* handle)
|
||||||
{
|
{
|
||||||
assert(game::gScrCompilePub[inst].scriptsPos);
|
assert(game::gScrCompilePub[inst].scriptsPos);
|
||||||
assert(strlen(file) < 0x40);
|
assert(strlen(file) < 0x40);
|
||||||
|
|
||||||
unsigned int fileNameHash = game::Scr_CreateCanonicalFilename(inst, file);
|
unsigned int fileNameHash = game::Scr_CreateCanonicalFilename(inst, file);
|
||||||
int id = game::FindVariable(fileNameHash, game::gScrCompilePub[inst].scriptsPos, inst);
|
int id = game::FindVariable(fileNameHash, game::gScrCompilePub[inst].scriptsPos, inst);
|
||||||
|
|
||||||
game::SL_RemoveRefToString(fileNameHash, inst);
|
game::SL_RemoveRefToString(fileNameHash, inst);
|
||||||
|
|
||||||
if (!id)
|
if (!id)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int posId = game::FindObject(inst, id);
|
unsigned int posId = game::FindObject(inst, id);
|
||||||
unsigned int str = game::SL_FindLowercaseString(handle, inst);
|
unsigned int str = game::SL_FindLowercaseString(handle, inst);
|
||||||
if (!str)
|
if (!str)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int filePosId = game::FindVariable(str, posId, inst);
|
unsigned int filePosId = game::FindVariable(str, posId, inst);
|
||||||
if (!filePosId)
|
if (!filePosId)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
game::VariableValue val = game::Scr_EvalVariable(inst, filePosId);
|
game::VariableValue val = game::Scr_EvalVariable(inst, filePosId);
|
||||||
|
|
||||||
assert(val.type == game::VAR_CODEPOS);
|
assert(val.type == game::VAR_CODEPOS);
|
||||||
|
|
||||||
const char* pos = val.u.codePosValue;
|
const char* pos = val.u.codePosValue;
|
||||||
if (!game::Scr_IsInOpcodeMemory(inst, pos))
|
if (!game::Scr_IsInOpcodeMemory(inst, pos))
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(pos - game::gScrVarPub[inst].programBuffer);
|
assert(pos - game::gScrVarPub[inst].programBuffer);
|
||||||
|
|
||||||
assert(pos > game::gScrVarPub[inst].programBuffer);
|
assert(pos > game::gScrVarPub[inst].programBuffer);
|
||||||
|
|
||||||
return pos - game::gScrVarPub[inst].programBuffer;
|
return pos - game::gScrVarPub[inst].programBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decomp Status: Completed
|
// Decomp Status: Completed
|
||||||
unsigned int SL_TransferToCanonicalString(game::scriptInstance_t inst, unsigned int stringValue)
|
unsigned int SL_TransferToCanonicalString(game::scriptInstance_t inst, unsigned int stringValue)
|
||||||
{
|
{
|
||||||
assert(stringValue);
|
assert(stringValue);
|
||||||
|
|
||||||
game::SL_TransferRefToUser(stringValue, 2u, inst);
|
game::SL_TransferRefToUser(stringValue, 2u, inst);
|
||||||
|
|
||||||
if ( game::gScrCompilePub[inst].canonicalStrings[stringValue] )
|
if ( game::gScrCompilePub[inst].canonicalStrings[stringValue] )
|
||||||
{
|
{
|
||||||
return game::gScrCompilePub[inst].canonicalStrings[stringValue];
|
return game::gScrCompilePub[inst].canonicalStrings[stringValue];
|
||||||
}
|
}
|
||||||
|
|
||||||
game::gScrCompilePub[inst].canonicalStrings[stringValue] = ++game::gScrVarPub[inst].canonicalStrCount;
|
game::gScrCompilePub[inst].canonicalStrings[stringValue] = ++game::gScrVarPub[inst].canonicalStrCount;
|
||||||
|
|
||||||
return game::gScrVarPub[inst].canonicalStrCount;
|
return game::gScrVarPub[inst].canonicalStrCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decomp Status: Tested, Completed
|
// Decomp Status: Tested, Completed
|
||||||
unsigned int SL_GetCanonicalString(char* token, game::scriptInstance_t inst)
|
unsigned int SL_GetCanonicalString(char* token, game::scriptInstance_t inst)
|
||||||
{
|
{
|
||||||
unsigned int str;
|
unsigned int str;
|
||||||
|
|
||||||
str = game::SL_FindString(token, inst);
|
str = game::SL_FindString(token, inst);
|
||||||
|
|
||||||
if ( game::gScrCompilePub[inst].canonicalStrings[str] )
|
if ( game::gScrCompilePub[inst].canonicalStrings[str] )
|
||||||
{
|
{
|
||||||
return game::gScrCompilePub[inst].canonicalStrings[str];
|
return game::gScrCompilePub[inst].canonicalStrings[str];
|
||||||
}
|
}
|
||||||
|
|
||||||
str = game::SL_GetString_(token, inst, 0);
|
str = game::SL_GetString_(token, inst, 0);
|
||||||
|
|
||||||
return game::SL_TransferToCanonicalString(inst, str);
|
return game::SL_TransferToCanonicalString(inst, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restored
|
// Restored
|
||||||
void SL_BeginLoadScripts(game::scriptInstance_t inst)
|
void SL_BeginLoadScripts(game::scriptInstance_t inst)
|
||||||
{
|
{
|
||||||
memset(game::gScrCompilePub[inst].canonicalStrings, 0, sizeof(game::gScrCompilePub[inst].canonicalStrings));
|
memset(game::gScrCompilePub[inst].canonicalStrings, 0, sizeof(game::gScrCompilePub[inst].canonicalStrings));
|
||||||
game::gScrVarPub[inst].canonicalStrCount = 0;
|
game::gScrVarPub[inst].canonicalStrCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restored
|
// Restored
|
||||||
void Scr_SetLoadedImpureScript(bool loadedImpureScript)
|
void Scr_SetLoadedImpureScript(bool loadedImpureScript)
|
||||||
{
|
{
|
||||||
*game::loadedImpureScript = loadedImpureScript;
|
*game::loadedImpureScript = loadedImpureScript;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decomp Status: Tested, Completed
|
// Decomp Status: Tested, Completed
|
||||||
void Scr_BeginLoadScripts(game::scriptInstance_t inst, int user)
|
void Scr_BeginLoadScripts(game::scriptInstance_t inst, int user)
|
||||||
{
|
{
|
||||||
assert(!game::gScrCompilePub[inst].script_loading);
|
assert(!game::gScrCompilePub[inst].script_loading);
|
||||||
|
|
||||||
game::gScrCompilePub[inst].script_loading = 1;
|
game::gScrCompilePub[inst].script_loading = 1;
|
||||||
|
|
||||||
game::Scr_InitOpcodeLookup(inst);
|
game::Scr_InitOpcodeLookup(inst);
|
||||||
|
|
||||||
assert(!game::gScrCompilePub[inst].loadedscripts);
|
assert(!game::gScrCompilePub[inst].loadedscripts);
|
||||||
|
|
||||||
game::gScrCompilePub[inst].loadedscripts = game::Scr_AllocArray(inst);
|
game::gScrCompilePub[inst].loadedscripts = game::Scr_AllocArray(inst);
|
||||||
|
|
||||||
assert(!game::gScrCompilePub[inst].scriptsPos);
|
assert(!game::gScrCompilePub[inst].scriptsPos);
|
||||||
|
|
||||||
game::gScrCompilePub[inst].scriptsPos = game::Scr_AllocArray(inst);
|
game::gScrCompilePub[inst].scriptsPos = game::Scr_AllocArray(inst);
|
||||||
|
|
||||||
assert(!game::gScrCompilePub[inst].scriptsCount);
|
assert(!game::gScrCompilePub[inst].scriptsCount);
|
||||||
|
|
||||||
game::gScrCompilePub[inst].scriptsCount = game::Scr_AllocArray(inst);
|
game::gScrCompilePub[inst].scriptsCount = game::Scr_AllocArray(inst);
|
||||||
|
|
||||||
assert(!game::gScrCompilePub[inst].builtinFunc);
|
assert(!game::gScrCompilePub[inst].builtinFunc);
|
||||||
|
|
||||||
game::gScrCompilePub[inst].builtinFunc = game::Scr_AllocArray(inst);
|
game::gScrCompilePub[inst].builtinFunc = game::Scr_AllocArray(inst);
|
||||||
|
|
||||||
assert(!game::gScrCompilePub[inst].builtinMeth);
|
assert(!game::gScrCompilePub[inst].builtinMeth);
|
||||||
|
|
||||||
game::gScrCompilePub[inst].builtinMeth = game::Scr_AllocArray(inst);
|
game::gScrCompilePub[inst].builtinMeth = game::Scr_AllocArray(inst);
|
||||||
|
|
||||||
game::gScrVarPub[inst].programHunkUser = game::Hunk_UserCreate(0x100000, "Scr_BeginLoadScripts", 1, 0, 0, 7);
|
game::gScrVarPub[inst].programHunkUser = game::Hunk_UserCreate(0x100000, "Scr_BeginLoadScripts", 1, 0, 0, 7);
|
||||||
game::TempMemoryReset(game::gScrVarPub[inst].programHunkUser);
|
game::TempMemoryReset(game::gScrVarPub[inst].programHunkUser);
|
||||||
game::gScrVarPub[inst].programBuffer = game::TempMalloc(0);
|
game::gScrVarPub[inst].programBuffer = game::TempMalloc(0);
|
||||||
|
|
||||||
assert(((int)game::gScrVarPub[inst].programBuffer & 0x1F) == 0);
|
assert(((int)game::gScrVarPub[inst].programBuffer & 0x1F) == 0);
|
||||||
|
|
||||||
game::gScrCompilePub[inst].programLen = 0;
|
game::gScrCompilePub[inst].programLen = 0;
|
||||||
game::gScrVarPub[inst].endScriptBuffer = 0;
|
game::gScrVarPub[inst].endScriptBuffer = 0;
|
||||||
|
|
||||||
game::SL_BeginLoadScripts(inst);
|
game::SL_BeginLoadScripts(inst);
|
||||||
|
|
||||||
game::gScrVarPub[inst].fieldBuffer = 0;
|
game::gScrVarPub[inst].fieldBuffer = 0;
|
||||||
game::gScrCompilePub[inst].value_count = 0;
|
game::gScrCompilePub[inst].value_count = 0;
|
||||||
game::gScrVarPub[inst].error_message = 0;
|
game::gScrVarPub[inst].error_message = 0;
|
||||||
game::gScrVmGlob[inst].dialog_error_message = 0;
|
game::gScrVmGlob[inst].dialog_error_message = 0;
|
||||||
game::gScrVarPub[inst].error_index = 0;
|
game::gScrVarPub[inst].error_index = 0;
|
||||||
game::gScrCompilePub[inst].func_table_size = 0;
|
game::gScrCompilePub[inst].func_table_size = 0;
|
||||||
|
|
||||||
game::Scr_SetLoadedImpureScript(false);
|
game::Scr_SetLoadedImpureScript(false);
|
||||||
|
|
||||||
game::gScrAnimPub[inst].animTreeNames = 0;
|
game::gScrAnimPub[inst].animTreeNames = 0;
|
||||||
game::Scr_BeginLoadAnimTrees(inst, user);
|
game::Scr_BeginLoadAnimTrees(inst, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decomp Status: Completed
|
// Decomp Status: Completed
|
||||||
void Scr_BeginLoadAnimTrees(game::scriptInstance_t inst, int user)
|
void Scr_BeginLoadAnimTrees(game::scriptInstance_t inst, int user)
|
||||||
{
|
{
|
||||||
assert(!game::gScrAnimPub[inst].animtree_loading);
|
assert(!game::gScrAnimPub[inst].animtree_loading);
|
||||||
|
|
||||||
game::gScrAnimPub[inst].animtree_loading = 1;
|
game::gScrAnimPub[inst].animtree_loading = 1;
|
||||||
game::gScrAnimPub[inst].xanim_num[user] = 0;
|
game::gScrAnimPub[inst].xanim_num[user] = 0;
|
||||||
game::gScrAnimPub[inst].xanim_lookup[user][0].anims = 0;
|
game::gScrAnimPub[inst].xanim_lookup[user][0].anims = 0;
|
||||||
|
|
||||||
assert(!game::gScrAnimPub[inst].animtrees);
|
assert(!game::gScrAnimPub[inst].animtrees);
|
||||||
|
|
||||||
game::gScrAnimPub[inst].animtrees = game::Scr_AllocArray(inst);
|
game::gScrAnimPub[inst].animtrees = game::Scr_AllocArray(inst);
|
||||||
game::gScrAnimPub[inst].animtree_node = 0;
|
game::gScrAnimPub[inst].animtree_node = 0;
|
||||||
game::gScrCompilePub[inst].developer_statement = 0;
|
game::gScrCompilePub[inst].developer_statement = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decomp Status: Completed
|
// Decomp Status: Completed
|
||||||
int Scr_ScanFile(int max_size, char* buf)
|
int Scr_ScanFile(int max_size, char* buf)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
int n;
|
int n;
|
||||||
game::scriptInstance_t inst;
|
game::scriptInstance_t inst;
|
||||||
|
|
||||||
inst = *game::gInst;
|
inst = *game::gInst;
|
||||||
|
|
||||||
c = '*';
|
c = '*';
|
||||||
for ( n = 0;
|
for ( n = 0;
|
||||||
n < max_size;
|
n < max_size;
|
||||||
++n )
|
++n )
|
||||||
{
|
{
|
||||||
c = *game::gScrCompilePub[inst].in_ptr++;
|
c = *game::gScrCompilePub[inst].in_ptr++;
|
||||||
|
|
||||||
if ( !c || c == '\n')
|
if ( !c || c == '\n')
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[n] = c;
|
buf[n] = c;
|
||||||
}
|
}
|
||||||
if ( c == '\n')
|
if ( c == '\n')
|
||||||
{
|
{
|
||||||
buf[n++] = c;
|
buf[n++] = c;
|
||||||
}
|
}
|
||||||
else if ( !c )
|
else if ( !c )
|
||||||
{
|
{
|
||||||
if ( game::gScrCompilePub[inst].parseBuf )
|
if ( game::gScrCompilePub[inst].parseBuf )
|
||||||
{
|
{
|
||||||
game::gScrCompilePub[inst].in_ptr = game::gScrCompilePub[inst].parseBuf;
|
game::gScrCompilePub[inst].in_ptr = game::gScrCompilePub[inst].parseBuf;
|
||||||
game::gScrCompilePub[inst].parseBuf = 0;
|
game::gScrCompilePub[inst].parseBuf = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
--game::gScrCompilePub[inst].in_ptr;
|
--game::gScrCompilePub[inst].in_ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decomp Status: Tested, Completed
|
// Decomp Status: Tested, Completed
|
||||||
unsigned int Scr_LoadScriptInternal(game::scriptInstance_t inst, const char* filename, game::PrecacheEntry* entries, int entriesCount)
|
unsigned int Scr_LoadScriptInternal(game::scriptInstance_t inst, const char* filename, game::PrecacheEntry* entries, int entriesCount)
|
||||||
{
|
{
|
||||||
unsigned int scriptPosVar;
|
unsigned int scriptPosVar;
|
||||||
unsigned int scriptCountVar;
|
unsigned int scriptCountVar;
|
||||||
const char *codepos;
|
const char *codepos;
|
||||||
char extFilename[64];
|
char extFilename[64];
|
||||||
unsigned int fileCountId;
|
unsigned int fileCountId;
|
||||||
unsigned int filePosPtr;
|
unsigned int filePosPtr;
|
||||||
char *sourceBuffer;
|
char *sourceBuffer;
|
||||||
const char *oldFilename;
|
const char *oldFilename;
|
||||||
unsigned int name;
|
unsigned int name;
|
||||||
unsigned int oldAnimTreeNames;
|
unsigned int oldAnimTreeNames;
|
||||||
const char *oldSourceBuf;
|
const char *oldSourceBuf;
|
||||||
unsigned int scriptId;
|
unsigned int scriptId;
|
||||||
unsigned int filePosId;
|
unsigned int filePosId;
|
||||||
const char *formatExtString;
|
const char *formatExtString;
|
||||||
game::sval_u parseData;
|
game::sval_u parseData;
|
||||||
|
|
||||||
assert(game::gScrCompilePub[inst].script_loading);
|
assert(game::gScrCompilePub[inst].script_loading);
|
||||||
|
|
||||||
assert(strlen(filename) < 0x40);
|
assert(strlen(filename) < 0x40);
|
||||||
|
|
||||||
name = game::Scr_CreateCanonicalFilename(inst, filename);
|
name = game::Scr_CreateCanonicalFilename(inst, filename);
|
||||||
if ( game::FindVariable(name, game::gScrCompilePub[inst].loadedscripts, inst) )
|
if ( game::FindVariable(name, game::gScrCompilePub[inst].loadedscripts, inst) )
|
||||||
{
|
{
|
||||||
game::SL_RemoveRefToString(name, inst);
|
game::SL_RemoveRefToString(name, inst);
|
||||||
filePosPtr = game::FindVariable(name, game::gScrCompilePub[inst].scriptsPos, inst);
|
filePosPtr = game::FindVariable(name, game::gScrCompilePub[inst].scriptsPos, inst);
|
||||||
if ( filePosPtr )
|
if ( filePosPtr )
|
||||||
{
|
{
|
||||||
return game::FindObject(inst, filePosPtr);
|
return game::FindObject(inst, filePosPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
scriptId = game::GetNewVariable(inst, name, game::gScrCompilePub[inst].loadedscripts);
|
scriptId = game::GetNewVariable(inst, name, game::gScrCompilePub[inst].loadedscripts);
|
||||||
game::SL_RemoveRefToString(name, inst);
|
game::SL_RemoveRefToString(name, inst);
|
||||||
formatExtString = "%s.gsc";
|
formatExtString = "%s.gsc";
|
||||||
|
|
||||||
if ( inst == game::SCRIPTINSTANCE_CLIENT && !strncmp(filename, "clientscripts", 13) )
|
if ( inst == game::SCRIPTINSTANCE_CLIENT && !strncmp(filename, "clientscripts", 13) )
|
||||||
{
|
{
|
||||||
formatExtString = "%s.csc";
|
formatExtString = "%s.csc";
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(extFilename, 64, formatExtString, filename);
|
snprintf(extFilename, 64, formatExtString, filename);
|
||||||
oldSourceBuf = game::gScrParserPub[inst].sourceBuf;
|
oldSourceBuf = game::gScrParserPub[inst].sourceBuf;
|
||||||
codepos = (const char *)game::TempMalloc(0);
|
codepos = (const char *)game::TempMalloc(0);
|
||||||
sourceBuffer = game::Scr_AddSourceBuffer(inst, (int)filename, extFilename, codepos);
|
sourceBuffer = game::Scr_AddSourceBuffer(inst, (int)filename, extFilename, codepos);
|
||||||
|
|
||||||
if (!sourceBuffer)
|
if (!sourceBuffer)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
oldAnimTreeNames = game::gScrAnimPub[inst].animTreeNames;
|
oldAnimTreeNames = game::gScrAnimPub[inst].animTreeNames;
|
||||||
game::gScrAnimPub[inst].animTreeNames = 0;
|
game::gScrAnimPub[inst].animTreeNames = 0;
|
||||||
game::gScrCompilePub[inst].far_function_count = 0;
|
game::gScrCompilePub[inst].far_function_count = 0;
|
||||||
|
|
||||||
game::Scr_InitAllocNode(inst);
|
game::Scr_InitAllocNode(inst);
|
||||||
|
|
||||||
oldFilename = game::gScrParserPub[inst].scriptfilename;
|
oldFilename = game::gScrParserPub[inst].scriptfilename;
|
||||||
game::gScrParserPub[inst].scriptfilename = extFilename;
|
game::gScrParserPub[inst].scriptfilename = extFilename;
|
||||||
game:: gScrCompilePub[inst].in_ptr = "+";
|
game:: gScrCompilePub[inst].in_ptr = "+";
|
||||||
game::gScrCompilePub[inst].parseBuf = sourceBuffer;
|
game::gScrCompilePub[inst].parseBuf = sourceBuffer;
|
||||||
game::ScriptParse(inst, &parseData);
|
game::ScriptParse(inst, &parseData);
|
||||||
scriptPosVar = game::GetVariable(inst, game::gScrCompilePub[inst].scriptsPos, name);
|
scriptPosVar = game::GetVariable(inst, game::gScrCompilePub[inst].scriptsPos, name);
|
||||||
filePosId = game::GetObject(inst, scriptPosVar);
|
filePosId = game::GetObject(inst, scriptPosVar);
|
||||||
scriptCountVar = game::GetVariable(inst, game::gScrCompilePub[inst].scriptsCount, name);
|
scriptCountVar = game::GetVariable(inst, game::gScrCompilePub[inst].scriptsCount, name);
|
||||||
fileCountId = game::GetObject(inst, scriptCountVar);
|
fileCountId = game::GetObject(inst, scriptCountVar);
|
||||||
|
|
||||||
game::ScriptCompile(inst, parseData, filePosId, fileCountId, scriptId, entries, entriesCount);
|
game::ScriptCompile(inst, parseData, filePosId, fileCountId, scriptId, entries, entriesCount);
|
||||||
|
|
||||||
game::gScrParserPub[inst].scriptfilename = oldFilename;
|
game::gScrParserPub[inst].scriptfilename = oldFilename;
|
||||||
game::gScrParserPub[inst].sourceBuf = oldSourceBuf;
|
game::gScrParserPub[inst].sourceBuf = oldSourceBuf;
|
||||||
game::gScrAnimPub[inst].animTreeNames = oldAnimTreeNames;
|
game::gScrAnimPub[inst].animTreeNames = oldAnimTreeNames;
|
||||||
|
|
||||||
return filePosId;
|
return filePosId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decomp Status: Tested, Completed
|
// Decomp Status: Tested, Completed
|
||||||
unsigned int Scr_LoadScript(const char* file, game::scriptInstance_t inst)
|
unsigned int Scr_LoadScript(const char* file, game::scriptInstance_t inst)
|
||||||
{
|
{
|
||||||
game::PrecacheEntry entries[1024];
|
game::PrecacheEntry entries[1024];
|
||||||
|
|
||||||
return game::Scr_LoadScriptInternal(inst, file, entries, 0);
|
return game::Scr_LoadScriptInternal(inst, file, entries, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decomp Status: Tested, Completed
|
// Decomp Status: Tested, Completed
|
||||||
void Scr_EndLoadScripts(game::scriptInstance_t inst)
|
void Scr_EndLoadScripts(game::scriptInstance_t inst)
|
||||||
{
|
{
|
||||||
// pluto
|
// pluto
|
||||||
game::plutonium::load_custom_script_func(inst);
|
game::plutonium::load_custom_script_func(inst);
|
||||||
//
|
//
|
||||||
|
|
||||||
game::SL_ShutdownSystem(inst, 2u);
|
game::SL_ShutdownSystem(inst, 2u);
|
||||||
game::gScrCompilePub[inst].script_loading = 0;
|
game::gScrCompilePub[inst].script_loading = 0;
|
||||||
|
|
||||||
assert(game::gScrCompilePub[inst].loadedscripts);
|
assert(game::gScrCompilePub[inst].loadedscripts);
|
||||||
|
|
||||||
game::ClearObject(game::gScrCompilePub[inst].loadedscripts, inst);
|
game::ClearObject(game::gScrCompilePub[inst].loadedscripts, inst);
|
||||||
game::RemoveRefToObject(game::gScrCompilePub[inst].loadedscripts, inst);
|
game::RemoveRefToObject(game::gScrCompilePub[inst].loadedscripts, inst);
|
||||||
game::gScrCompilePub[inst].loadedscripts = 0;
|
game::gScrCompilePub[inst].loadedscripts = 0;
|
||||||
|
|
||||||
assert(game::gScrCompilePub[inst].scriptsPos);
|
assert(game::gScrCompilePub[inst].scriptsPos);
|
||||||
|
|
||||||
game::ClearObject(game::gScrCompilePub[inst].scriptsPos, inst);
|
game::ClearObject(game::gScrCompilePub[inst].scriptsPos, inst);
|
||||||
game::RemoveRefToObject(game::gScrCompilePub[inst].scriptsPos, inst);
|
game::RemoveRefToObject(game::gScrCompilePub[inst].scriptsPos, inst);
|
||||||
game::gScrCompilePub[inst].scriptsPos = 0;
|
game::gScrCompilePub[inst].scriptsPos = 0;
|
||||||
|
|
||||||
assert(game::gScrCompilePub[inst].scriptsCount);
|
assert(game::gScrCompilePub[inst].scriptsCount);
|
||||||
|
|
||||||
game::ClearObject(game::gScrCompilePub[inst].scriptsCount, inst);
|
game::ClearObject(game::gScrCompilePub[inst].scriptsCount, inst);
|
||||||
game::RemoveRefToObject(game::gScrCompilePub[inst].scriptsCount, inst);
|
game::RemoveRefToObject(game::gScrCompilePub[inst].scriptsCount, inst);
|
||||||
game::gScrCompilePub[inst].scriptsCount = 0;
|
game::gScrCompilePub[inst].scriptsCount = 0;
|
||||||
|
|
||||||
assert(game::gScrCompilePub[inst].builtinFunc);
|
assert(game::gScrCompilePub[inst].builtinFunc);
|
||||||
|
|
||||||
game::ClearObject(game::gScrCompilePub[inst].builtinFunc, inst);
|
game::ClearObject(game::gScrCompilePub[inst].builtinFunc, inst);
|
||||||
game::RemoveRefToObject(game::gScrCompilePub[inst].builtinFunc, inst);
|
game::RemoveRefToObject(game::gScrCompilePub[inst].builtinFunc, inst);
|
||||||
game::gScrCompilePub[inst].builtinFunc = 0;
|
game::gScrCompilePub[inst].builtinFunc = 0;
|
||||||
|
|
||||||
assert(game::gScrCompilePub[inst].builtinMeth);
|
assert(game::gScrCompilePub[inst].builtinMeth);
|
||||||
|
|
||||||
game::ClearObject(game::gScrCompilePub[inst].builtinMeth, inst);
|
game::ClearObject(game::gScrCompilePub[inst].builtinMeth, inst);
|
||||||
game::RemoveRefToObject(game::gScrCompilePub[inst].builtinMeth, inst);
|
game::RemoveRefToObject(game::gScrCompilePub[inst].builtinMeth, inst);
|
||||||
game::gScrCompilePub[inst].builtinMeth = 0;
|
game::gScrCompilePub[inst].builtinMeth = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decomp Status: Tested, Completed
|
// Decomp Status: Tested, Completed
|
||||||
void Scr_PrecacheAnimTrees(game::scriptInstance_t inst, void* (__cdecl *Alloc)(int), int user, int modChecksum)
|
void Scr_PrecacheAnimTrees(game::scriptInstance_t inst, void* (__cdecl *Alloc)(int), int user, int modChecksum)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 1; i <= game::gScrAnimPub[inst].xanim_num[user]; ++i)
|
for (i = 1; i <= game::gScrAnimPub[inst].xanim_num[user]; ++i)
|
||||||
{
|
{
|
||||||
game::Scr_LoadAnimTreeAtIndex(inst, user, i, Alloc, modChecksum);
|
game::Scr_LoadAnimTreeAtIndex(inst, user, i, Alloc, modChecksum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decomp Status: Tested, Completed
|
// Decomp Status: Tested, Completed
|
||||||
void Scr_EndLoadAnimTrees(game::scriptInstance_t inst)
|
void Scr_EndLoadAnimTrees(game::scriptInstance_t inst)
|
||||||
{
|
{
|
||||||
unsigned int animtreeNode;
|
unsigned int animtreeNode;
|
||||||
|
|
||||||
assert(game::gScrAnimPub[inst].animtrees);
|
assert(game::gScrAnimPub[inst].animtrees);
|
||||||
|
|
||||||
game::ClearObject(game::gScrAnimPub[inst].animtrees, inst);
|
game::ClearObject(game::gScrAnimPub[inst].animtrees, inst);
|
||||||
game::RemoveRefToObject(game::gScrAnimPub[inst].animtrees, inst);
|
game::RemoveRefToObject(game::gScrAnimPub[inst].animtrees, inst);
|
||||||
animtreeNode = game::gScrAnimPub[inst].animtree_node;
|
animtreeNode = game::gScrAnimPub[inst].animtree_node;
|
||||||
game::gScrAnimPub[inst].animtrees = 0;
|
game::gScrAnimPub[inst].animtrees = 0;
|
||||||
|
|
||||||
if (animtreeNode)
|
if (animtreeNode)
|
||||||
{
|
{
|
||||||
game::RemoveRefToObject(animtreeNode, inst);
|
game::RemoveRefToObject(animtreeNode, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
game::SL_ShutdownSystem(inst, 2u);
|
game::SL_ShutdownSystem(inst, 2u);
|
||||||
|
|
||||||
if (game::gScrVarPub[inst].programBuffer && !game::gScrVarPub[inst].endScriptBuffer)
|
if (game::gScrVarPub[inst].programBuffer && !game::gScrVarPub[inst].endScriptBuffer)
|
||||||
{
|
{
|
||||||
game::gScrVarPub[inst].endScriptBuffer = game::TempMalloc(0);
|
game::gScrVarPub[inst].endScriptBuffer = game::TempMalloc(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
game::gScrAnimPub[inst].animtree_loading = 0;
|
game::gScrAnimPub[inst].animtree_loading = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decomp Status: Tested, Completed
|
// Decomp Status: Tested, Completed
|
||||||
void Scr_FreeScripts(game::scriptInstance_t inst)
|
void Scr_FreeScripts(game::scriptInstance_t inst)
|
||||||
{
|
{
|
||||||
//char sys = 1;
|
//char sys = 1;
|
||||||
|
|
||||||
//assert(sys == SCR_SYS_GAME);
|
//assert(sys == SCR_SYS_GAME);
|
||||||
|
|
||||||
if (game::gScrCompilePub[inst].script_loading)
|
if (game::gScrCompilePub[inst].script_loading)
|
||||||
{
|
{
|
||||||
game::gScrCompilePub[inst].script_loading = 0;
|
game::gScrCompilePub[inst].script_loading = 0;
|
||||||
game::Scr_EndLoadScripts(inst);
|
game::Scr_EndLoadScripts(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game::gScrAnimPub[inst].animtree_loading)
|
if (game::gScrAnimPub[inst].animtree_loading)
|
||||||
{
|
{
|
||||||
game::gScrAnimPub[inst].animtree_loading = 0;
|
game::gScrAnimPub[inst].animtree_loading = 0;
|
||||||
game::Scr_EndLoadAnimTrees(inst);
|
game::Scr_EndLoadAnimTrees(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
game::SL_ShutdownSystem(inst, 1u);
|
game::SL_ShutdownSystem(inst, 1u);
|
||||||
game::Scr_ShutdownOpcodeLookup(inst);
|
game::Scr_ShutdownOpcodeLookup(inst);
|
||||||
|
|
||||||
if (game::gScrVarPub[inst].programHunkUser)
|
if (game::gScrVarPub[inst].programHunkUser)
|
||||||
{
|
{
|
||||||
game::Hunk_UserDestroy(game::gScrVarPub[inst].programHunkUser);
|
game::Hunk_UserDestroy(game::gScrVarPub[inst].programHunkUser);
|
||||||
game::gScrVarPub[inst].programHunkUser = 0;
|
game::gScrVarPub[inst].programHunkUser = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
game::gScrVarPub[inst].programBuffer = 0;
|
game::gScrVarPub[inst].programBuffer = 0;
|
||||||
game::gScrVarPub[inst].endScriptBuffer = 0;
|
game::gScrVarPub[inst].endScriptBuffer = 0;
|
||||||
game::gScrVarPub[inst].checksum = 0;
|
game::gScrVarPub[inst].checksum = 0;
|
||||||
game::gScrCompilePub[inst].programLen = 0;
|
game::gScrCompilePub[inst].programLen = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
@ -21,9 +21,9 @@ namespace codsrc
|
|||||||
return game::FindVariableIndexInternal2(inst, name, (parentId + name) % 0xFFFD + 1);
|
return game::FindVariableIndexInternal2(inst, name, (parentId + name) % 0xFFFD + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decomp Status: Tested, Completed
|
// Decomp Status: Tested, Completed
|
||||||
unsigned int FindVariableIndexInternal2(game::scriptInstance_t inst, unsigned int name, unsigned int index)
|
unsigned int FindVariableIndexInternal2(game::scriptInstance_t inst, unsigned int name, unsigned int index)
|
||||||
{
|
{
|
||||||
unsigned int newIndex;
|
unsigned int newIndex;
|
||||||
game::VariableValueInternal* newEntryValue;
|
game::VariableValueInternal* newEntryValue;
|
||||||
game::VariableValueInternal* entryValue;
|
game::VariableValueInternal* entryValue;
|
||||||
@ -76,11 +76,11 @@ namespace codsrc
|
|||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decomp Status: Tested, Completed
|
// Decomp Status: Tested, Completed
|
||||||
unsigned int FindLastSibling(unsigned int parentId, game::scriptInstance_t inst)
|
unsigned int FindLastSibling(unsigned int parentId, game::scriptInstance_t inst)
|
||||||
{
|
{
|
||||||
game::VariableValueInternal* parentValue;
|
game::VariableValueInternal* parentValue;
|
||||||
unsigned int nextParentVarIndex;
|
unsigned int nextParentVarIndex;
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
@ -101,10 +101,10 @@ namespace codsrc
|
|||||||
|
|
||||||
id = game::gScrVarGlob[inst].parentVariables[nextParentVarIndex].hash.u.prev;
|
id = game::gScrVarGlob[inst].parentVariables[nextParentVarIndex].hash.u.prev;
|
||||||
|
|
||||||
if (!id)
|
if (!id)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
childVarName = game::gScrVarGlob[inst].childVariables[id].w.status >> VAR_NAME_BIT_SHIFT;
|
childVarName = game::gScrVarGlob[inst].childVariables[id].w.status >> VAR_NAME_BIT_SHIFT;
|
||||||
|
|
||||||
@ -113,5 +113,5 @@ namespace codsrc
|
|||||||
assert(index);
|
assert(index);
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
@ -3,21 +3,21 @@
|
|||||||
|
|
||||||
namespace codsrc
|
namespace codsrc
|
||||||
{
|
{
|
||||||
// Restored
|
// Restored
|
||||||
char* TempMalloc(int len)
|
char* TempMalloc(int len)
|
||||||
{
|
{
|
||||||
return (char *)game::Hunk_UserAlloc(*game::g_user, len, 1);
|
return (char *)game::Hunk_UserAlloc(*game::g_user, len, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restored
|
// Restored
|
||||||
void TempMemoryReset(game::HunkUser* user)
|
void TempMemoryReset(game::HunkUser* user)
|
||||||
{
|
{
|
||||||
*game::g_user = user;
|
*game::g_user = user;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restored
|
// Restored
|
||||||
void TempMemorySetPos(char* pos)
|
void TempMemorySetPos(char* pos)
|
||||||
{
|
{
|
||||||
(*game::g_user)->pos = (int)pos;
|
(*game::g_user)->pos = (int)pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1108,16 +1108,16 @@ namespace codsrc
|
|||||||
game::gScrVmPub[inst].function_frame->fs.pos = game::gFs[inst].pos;
|
game::gScrVmPub[inst].function_frame->fs.pos = game::gFs[inst].pos;
|
||||||
/*
|
/*
|
||||||
if ( gScrVmGlob[inst].recordPlace )
|
if ( gScrVmGlob[inst].recordPlace )
|
||||||
Scr_GetFileAndLine(inst, localFs.pos, &gScrVmGlob[inst].lastFileName, &gScrVmGlob[inst].lastLine);
|
Scr_GetFileAndLine(inst, localFs.pos, &gScrVmGlob[inst].lastFileName, &gScrVmGlob[inst].lastLine);
|
||||||
if ( gScrVmDebugPub[inst].func_table[builtinIndex].breakpointCount )
|
if ( gScrVmDebugPub[inst].func_table[builtinIndex].breakpointCount )
|
||||||
{
|
{
|
||||||
if ( gScrVmPub[inst].top != localFs.top - 1 && !Assert_MyHandler("C:\\projects_pc\\cod\\codsrc\\src\\clientscript\\cscr_vm.cpp", 1611, 0, "%s", "gScrVmPub[inst].top == localFs.top - 1") )
|
if ( gScrVmPub[inst].top != localFs.top - 1 && !Assert_MyHandler("C:\\projects_pc\\cod\\codsrc\\src\\clientscript\\cscr_vm.cpp", 1611, 0, "%s", "gScrVmPub[inst].top == localFs.top - 1") )
|
||||||
__debugbreak();
|
__debugbreak();
|
||||||
v104 = gScrVmPub[inst].outparamcount;
|
v104 = gScrVmPub[inst].outparamcount;
|
||||||
Scr_HitBuiltinBreakpoint(inst, localFs.top, debugpos, localFs.localId, gOpcode[inst], builtinIndex, v104 + 1);
|
Scr_HitBuiltinBreakpoint(inst, localFs.top, debugpos, localFs.localId, gOpcode[inst], builtinIndex, v104 + 1);
|
||||||
gScrVmPub[inst].outparamcount = v104;
|
gScrVmPub[inst].outparamcount = v104;
|
||||||
gScrVmPub[inst].top = localFs.top - 1;
|
gScrVmPub[inst].top = localFs.top - 1;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
assert(builtinIndex >= 0);
|
assert(builtinIndex >= 0);
|
||||||
assert(builtinIndex < 1024);
|
assert(builtinIndex < 1024);
|
||||||
@ -5442,7 +5442,7 @@ namespace codsrc
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return game::CScr_SetEntityField(offset, entnum, clientNum);
|
return game::CScr_SetEntityField(offset, entnum, clientNum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,137 +1,137 @@
|
|||||||
#include <stdinc.hpp>
|
#include <stdinc.hpp>
|
||||||
#include "loader/component_loader.hpp"
|
#include "loader/component_loader.hpp"
|
||||||
|
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
#include <utils/io.hpp>
|
#include <utils/io.hpp>
|
||||||
#include <utils/string.hpp>
|
#include <utils/string.hpp>
|
||||||
#include <utils/thread.hpp>
|
#include <utils/thread.hpp>
|
||||||
#include <utils/compression.hpp>
|
#include <utils/compression.hpp>
|
||||||
|
|
||||||
#include <exception/minidump.hpp>
|
#include <exception/minidump.hpp>
|
||||||
|
|
||||||
namespace exception
|
namespace exception
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
thread_local struct
|
thread_local struct
|
||||||
{
|
{
|
||||||
DWORD code = 0;
|
DWORD code = 0;
|
||||||
PVOID address = nullptr;
|
PVOID address = nullptr;
|
||||||
} exception_data;
|
} exception_data;
|
||||||
|
|
||||||
void show_mouse_cursor()
|
void show_mouse_cursor()
|
||||||
{
|
{
|
||||||
while (ShowCursor(TRUE) < 0);
|
while (ShowCursor(TRUE) < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_error_dialog()
|
void display_error_dialog()
|
||||||
{
|
{
|
||||||
std::string error_str = utils::string::va("Fatal error (0x%08X) at 0x%p.\n"
|
std::string error_str = utils::string::va("Fatal error (0x%08X) at 0x%p.\n"
|
||||||
"A minidump has been written.\n\n",
|
"A minidump has been written.\n\n",
|
||||||
exception_data.code, exception_data.address);
|
exception_data.code, exception_data.address);
|
||||||
|
|
||||||
error_str += "Make sure to update your graphics card drivers and install operating system updates!";
|
error_str += "Make sure to update your graphics card drivers and install operating system updates!";
|
||||||
|
|
||||||
utils::thread::suspend_other_threads();
|
utils::thread::suspend_other_threads();
|
||||||
show_mouse_cursor();
|
show_mouse_cursor();
|
||||||
MessageBoxA(nullptr, error_str.data(), "Plutonium T4 ERROR", MB_ICONERROR);
|
MessageBoxA(nullptr, error_str.data(), "Plutonium T4 ERROR", MB_ICONERROR);
|
||||||
TerminateProcess(GetCurrentProcess(), exception_data.code);
|
TerminateProcess(GetCurrentProcess(), exception_data.code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset_state()
|
void reset_state()
|
||||||
{
|
{
|
||||||
display_error_dialog();
|
display_error_dialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t get_reset_state_stub()
|
size_t get_reset_state_stub()
|
||||||
{
|
{
|
||||||
static auto* stub = utils::hook::assemble([](utils::hook::assembler& a)
|
static auto* stub = utils::hook::assemble([](utils::hook::assembler& a)
|
||||||
{
|
{
|
||||||
a.sub(esp, 0x10);
|
a.sub(esp, 0x10);
|
||||||
a.or_(esp, 0x8);
|
a.or_(esp, 0x8);
|
||||||
a.jmp(reset_state);
|
a.jmp(reset_state);
|
||||||
});
|
});
|
||||||
|
|
||||||
return reinterpret_cast<size_t>(stub);
|
return reinterpret_cast<size_t>(stub);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string generate_crash_info(const LPEXCEPTION_POINTERS exceptioninfo)
|
std::string generate_crash_info(const LPEXCEPTION_POINTERS exceptioninfo)
|
||||||
{
|
{
|
||||||
std::string info{};
|
std::string info{};
|
||||||
const auto line = [&info](const std::string& text)
|
const auto line = [&info](const std::string& text)
|
||||||
{
|
{
|
||||||
info.append(text);
|
info.append(text);
|
||||||
info.append("\r\n");
|
info.append("\r\n");
|
||||||
};
|
};
|
||||||
|
|
||||||
line("Plutonium T4 Crash Dump");
|
line("Plutonium T4 Crash Dump");
|
||||||
line("");
|
line("");
|
||||||
line("Timestamp: "s + utils::string::get_timestamp());
|
line("Timestamp: "s + utils::string::get_timestamp());
|
||||||
line(utils::string::va("Exception: 0x%08X", exceptioninfo->ExceptionRecord->ExceptionCode));
|
line(utils::string::va("Exception: 0x%08X", exceptioninfo->ExceptionRecord->ExceptionCode));
|
||||||
line(utils::string::va("Address: 0x%lX", exceptioninfo->ExceptionRecord->ExceptionAddress));
|
line(utils::string::va("Address: 0x%lX", exceptioninfo->ExceptionRecord->ExceptionAddress));
|
||||||
|
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable: 4996)
|
#pragma warning(disable: 4996)
|
||||||
OSVERSIONINFOEXA version_info;
|
OSVERSIONINFOEXA version_info;
|
||||||
ZeroMemory(&version_info, sizeof(version_info));
|
ZeroMemory(&version_info, sizeof(version_info));
|
||||||
version_info.dwOSVersionInfoSize = sizeof(version_info);
|
version_info.dwOSVersionInfoSize = sizeof(version_info);
|
||||||
GetVersionExA(reinterpret_cast<LPOSVERSIONINFOA>(&version_info));
|
GetVersionExA(reinterpret_cast<LPOSVERSIONINFOA>(&version_info));
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
|
|
||||||
line(utils::string::va("OS Version: %u.%u", version_info.dwMajorVersion, version_info.dwMinorVersion));
|
line(utils::string::va("OS Version: %u.%u", version_info.dwMajorVersion, version_info.dwMinorVersion));
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_minidump(const LPEXCEPTION_POINTERS exceptioninfo)
|
void write_minidump(const LPEXCEPTION_POINTERS exceptioninfo)
|
||||||
{
|
{
|
||||||
const std::string crash_name = utils::string::va("minidumps/plutonium-t4-crash-%s.zip",
|
const std::string crash_name = utils::string::va("minidumps/plutonium-t4-crash-%s.zip",
|
||||||
utils::string::get_timestamp().data());
|
utils::string::get_timestamp().data());
|
||||||
|
|
||||||
utils::compression::zip::archive zip_file{};
|
utils::compression::zip::archive zip_file{};
|
||||||
zip_file.add("crash.dmp", create_minidump(exceptioninfo));
|
zip_file.add("crash.dmp", create_minidump(exceptioninfo));
|
||||||
zip_file.add("info.txt", generate_crash_info(exceptioninfo));
|
zip_file.add("info.txt", generate_crash_info(exceptioninfo));
|
||||||
zip_file.write(crash_name, "Plutonium T4 Crash Dump");
|
zip_file.write(crash_name, "Plutonium T4 Crash Dump");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_harmless_error(const LPEXCEPTION_POINTERS exceptioninfo)
|
bool is_harmless_error(const LPEXCEPTION_POINTERS exceptioninfo)
|
||||||
{
|
{
|
||||||
const auto code = exceptioninfo->ExceptionRecord->ExceptionCode;
|
const auto code = exceptioninfo->ExceptionRecord->ExceptionCode;
|
||||||
return code == STATUS_INTEGER_OVERFLOW || code == STATUS_FLOAT_OVERFLOW || code == STATUS_SINGLE_STEP;
|
return code == STATUS_INTEGER_OVERFLOW || code == STATUS_FLOAT_OVERFLOW || code == STATUS_SINGLE_STEP;
|
||||||
}
|
}
|
||||||
|
|
||||||
LONG WINAPI exception_filter(const LPEXCEPTION_POINTERS exceptioninfo)
|
LONG WINAPI exception_filter(const LPEXCEPTION_POINTERS exceptioninfo)
|
||||||
{
|
{
|
||||||
if (is_harmless_error(exceptioninfo))
|
if (is_harmless_error(exceptioninfo))
|
||||||
{
|
{
|
||||||
return EXCEPTION_CONTINUE_EXECUTION;
|
return EXCEPTION_CONTINUE_EXECUTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
write_minidump(exceptioninfo);
|
write_minidump(exceptioninfo);
|
||||||
|
|
||||||
exception_data.code = exceptioninfo->ExceptionRecord->ExceptionCode;
|
exception_data.code = exceptioninfo->ExceptionRecord->ExceptionCode;
|
||||||
exception_data.address = exceptioninfo->ExceptionRecord->ExceptionAddress;
|
exception_data.address = exceptioninfo->ExceptionRecord->ExceptionAddress;
|
||||||
exceptioninfo->ContextRecord->Eip = get_reset_state_stub();
|
exceptioninfo->ContextRecord->Eip = get_reset_state_stub();
|
||||||
|
|
||||||
return EXCEPTION_CONTINUE_EXECUTION;
|
return EXCEPTION_CONTINUE_EXECUTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI set_unhandled_exception_filter_stub(LPTOP_LEVEL_EXCEPTION_FILTER)
|
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI set_unhandled_exception_filter_stub(LPTOP_LEVEL_EXCEPTION_FILTER)
|
||||||
{
|
{
|
||||||
// Don't register anything here...
|
// Don't register anything here...
|
||||||
return &exception_filter;
|
return &exception_filter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class component final : public component_interface
|
class component final : public component_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void post_unpack() override
|
void post_unpack() override
|
||||||
{
|
{
|
||||||
SetUnhandledExceptionFilter(exception_filter);
|
SetUnhandledExceptionFilter(exception_filter);
|
||||||
utils::hook::jump(reinterpret_cast<uintptr_t>(&SetUnhandledExceptionFilter), set_unhandled_exception_filter_stub);
|
utils::hook::jump(reinterpret_cast<uintptr_t>(&SetUnhandledExceptionFilter), set_unhandled_exception_filter_stub);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
REGISTER_COMPONENT(exception::component)
|
REGISTER_COMPONENT(exception::component)
|
||||||
|
@ -1,195 +1,195 @@
|
|||||||
#include <stdinc.hpp>
|
#include <stdinc.hpp>
|
||||||
#include "loader/component_loader.hpp"
|
#include "loader/component_loader.hpp"
|
||||||
|
|
||||||
#include "scheduler.hpp"
|
#include "scheduler.hpp"
|
||||||
|
|
||||||
#include <utils/concurrency.hpp>
|
#include <utils/concurrency.hpp>
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
|
|
||||||
namespace scheduler
|
namespace scheduler
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
struct task
|
struct task
|
||||||
{
|
{
|
||||||
std::function<bool()> handler{};
|
std::function<bool()> handler{};
|
||||||
std::chrono::milliseconds interval{};
|
std::chrono::milliseconds interval{};
|
||||||
std::chrono::high_resolution_clock::time_point last_call{};
|
std::chrono::high_resolution_clock::time_point last_call{};
|
||||||
};
|
};
|
||||||
|
|
||||||
using task_list = std::vector<task>;
|
using task_list = std::vector<task>;
|
||||||
|
|
||||||
class task_pipeline
|
class task_pipeline
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void add(task&& task)
|
void add(task&& task)
|
||||||
{
|
{
|
||||||
new_callbacks_.access([&task](task_list& tasks)
|
new_callbacks_.access([&task](task_list& tasks)
|
||||||
{
|
{
|
||||||
tasks.emplace_back(std::move(task));
|
tasks.emplace_back(std::move(task));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void execute()
|
void execute()
|
||||||
{
|
{
|
||||||
callbacks_.access([&](task_list& tasks)
|
callbacks_.access([&](task_list& tasks)
|
||||||
{
|
{
|
||||||
this->merge_callbacks();
|
this->merge_callbacks();
|
||||||
|
|
||||||
for (auto i = tasks.begin(); i != tasks.end();)
|
for (auto i = tasks.begin(); i != tasks.end();)
|
||||||
{
|
{
|
||||||
const auto now = std::chrono::high_resolution_clock::now();
|
const auto now = std::chrono::high_resolution_clock::now();
|
||||||
const auto diff = now - i->last_call;
|
const auto diff = now - i->last_call;
|
||||||
|
|
||||||
if (diff < i->interval)
|
if (diff < i->interval)
|
||||||
{
|
{
|
||||||
++i;
|
++i;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
i->last_call = now;
|
i->last_call = now;
|
||||||
|
|
||||||
const auto res = i->handler();
|
const auto res = i->handler();
|
||||||
if (res == cond_end)
|
if (res == cond_end)
|
||||||
{
|
{
|
||||||
i = tasks.erase(i);
|
i = tasks.erase(i);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
utils::concurrency::container<task_list> new_callbacks_;
|
utils::concurrency::container<task_list> new_callbacks_;
|
||||||
utils::concurrency::container<task_list, std::recursive_mutex> callbacks_;
|
utils::concurrency::container<task_list, std::recursive_mutex> callbacks_;
|
||||||
|
|
||||||
void merge_callbacks()
|
void merge_callbacks()
|
||||||
{
|
{
|
||||||
callbacks_.access([&](task_list& tasks)
|
callbacks_.access([&](task_list& tasks)
|
||||||
{
|
{
|
||||||
new_callbacks_.access([&](task_list& new_tasks)
|
new_callbacks_.access([&](task_list& new_tasks)
|
||||||
{
|
{
|
||||||
tasks.insert(tasks.end(), std::move_iterator<task_list::iterator>(new_tasks.begin()), std::move_iterator<task_list::iterator>(new_tasks.end()));
|
tasks.insert(tasks.end(), std::move_iterator<task_list::iterator>(new_tasks.begin()), std::move_iterator<task_list::iterator>(new_tasks.end()));
|
||||||
new_tasks = {};
|
new_tasks = {};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::thread thread;
|
std::thread thread;
|
||||||
task_pipeline pipelines[pipeline::count];
|
task_pipeline pipelines[pipeline::count];
|
||||||
|
|
||||||
void execute(const pipeline type)
|
void execute(const pipeline type)
|
||||||
{
|
{
|
||||||
assert(type >= 0 && type < pipeline::count);
|
assert(type >= 0 && type < pipeline::count);
|
||||||
pipelines[type].execute();
|
pipelines[type].execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
void execute_server()
|
void execute_server()
|
||||||
{
|
{
|
||||||
execute(pipeline::server);
|
execute(pipeline::server);
|
||||||
}
|
}
|
||||||
|
|
||||||
void execute_main()
|
void execute_main()
|
||||||
{
|
{
|
||||||
execute(pipeline::main);
|
execute(pipeline::main);
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::hook::detour com_init_hook;
|
utils::hook::detour com_init_hook;
|
||||||
utils::hook::detour gscr_postloadscripts_hook;
|
utils::hook::detour gscr_postloadscripts_hook;
|
||||||
|
|
||||||
std::vector<std::function<void()>> post_init_funcs;
|
std::vector<std::function<void()>> post_init_funcs;
|
||||||
bool com_inited = false;
|
bool com_inited = false;
|
||||||
|
|
||||||
void on_post_init_hook()
|
void on_post_init_hook()
|
||||||
{
|
{
|
||||||
if (com_inited)
|
if (com_inited)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
com_inited = true;
|
com_inited = true;
|
||||||
for (const auto& func : post_init_funcs)
|
for (const auto& func : post_init_funcs)
|
||||||
{
|
{
|
||||||
func();
|
func();
|
||||||
}
|
}
|
||||||
|
|
||||||
post_init_funcs.clear();
|
post_init_funcs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void com_init_stub()
|
void com_init_stub()
|
||||||
{
|
{
|
||||||
com_init_hook.invoke<void>();
|
com_init_hook.invoke<void>();
|
||||||
on_post_init_hook();
|
on_post_init_hook();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void schedule(const std::function<bool()>& callback, const pipeline type,
|
void schedule(const std::function<bool()>& callback, const pipeline type,
|
||||||
const std::chrono::milliseconds delay)
|
const std::chrono::milliseconds delay)
|
||||||
{
|
{
|
||||||
assert(type >= 0 && type < pipeline::count);
|
assert(type >= 0 && type < pipeline::count);
|
||||||
|
|
||||||
task task;
|
task task;
|
||||||
task.handler = callback;
|
task.handler = callback;
|
||||||
task.interval = delay;
|
task.interval = delay;
|
||||||
task.last_call = std::chrono::high_resolution_clock::now();
|
task.last_call = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
pipelines[type].add(std::move(task));
|
pipelines[type].add(std::move(task));
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop(const std::function<void()>& callback, const pipeline type,
|
void loop(const std::function<void()>& callback, const pipeline type,
|
||||||
const std::chrono::milliseconds delay)
|
const std::chrono::milliseconds delay)
|
||||||
{
|
{
|
||||||
schedule([callback]()
|
schedule([callback]()
|
||||||
{
|
{
|
||||||
callback();
|
callback();
|
||||||
return cond_continue;
|
return cond_continue;
|
||||||
}, type, delay);
|
}, type, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
void once(const std::function<void()>& callback, const pipeline type,
|
void once(const std::function<void()>& callback, const pipeline type,
|
||||||
const std::chrono::milliseconds delay)
|
const std::chrono::milliseconds delay)
|
||||||
{
|
{
|
||||||
schedule([callback]()
|
schedule([callback]()
|
||||||
{
|
{
|
||||||
callback();
|
callback();
|
||||||
return cond_end;
|
return cond_end;
|
||||||
}, type, delay);
|
}, type, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_init(const std::function<void()>& callback)
|
void on_init(const std::function<void()>& callback)
|
||||||
{
|
{
|
||||||
if (com_inited)
|
if (com_inited)
|
||||||
{
|
{
|
||||||
once(callback, pipeline::main);
|
once(callback, pipeline::main);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
post_init_funcs.push_back(callback);
|
post_init_funcs.push_back(callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class component final : public component_interface
|
class component final : public component_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void post_unpack() override
|
void post_unpack() override
|
||||||
{
|
{
|
||||||
thread = std::thread([]()
|
thread = std::thread([]()
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
execute(pipeline::async);
|
execute(pipeline::async);
|
||||||
std::this_thread::sleep_for(10ms);
|
std::this_thread::sleep_for(10ms);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
com_init_hook.create(SELECT(0x0, 0x59D710), com_init_stub);
|
com_init_hook.create(SELECT(0x0, 0x59D710), com_init_stub);
|
||||||
utils::hook::call(SELECT(0x0, 0x503B5D), execute_server);
|
utils::hook::call(SELECT(0x0, 0x503B5D), execute_server);
|
||||||
utils::hook::call(SELECT(0x0, 0x59DCFD), execute_main);
|
utils::hook::call(SELECT(0x0, 0x59DCFD), execute_main);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
REGISTER_COMPONENT(scheduler::component)
|
REGISTER_COMPONENT(scheduler::component)
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace scheduler
|
namespace scheduler
|
||||||
{
|
{
|
||||||
enum pipeline
|
enum pipeline
|
||||||
{
|
{
|
||||||
server,
|
server,
|
||||||
async,
|
async,
|
||||||
main,
|
main,
|
||||||
count,
|
count,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const bool cond_continue = false;
|
static const bool cond_continue = false;
|
||||||
static const bool cond_end = true;
|
static const bool cond_end = true;
|
||||||
|
|
||||||
void schedule(const std::function<bool()>& callback, pipeline type = pipeline::main,
|
void schedule(const std::function<bool()>& callback, pipeline type = pipeline::main,
|
||||||
std::chrono::milliseconds delay = 0ms);
|
std::chrono::milliseconds delay = 0ms);
|
||||||
void loop(const std::function<void()>& callback, pipeline type = pipeline::main,
|
void loop(const std::function<void()>& callback, pipeline type = pipeline::main,
|
||||||
std::chrono::milliseconds delay = 0ms);
|
std::chrono::milliseconds delay = 0ms);
|
||||||
void once(const std::function<void()>& callback, pipeline type = pipeline::main,
|
void once(const std::function<void()>& callback, pipeline type = pipeline::main,
|
||||||
std::chrono::milliseconds delay = 0ms);
|
std::chrono::milliseconds delay = 0ms);
|
||||||
|
|
||||||
void on_init(const std::function<void()>& callback);
|
void on_init(const std::function<void()>& callback);
|
||||||
}
|
}
|
||||||
|
@ -1,39 +1,39 @@
|
|||||||
#include <stdinc.hpp>
|
#include <stdinc.hpp>
|
||||||
#include "loader/component_loader.hpp"
|
#include "loader/component_loader.hpp"
|
||||||
|
|
||||||
#include "scheduler.hpp"
|
#include "scheduler.hpp"
|
||||||
#include "gsc.hpp"
|
#include "gsc.hpp"
|
||||||
|
|
||||||
#include <utils/io.hpp>
|
#include <utils/io.hpp>
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
#include <utils/string.hpp>
|
#include <utils/string.hpp>
|
||||||
#include <utils/http.hpp>
|
#include <utils/http.hpp>
|
||||||
#include <json.hpp>
|
#include <json.hpp>
|
||||||
|
|
||||||
namespace test
|
namespace test
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
class component final : public component_interface
|
class component final : public component_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void post_unpack() override
|
void post_unpack() override
|
||||||
{
|
{
|
||||||
//Disable AI print spam
|
//Disable AI print spam
|
||||||
utils::hook::nop(0x4BAB7D, 5);
|
utils::hook::nop(0x4BAB7D, 5);
|
||||||
utils::hook::nop(0x4BAAFA, 5);
|
utils::hook::nop(0x4BAAFA, 5);
|
||||||
|
|
||||||
//Disable asset loading print spam
|
//Disable asset loading print spam
|
||||||
utils::hook::nop(0x48D9D9, 5);
|
utils::hook::nop(0x48D9D9, 5);
|
||||||
|
|
||||||
//Disable unknown dvar spam
|
//Disable unknown dvar spam
|
||||||
utils::hook::nop(0x5F04AF, 5);
|
utils::hook::nop(0x5F04AF, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
REGISTER_COMPONENT(test::component)
|
REGISTER_COMPONENT(test::component)
|
||||||
|
@ -1,39 +1,39 @@
|
|||||||
#include <stdinc.hpp>
|
#include <stdinc.hpp>
|
||||||
#include "loader/component_loader.hpp"
|
#include "loader/component_loader.hpp"
|
||||||
#include "component/signatures.hpp"
|
#include "component/signatures.hpp"
|
||||||
|
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
|
|
||||||
BOOL APIENTRY DllMain(HMODULE /*module_*/, DWORD ul_reason_for_call, LPVOID /*reserved_*/)
|
BOOL APIENTRY DllMain(HMODULE /*module_*/, DWORD ul_reason_for_call, LPVOID /*reserved_*/)
|
||||||
{
|
{
|
||||||
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
|
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
|
||||||
{
|
{
|
||||||
if (game::environment::t4sp())
|
if (game::environment::t4sp())
|
||||||
{
|
{
|
||||||
if (!signatures::process())
|
if (!signatures::process())
|
||||||
{
|
{
|
||||||
MessageBoxA(NULL,
|
MessageBoxA(NULL,
|
||||||
"This version of t4sp-server-plugin is outdated.\n" \
|
"This version of t4sp-server-plugin is outdated.\n" \
|
||||||
"Download the latest dll from here: https://github.com/JezuzLizard/T4SP-Server-Plugin/releases",
|
"Download the latest dll from here: https://github.com/JezuzLizard/T4SP-Server-Plugin/releases",
|
||||||
"ERROR", MB_ICONERROR);
|
"ERROR", MB_ICONERROR);
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game::plutonium::printf.get() != nullptr)
|
if (game::plutonium::printf.get() != nullptr)
|
||||||
{
|
{
|
||||||
utils::hook::jump(reinterpret_cast<uintptr_t>(&printf), game::plutonium::printf);
|
utils::hook::jump(reinterpret_cast<uintptr_t>(&printf), game::plutonium::printf);
|
||||||
}
|
}
|
||||||
|
|
||||||
component_loader::post_unpack();
|
component_loader::post_unpack();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MessageBoxA(nullptr, "Unsupported game executable. (t4sp is only supported)", "ERROR, BRO!", 0);
|
MessageBoxA(nullptr, "Unsupported game executable. (t4sp is only supported)", "ERROR, BRO!", 0);
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
@ -1,94 +1,94 @@
|
|||||||
#include <stdinc.hpp>
|
#include <stdinc.hpp>
|
||||||
#include "minidump.hpp"
|
#include "minidump.hpp"
|
||||||
|
|
||||||
#include <DbgHelp.h>
|
#include <DbgHelp.h>
|
||||||
#pragma comment(lib, "dbghelp.lib")
|
#pragma comment(lib, "dbghelp.lib")
|
||||||
|
|
||||||
#include <gsl/gsl>
|
#include <gsl/gsl>
|
||||||
|
|
||||||
namespace exception
|
namespace exception
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
constexpr MINIDUMP_TYPE get_minidump_type()
|
constexpr MINIDUMP_TYPE get_minidump_type()
|
||||||
{
|
{
|
||||||
const auto type = MiniDumpIgnoreInaccessibleMemory //
|
const auto type = MiniDumpIgnoreInaccessibleMemory //
|
||||||
| MiniDumpWithHandleData //
|
| MiniDumpWithHandleData //
|
||||||
| MiniDumpScanMemory //
|
| MiniDumpScanMemory //
|
||||||
| MiniDumpWithProcessThreadData //
|
| MiniDumpWithProcessThreadData //
|
||||||
| MiniDumpWithFullMemoryInfo //
|
| MiniDumpWithFullMemoryInfo //
|
||||||
| MiniDumpWithThreadInfo //
|
| MiniDumpWithThreadInfo //
|
||||||
| MiniDumpWithUnloadedModules;
|
| MiniDumpWithUnloadedModules;
|
||||||
|
|
||||||
return static_cast<MINIDUMP_TYPE>(type);
|
return static_cast<MINIDUMP_TYPE>(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_temp_filename()
|
std::string get_temp_filename()
|
||||||
{
|
{
|
||||||
char filename[MAX_PATH] = {0};
|
char filename[MAX_PATH] = {0};
|
||||||
char pathname[MAX_PATH] = {0};
|
char pathname[MAX_PATH] = {0};
|
||||||
|
|
||||||
GetTempPathA(sizeof(pathname), pathname);
|
GetTempPathA(sizeof(pathname), pathname);
|
||||||
GetTempFileNameA(pathname, "Plutonium T4 -", 0, filename);
|
GetTempFileNameA(pathname, "Plutonium T4 -", 0, filename);
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE write_dump_to_temp_file(const LPEXCEPTION_POINTERS exceptioninfo)
|
HANDLE write_dump_to_temp_file(const LPEXCEPTION_POINTERS exceptioninfo)
|
||||||
{
|
{
|
||||||
MINIDUMP_EXCEPTION_INFORMATION minidump_exception_info = {GetCurrentThreadId(), exceptioninfo, FALSE};
|
MINIDUMP_EXCEPTION_INFORMATION minidump_exception_info = {GetCurrentThreadId(), exceptioninfo, FALSE};
|
||||||
|
|
||||||
auto* const file_handle = CreateFileA(get_temp_filename().data(), GENERIC_WRITE | GENERIC_READ,
|
auto* const file_handle = CreateFileA(get_temp_filename().data(), GENERIC_WRITE | GENERIC_READ,
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS,
|
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS,
|
||||||
FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
|
FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
|
||||||
nullptr);
|
nullptr);
|
||||||
|
|
||||||
if (!MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), file_handle, get_minidump_type(),
|
if (!MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), file_handle, get_minidump_type(),
|
||||||
&minidump_exception_info,
|
&minidump_exception_info,
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr))
|
nullptr))
|
||||||
{
|
{
|
||||||
MessageBoxA(nullptr, "There was an error creating the minidump! Hit OK to close the program.",
|
MessageBoxA(nullptr, "There was an error creating the minidump! Hit OK to close the program.",
|
||||||
"Minidump Error", MB_OK | MB_ICONERROR);
|
"Minidump Error", MB_OK | MB_ICONERROR);
|
||||||
TerminateProcess(GetCurrentProcess(), 123);
|
TerminateProcess(GetCurrentProcess(), 123);
|
||||||
}
|
}
|
||||||
|
|
||||||
return file_handle;
|
return file_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string read_file(HANDLE file_handle)
|
std::string read_file(HANDLE file_handle)
|
||||||
{
|
{
|
||||||
FlushFileBuffers(file_handle);
|
FlushFileBuffers(file_handle);
|
||||||
SetFilePointer(file_handle, 0, nullptr, FILE_BEGIN);
|
SetFilePointer(file_handle, 0, nullptr, FILE_BEGIN);
|
||||||
|
|
||||||
std::string buffer{};
|
std::string buffer{};
|
||||||
|
|
||||||
DWORD bytes_read = 0;
|
DWORD bytes_read = 0;
|
||||||
char temp_bytes[0x2000];
|
char temp_bytes[0x2000];
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (!ReadFile(file_handle, temp_bytes, sizeof(temp_bytes), &bytes_read, nullptr))
|
if (!ReadFile(file_handle, temp_bytes, sizeof(temp_bytes), &bytes_read, nullptr))
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.append(temp_bytes, bytes_read);
|
buffer.append(temp_bytes, bytes_read);
|
||||||
}
|
}
|
||||||
while (bytes_read == sizeof(temp_bytes));
|
while (bytes_read == sizeof(temp_bytes));
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string create_minidump(const LPEXCEPTION_POINTERS exceptioninfo)
|
std::string create_minidump(const LPEXCEPTION_POINTERS exceptioninfo)
|
||||||
{
|
{
|
||||||
auto* const file_handle = write_dump_to_temp_file(exceptioninfo);
|
auto* const file_handle = write_dump_to_temp_file(exceptioninfo);
|
||||||
|
|
||||||
const auto _ = gsl::finally([file_handle]()
|
const auto _ = gsl::finally([file_handle]()
|
||||||
{
|
{
|
||||||
CloseHandle(file_handle);
|
CloseHandle(file_handle);
|
||||||
});
|
});
|
||||||
|
|
||||||
return read_file(file_handle);
|
return read_file(file_handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace exception
|
namespace exception
|
||||||
{
|
{
|
||||||
std::string create_minidump(LPEXCEPTION_POINTERS exceptioninfo);
|
std::string create_minidump(LPEXCEPTION_POINTERS exceptioninfo);
|
||||||
}
|
}
|
||||||
|
7826
src/game/enums.hpp
7826
src/game/enums.hpp
File diff suppressed because it is too large
Load Diff
@ -1,206 +1,206 @@
|
|||||||
#include <stdinc.hpp>
|
#include <stdinc.hpp>
|
||||||
|
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
#include <utils/memory.hpp>
|
#include <utils/memory.hpp>
|
||||||
#include <utils/string.hpp>
|
#include <utils/string.hpp>
|
||||||
|
|
||||||
namespace game
|
namespace game
|
||||||
{
|
{
|
||||||
gamemode current = reinterpret_cast<const char*>(0x88A5DC) != "CoDWaW.exe"s
|
gamemode current = reinterpret_cast<const char*>(0x88A5DC) != "CoDWaW.exe"s
|
||||||
? gamemode::multiplayer
|
? gamemode::multiplayer
|
||||||
: gamemode::singleplayer;
|
: gamemode::singleplayer;
|
||||||
|
|
||||||
namespace environment
|
namespace environment
|
||||||
{
|
{
|
||||||
bool t4mp()
|
bool t4mp()
|
||||||
{
|
{
|
||||||
return current == gamemode::multiplayer;
|
return current == gamemode::multiplayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool t4sp()
|
bool t4sp()
|
||||||
{
|
{
|
||||||
return current == gamemode::singleplayer;
|
return current == gamemode::singleplayer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HunkUser* __usercall Hunk_UserCreate@<eax>(signed int maxSize@<edi>, char* name, char fixed, char tempMem, char debugMem, int type);
|
// HunkUser* __usercall Hunk_UserCreate@<eax>(signed int maxSize@<edi>, char* name, char fixed, char tempMem, char debugMem, int type);
|
||||||
HunkUser* Hunk_UserCreate(signed int maxSize, const char* name, int fixed, int tempMem, int debugMem, int typ, void* call_addr)
|
HunkUser* Hunk_UserCreate(signed int maxSize, const char* name, int fixed, int tempMem, int debugMem, int typ, void* call_addr)
|
||||||
{
|
{
|
||||||
HunkUser* answer;
|
HunkUser* answer;
|
||||||
|
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
push typ;
|
push typ;
|
||||||
push debugMem;
|
push debugMem;
|
||||||
push tempMem;
|
push tempMem;
|
||||||
push fixed;
|
push fixed;
|
||||||
push name;
|
push name;
|
||||||
mov edi, maxSize;
|
mov edi, maxSize;
|
||||||
call call_addr;
|
call call_addr;
|
||||||
add esp, 0x14;
|
add esp, 0x14;
|
||||||
mov answer, eax;
|
mov answer, eax;
|
||||||
}
|
}
|
||||||
|
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// unsigned int __usercall Hunk_AllocateTempMemoryHigh@<eax>(int a1@<eax>)
|
// unsigned int __usercall Hunk_AllocateTempMemoryHigh@<eax>(int a1@<eax>)
|
||||||
unsigned int Hunk_AllocateTempMemoryHigh(int size_, void* call_addr)
|
unsigned int Hunk_AllocateTempMemoryHigh(int size_, void* call_addr)
|
||||||
{
|
{
|
||||||
unsigned int answer;
|
unsigned int answer;
|
||||||
|
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
mov eax, size_;
|
mov eax, size_;
|
||||||
call call_addr;
|
call call_addr;
|
||||||
mov answer, eax;
|
mov answer, eax;
|
||||||
}
|
}
|
||||||
|
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// void __usercall FS_FCloseFile(int h@<eax>)
|
// void __usercall FS_FCloseFile(int h@<eax>)
|
||||||
void FS_FCloseFile(int h, void* call_addr)
|
void FS_FCloseFile(int h, void* call_addr)
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
mov eax, h;
|
mov eax, h;
|
||||||
call call_addr;
|
call call_addr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// void *__usercall Z_TryVirtualAlloc@<eax>(signed int a1@<edi>)
|
// void *__usercall Z_TryVirtualAlloc@<eax>(signed int a1@<edi>)
|
||||||
void* Z_TryVirtualAlloc(signed int size_, void* call_addr)
|
void* Z_TryVirtualAlloc(signed int size_, void* call_addr)
|
||||||
{
|
{
|
||||||
void* answer;
|
void* answer;
|
||||||
|
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
mov edi, size_;
|
mov edi, size_;
|
||||||
call call_addr;
|
call call_addr;
|
||||||
mov answer, eax;
|
mov answer, eax;
|
||||||
}
|
}
|
||||||
|
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// int __usercall I_stricmp@<eax>(int a1@<eax>, CHAR *a2@<edx>, const char *a3)
|
// int __usercall I_stricmp@<eax>(int a1@<eax>, CHAR *a2@<edx>, const char *a3)
|
||||||
int I_stricmp(int len, const char* s0, const char* s1, void* call_addr)
|
int I_stricmp(int len, const char* s0, const char* s1, void* call_addr)
|
||||||
{
|
{
|
||||||
int answer;
|
int answer;
|
||||||
|
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
push s1;
|
push s1;
|
||||||
mov eax, len;
|
mov eax, len;
|
||||||
mov edx, s0;
|
mov edx, s0;
|
||||||
call call_addr;
|
call call_addr;
|
||||||
mov answer, eax;
|
mov answer, eax;
|
||||||
add esp, 0x4;
|
add esp, 0x4;
|
||||||
}
|
}
|
||||||
|
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
//parseInfo_t* __usercall Com_Parse@<eax>(const char** a1@<esi>)
|
//parseInfo_t* __usercall Com_Parse@<eax>(const char** a1@<esi>)
|
||||||
parseInfo_t* Com_Parse(const char** buffer, void* call_addr)
|
parseInfo_t* Com_Parse(const char** buffer, void* call_addr)
|
||||||
{
|
{
|
||||||
parseInfo_t* answer;
|
parseInfo_t* answer;
|
||||||
|
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
mov esi, buffer;
|
mov esi, buffer;
|
||||||
call call_addr;
|
call call_addr;
|
||||||
mov answer, eax;
|
mov answer, eax;
|
||||||
}
|
}
|
||||||
|
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
//int __usercall I_strncmp@<eax>(char *str1@<edx>, char *str2@<ecx>, int len)
|
//int __usercall I_strncmp@<eax>(char *str1@<edx>, char *str2@<ecx>, int len)
|
||||||
int I_strncmp(const char* str1, const char* str2, int len, void* call_addr)
|
int I_strncmp(const char* str1, const char* str2, int len, void* call_addr)
|
||||||
{
|
{
|
||||||
int answer;
|
int answer;
|
||||||
|
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
push len;
|
push len;
|
||||||
mov ecx, str2;
|
mov ecx, str2;
|
||||||
mov edx, str1;
|
mov edx, str1;
|
||||||
call call_addr;
|
call call_addr;
|
||||||
mov answer, eax;
|
mov answer, eax;
|
||||||
}
|
}
|
||||||
|
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// const char **__usercall FS_ListFilteredFiles@<eax>(searchpath_s *searchPath@<eax>, const char *path@<edx>, const char *extension, const char *filter, FsListBehavior_e behavior, int *numFiles)
|
// const char **__usercall FS_ListFilteredFiles@<eax>(searchpath_s *searchPath@<eax>, const char *path@<edx>, const char *extension, const char *filter, FsListBehavior_e behavior, int *numFiles)
|
||||||
const char** FS_ListFilteredFiles(searchpath_s* searchPath, const char* path, const char* extension, const char* filter, FsListBehavior_e behavior, int* numFiles, void* call_addr)
|
const char** FS_ListFilteredFiles(searchpath_s* searchPath, const char* path, const char* extension, const char* filter, FsListBehavior_e behavior, int* numFiles, void* call_addr)
|
||||||
{
|
{
|
||||||
const char** answer;
|
const char** answer;
|
||||||
|
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
push numFiles;
|
push numFiles;
|
||||||
push behavior;
|
push behavior;
|
||||||
push filter;
|
push filter;
|
||||||
push extension;
|
push extension;
|
||||||
mov eax, searchPath;
|
mov eax, searchPath;
|
||||||
mov edx, path;
|
mov edx, path;
|
||||||
call call_addr;
|
call call_addr;
|
||||||
mov answer, eax;
|
mov answer, eax;
|
||||||
add esp, 0x10;
|
add esp, 0x10;
|
||||||
}
|
}
|
||||||
|
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
dvar_s * Dvar_RegisterBool/*@<eax>*/(unsigned __int8 val/*@<al>*/, const char * name/*@<edi>*/, int flags, const char * desc, void* call_addr)
|
dvar_s * Dvar_RegisterBool/*@<eax>*/(unsigned __int8 val/*@<al>*/, const char * name/*@<edi>*/, int flags, const char * desc, void* call_addr)
|
||||||
{
|
{
|
||||||
dvar_s * answer;
|
dvar_s * answer;
|
||||||
|
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
push desc;
|
push desc;
|
||||||
push flags;
|
push flags;
|
||||||
mov al, val;
|
mov al, val;
|
||||||
mov edi, name;
|
mov edi, name;
|
||||||
call call_addr;
|
call call_addr;
|
||||||
mov answer, eax;
|
mov answer, eax;
|
||||||
add esp, 0x8;
|
add esp, 0x8;
|
||||||
}
|
}
|
||||||
|
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char * XAnimGetAnimDebugName/*@<eax>*/(unsigned int animIndex/*@<ecx>*/, XAnim_s * anims/*@<edx>*/, void* call_addr)
|
const char * XAnimGetAnimDebugName/*@<eax>*/(unsigned int animIndex/*@<ecx>*/, XAnim_s * anims/*@<edx>*/, void* call_addr)
|
||||||
{
|
{
|
||||||
const char * answer;
|
const char * answer;
|
||||||
|
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
mov ecx, animIndex;
|
mov ecx, animIndex;
|
||||||
mov edx, anims;
|
mov edx, anims;
|
||||||
call call_addr;
|
call call_addr;
|
||||||
mov answer, eax;
|
mov answer, eax;
|
||||||
}
|
}
|
||||||
|
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// restored
|
// restored
|
||||||
void Sys_EnterCriticalSection(CriticalSection critSect)
|
void Sys_EnterCriticalSection(CriticalSection critSect)
|
||||||
{
|
{
|
||||||
EnterCriticalSection(&s_criticalSection[critSect]);
|
EnterCriticalSection(&s_criticalSection[critSect]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// restored
|
// restored
|
||||||
void Sys_LeaveCriticalSection(CriticalSection critSect)
|
void Sys_LeaveCriticalSection(CriticalSection critSect)
|
||||||
{
|
{
|
||||||
LeaveCriticalSection(&s_criticalSection[critSect]);
|
LeaveCriticalSection(&s_criticalSection[critSect]);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace plutonium
|
namespace plutonium
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,70 +1,70 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define WEAK __declspec(selectany)
|
#define WEAK __declspec(selectany)
|
||||||
#define NAKED __declspec(naked)
|
#define NAKED __declspec(naked)
|
||||||
|
|
||||||
#define SELECT(mp, sp) (game::environment::t4mp() ? mp : sp)
|
#define SELECT(mp, sp) (game::environment::t4mp() ? mp : sp)
|
||||||
#define ASSIGN(type, mp, sp) reinterpret_cast<type>(SELECT(mp, sp))
|
#define ASSIGN(type, mp, sp) reinterpret_cast<type>(SELECT(mp, sp))
|
||||||
#define CALL_ADDR(mp, sp) ASSIGN(void*, mp, sp)
|
#define CALL_ADDR(mp, sp) ASSIGN(void*, mp, sp)
|
||||||
|
|
||||||
#define ARRAY_COUNT(arrayn) \
|
#define ARRAY_COUNT(arrayn) \
|
||||||
((sizeof(arrayn)) / (sizeof(arrayn[0])))
|
((sizeof(arrayn)) / (sizeof(arrayn[0])))
|
||||||
|
|
||||||
namespace game
|
namespace game
|
||||||
{
|
{
|
||||||
enum gamemode
|
enum gamemode
|
||||||
{
|
{
|
||||||
multiplayer,
|
multiplayer,
|
||||||
singleplayer,
|
singleplayer,
|
||||||
none
|
none
|
||||||
};
|
};
|
||||||
|
|
||||||
extern gamemode current;
|
extern gamemode current;
|
||||||
|
|
||||||
namespace environment
|
namespace environment
|
||||||
{
|
{
|
||||||
bool t4mp();
|
bool t4mp();
|
||||||
bool t4sp();
|
bool t4sp();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class symbol
|
class symbol
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
symbol(const size_t t4mp, const size_t t4sp)
|
symbol(const size_t t4mp, const size_t t4sp)
|
||||||
: t4mp_(reinterpret_cast<T*>(t4mp))
|
: t4mp_(reinterpret_cast<T*>(t4mp))
|
||||||
, t4sp_(reinterpret_cast<T*>(t4sp))
|
, t4sp_(reinterpret_cast<T*>(t4sp))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
T* get() const
|
T* get() const
|
||||||
{
|
{
|
||||||
if (environment::t4mp())
|
if (environment::t4mp())
|
||||||
{
|
{
|
||||||
return t4mp_;
|
return t4mp_;
|
||||||
}
|
}
|
||||||
|
|
||||||
return t4sp_;
|
return t4sp_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set(const size_t ptr)
|
void set(const size_t ptr)
|
||||||
{
|
{
|
||||||
this->t4mp_ = reinterpret_cast<T*>(ptr);
|
this->t4mp_ = reinterpret_cast<T*>(ptr);
|
||||||
this->t4sp_ = reinterpret_cast<T*>(ptr);
|
this->t4sp_ = reinterpret_cast<T*>(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
operator T* () const
|
operator T* () const
|
||||||
{
|
{
|
||||||
return this->get();
|
return this->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
T* operator->() const
|
T* operator->() const
|
||||||
{
|
{
|
||||||
return this->get();
|
return this->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T* t4mp_;
|
T* t4mp_;
|
||||||
T* t4sp_;
|
T* t4sp_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
26428
src/game/structs.hpp
26428
src/game/structs.hpp
File diff suppressed because it is too large
Load Diff
@ -1,77 +1,77 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace game
|
namespace game
|
||||||
{
|
{
|
||||||
// Functions
|
// Functions
|
||||||
WEAK symbol<void(con_channel_e channel, const char* fmt, ...)> Com_Printf{ 0x0, 0x59A2C0 };
|
WEAK symbol<void(con_channel_e channel, const char* fmt, ...)> Com_Printf{ 0x0, 0x59A2C0 };
|
||||||
WEAK symbol<void(con_channel_e a1, const char* Source, int a3)>Com_PrintMessage{ 0x0, 0x59A170 };
|
WEAK symbol<void(con_channel_e a1, const char* Source, int a3)>Com_PrintMessage{ 0x0, 0x59A170 };
|
||||||
WEAK symbol<void(con_channel_e a1, const char* Format, ...)>Com_PrintWarning{ 0x0, 0x59A440 };
|
WEAK symbol<void(con_channel_e a1, const char* Format, ...)>Com_PrintWarning{ 0x0, 0x59A440 };
|
||||||
WEAK symbol<void(con_channel_e a1, const char* Format, ...)>Com_PrintError{ 0x0, 0x59A380 };
|
WEAK symbol<void(con_channel_e a1, const char* Format, ...)>Com_PrintError{ 0x0, 0x59A380 };
|
||||||
WEAK symbol<void(errorParm_t a1, const char* Format, ...)>Com_Error{ 0x0, 0x59AC50 };
|
WEAK symbol<void(errorParm_t a1, const char* Format, ...)>Com_Error{ 0x0, 0x59AC50 };
|
||||||
WEAK symbol<void(const char* Format, ...)>Sys_Error{ 0x0, 0x5FE8C0 };
|
WEAK symbol<void(const char* Format, ...)>Sys_Error{ 0x0, 0x5FE8C0 };
|
||||||
|
|
||||||
WEAK symbol<void(HunkUser *user)>Hunk_UserDestroy{ 0x0, 0x5E4940 };
|
WEAK symbol<void(HunkUser *user)>Hunk_UserDestroy{ 0x0, 0x5E4940 };
|
||||||
WEAK symbol<void *(HunkUser *user, int size, int alignment)> Hunk_UserAlloc{ 0x0, 0x5E47B0 };
|
WEAK symbol<void *(HunkUser *user, int size, int alignment)> Hunk_UserAlloc{ 0x0, 0x5E47B0 };
|
||||||
WEAK symbol<void()> Hunk_ClearTempMemoryHigh{ 0x0, 0x5E4300 };
|
WEAK symbol<void()> Hunk_ClearTempMemoryHigh{ 0x0, 0x5E4300 };
|
||||||
|
|
||||||
WEAK symbol<int(const char* filename, int* file)>FS_FOpenFileRead{ 0x0, 0x5DBD20 };
|
WEAK symbol<int(const char* filename, int* file)>FS_FOpenFileRead{ 0x0, 0x5DBD20 };
|
||||||
WEAK symbol<int(char* Buffer, size_t ElementCount, int a3)>FS_Read{ 0x0, 0x5DBDF0 };
|
WEAK symbol<int(char* Buffer, size_t ElementCount, int a3)>FS_Read{ 0x0, 0x5DBDF0 };
|
||||||
WEAK symbol<int(const char* filename, int* file, fsMode_t mode)>FS_FOpenFileByMode{ 0x0, 0x5DB630 };
|
WEAK symbol<int(const char* filename, int* file, fsMode_t mode)>FS_FOpenFileByMode{ 0x0, 0x5DB630 };
|
||||||
|
|
||||||
WEAK symbol<const char*(const char* Format, ...)>va{ 0x0, 0x5F6D80 };
|
WEAK symbol<const char*(const char* Format, ...)>va{ 0x0, 0x5F6D80 };
|
||||||
|
|
||||||
WEAK symbol<parseInfo_t* (const char* ArgList)>Com_BeginParseSession{ 0x0, 0x5F5830 };
|
WEAK symbol<parseInfo_t* (const char* ArgList)>Com_BeginParseSession{ 0x0, 0x5F5830 };
|
||||||
WEAK symbol<void()> Com_EndParseSession{ 0x0, 0x5F5910 };
|
WEAK symbol<void()> Com_EndParseSession{ 0x0, 0x5F5910 };
|
||||||
WEAK symbol<int()> Sys_Milliseconds{ 0x0, 0x603D40 };
|
WEAK symbol<int()> Sys_Milliseconds{ 0x0, 0x603D40 };
|
||||||
|
|
||||||
WEAK symbol<void(char* Destination, const char* Source, size_t Count)>I_strncpyz{ 0x0, 0x7AA9C0 };
|
WEAK symbol<void(char* Destination, const char* Source, size_t Count)>I_strncpyz{ 0x0, 0x7AA9C0 };
|
||||||
|
|
||||||
inline void* I_strncmp_ADDR() { return CALL_ADDR(0x0, 0x5F6A40); }
|
inline void* I_strncmp_ADDR() { return CALL_ADDR(0x0, 0x5F6A40); }
|
||||||
int I_strncmp(const char* str1, const char* str2, int len, void* call_addr = I_strncmp_ADDR());
|
int I_strncmp(const char* str1, const char* str2, int len, void* call_addr = I_strncmp_ADDR());
|
||||||
|
|
||||||
inline void* Hunk_UserCreate_ADDR() { return CALL_ADDR(0x0, 0x5E46E0); }
|
inline void* Hunk_UserCreate_ADDR() { return CALL_ADDR(0x0, 0x5E46E0); }
|
||||||
HunkUser* Hunk_UserCreate(signed int maxSize, const char* name, int fixed, int tempMem, int debugMem, int type, void* call_addr = Hunk_UserCreate_ADDR());
|
HunkUser* Hunk_UserCreate(signed int maxSize, const char* name, int fixed, int tempMem, int debugMem, int type, void* call_addr = Hunk_UserCreate_ADDR());
|
||||||
inline void* Hunk_AllocateTempMemoryHigh_ADDR() { return CALL_ADDR(0x0, 0x5E4220); }
|
inline void* Hunk_AllocateTempMemoryHigh_ADDR() { return CALL_ADDR(0x0, 0x5E4220); }
|
||||||
unsigned int Hunk_AllocateTempMemoryHigh(int size_, void* call_addr = Hunk_AllocateTempMemoryHigh_ADDR());
|
unsigned int Hunk_AllocateTempMemoryHigh(int size_, void* call_addr = Hunk_AllocateTempMemoryHigh_ADDR());
|
||||||
|
|
||||||
inline void* FS_FCloseFile_ADDR() { return CALL_ADDR(0x0, 0x5DB060); }
|
inline void* FS_FCloseFile_ADDR() { return CALL_ADDR(0x0, 0x5DB060); }
|
||||||
void FS_FCloseFile(int h, void* call_addr = FS_FCloseFile_ADDR());
|
void FS_FCloseFile(int h, void* call_addr = FS_FCloseFile_ADDR());
|
||||||
inline void* FS_ListFilteredFiles_ADDR() { return CALL_ADDR(0x0, 0x5DC720); }
|
inline void* FS_ListFilteredFiles_ADDR() { return CALL_ADDR(0x0, 0x5DC720); }
|
||||||
const char** FS_ListFilteredFiles(searchpath_s* searchPath, const char* path, const char* extension, const char* filter, FsListBehavior_e behavior, int* numFiles, void* call_addr = FS_ListFilteredFiles_ADDR());
|
const char** FS_ListFilteredFiles(searchpath_s* searchPath, const char* path, const char* extension, const char* filter, FsListBehavior_e behavior, int* numFiles, void* call_addr = FS_ListFilteredFiles_ADDR());
|
||||||
|
|
||||||
inline void* Z_TryVirtualAlloc_ADDR() { return CALL_ADDR(0x0, 0x5E39D0); }
|
inline void* Z_TryVirtualAlloc_ADDR() { return CALL_ADDR(0x0, 0x5E39D0); }
|
||||||
void* Z_TryVirtualAlloc(signed int size_, void* call_addr = Z_TryVirtualAlloc_ADDR());
|
void* Z_TryVirtualAlloc(signed int size_, void* call_addr = Z_TryVirtualAlloc_ADDR());
|
||||||
inline void* I_stricmp_ADDR() { return CALL_ADDR(0x0, 0x5F69E0); }
|
inline void* I_stricmp_ADDR() { return CALL_ADDR(0x0, 0x5F69E0); }
|
||||||
int I_stricmp(int len, const char* s0, const char* s1, void* call_addr = I_stricmp_ADDR());
|
int I_stricmp(int len, const char* s0, const char* s1, void* call_addr = I_stricmp_ADDR());
|
||||||
|
|
||||||
inline void* Com_Parse_ADDR() { return CALL_ADDR(0x0, 0x5F61B0); }
|
inline void* Com_Parse_ADDR() { return CALL_ADDR(0x0, 0x5F61B0); }
|
||||||
parseInfo_t* Com_Parse(const char** buffer, void* call_addr = Com_Parse_ADDR());
|
parseInfo_t* Com_Parse(const char** buffer, void* call_addr = Com_Parse_ADDR());
|
||||||
|
|
||||||
inline void* Dvar_RegisterBool_ADDR() { return CALL_ADDR(0x0, 0x5EEE20); }
|
inline void* Dvar_RegisterBool_ADDR() { return CALL_ADDR(0x0, 0x5EEE20); }
|
||||||
dvar_s * Dvar_RegisterBool(unsigned __int8 val, const char * name, int flags, const char * desc, void* call_addr = Dvar_RegisterBool_ADDR());
|
dvar_s * Dvar_RegisterBool(unsigned __int8 val, const char * name, int flags, const char * desc, void* call_addr = Dvar_RegisterBool_ADDR());
|
||||||
|
|
||||||
inline void* XAnimGetAnimDebugName_ADDR() { return CALL_ADDR(0x0, 0x60F850); }
|
inline void* XAnimGetAnimDebugName_ADDR() { return CALL_ADDR(0x0, 0x60F850); }
|
||||||
const char * XAnimGetAnimDebugName(unsigned int animIndex, XAnim_s * anims, void* call_addr = XAnimGetAnimDebugName_ADDR());
|
const char * XAnimGetAnimDebugName(unsigned int animIndex, XAnim_s * anims, void* call_addr = XAnimGetAnimDebugName_ADDR());
|
||||||
|
|
||||||
void Sys_EnterCriticalSection(CriticalSection critSect);
|
void Sys_EnterCriticalSection(CriticalSection critSect);
|
||||||
void Sys_LeaveCriticalSection(CriticalSection critSect);
|
void Sys_LeaveCriticalSection(CriticalSection critSect);
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
WEAK symbol<CRITICAL_SECTION> s_criticalSection{ 0x0, 0x2298D08 };
|
WEAK symbol<CRITICAL_SECTION> s_criticalSection{ 0x0, 0x2298D08 };
|
||||||
WEAK symbol<HunkUser*> g_DebugHunkUser{ 0x0, 0x212B2EC };
|
WEAK symbol<HunkUser*> g_DebugHunkUser{ 0x0, 0x212B2EC };
|
||||||
WEAK symbol<dvar_s*> useFastFile{ 0x0, 0x1F552FC };
|
WEAK symbol<dvar_s*> useFastFile{ 0x0, 0x1F552FC };
|
||||||
WEAK symbol<fileHandleData_t> fsh{ 0x0, 0x2126E20 };
|
WEAK symbol<fileHandleData_t> fsh{ 0x0, 0x2126E20 };
|
||||||
WEAK symbol<dvar_s*> fs_game{ 0x0, 0x2122B00 };
|
WEAK symbol<dvar_s*> fs_game{ 0x0, 0x2122B00 };
|
||||||
WEAK symbol<dvar_s*> com_developer{ 0x0, 0x1F55288 };
|
WEAK symbol<dvar_s*> com_developer{ 0x0, 0x1F55288 };
|
||||||
WEAK symbol<int> statmon_related_bool{ 0x0, 0x2122B04 };
|
WEAK symbol<int> statmon_related_bool{ 0x0, 0x2122B04 };
|
||||||
WEAK symbol<HunkUser*> g_allocNodeUser{ 0x0, 0x3882B20 };
|
WEAK symbol<HunkUser*> g_allocNodeUser{ 0x0, 0x3882B20 };
|
||||||
WEAK symbol<struct HunkUser *> g_user{ 0x0, 0x3882B48 };
|
WEAK symbol<struct HunkUser *> g_user{ 0x0, 0x3882B48 };
|
||||||
WEAK symbol<searchpath_s*> fs_searchpaths{ 0x0, 0x46E5044 };
|
WEAK symbol<searchpath_s*> fs_searchpaths{ 0x0, 0x46E5044 };
|
||||||
|
|
||||||
namespace plutonium
|
namespace plutonium
|
||||||
{
|
{
|
||||||
WEAK symbol<int(const char* fmt, ...)> printf{0x0, 0x0};
|
WEAK symbol<int(const char* fmt, ...)> printf{0x0, 0x0};
|
||||||
|
|
||||||
WEAK symbol<void(scriptInstance_t)> load_custom_script_func{0x0, 0x0};
|
WEAK symbol<void(scriptInstance_t)> load_custom_script_func{0x0, 0x0};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,35 +1,35 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
class component_interface
|
class component_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~component_interface()
|
virtual ~component_interface()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void post_start()
|
virtual void post_start()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void post_load()
|
virtual void post_load()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void pre_destroy()
|
virtual void pre_destroy()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void post_unpack()
|
virtual void post_unpack()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* load_import([[maybe_unused]] const std::string& library, [[maybe_unused]] const std::string& function)
|
virtual void* load_import([[maybe_unused]] const std::string& library, [[maybe_unused]] const std::string& function)
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool is_supported()
|
virtual bool is_supported()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,110 +1,110 @@
|
|||||||
#include <stdinc.hpp>
|
#include <stdinc.hpp>
|
||||||
#include "component_loader.hpp"
|
#include "component_loader.hpp"
|
||||||
|
|
||||||
void component_loader::register_component(std::unique_ptr<component_interface>&& component_)
|
void component_loader::register_component(std::unique_ptr<component_interface>&& component_)
|
||||||
{
|
{
|
||||||
get_components().push_back(std::move(component_));
|
get_components().push_back(std::move(component_));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool component_loader::post_start()
|
bool component_loader::post_start()
|
||||||
{
|
{
|
||||||
static auto handled = false;
|
static auto handled = false;
|
||||||
|
|
||||||
if (handled) return true;
|
if (handled) return true;
|
||||||
handled = true;
|
handled = true;
|
||||||
|
|
||||||
for (const auto& component_ : get_components())
|
for (const auto& component_ : get_components())
|
||||||
{
|
{
|
||||||
component_->post_start();
|
component_->post_start();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool component_loader::post_load()
|
bool component_loader::post_load()
|
||||||
{
|
{
|
||||||
static auto handled = false;
|
static auto handled = false;
|
||||||
if (handled) return true;
|
if (handled) return true;
|
||||||
handled = true;
|
handled = true;
|
||||||
|
|
||||||
clean();
|
clean();
|
||||||
|
|
||||||
for (const auto& component_ : get_components())
|
for (const auto& component_ : get_components())
|
||||||
{
|
{
|
||||||
component_->post_load();
|
component_->post_load();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void component_loader::post_unpack()
|
void component_loader::post_unpack()
|
||||||
{
|
{
|
||||||
static auto handled = false;
|
static auto handled = false;
|
||||||
if (handled) return;
|
if (handled) return;
|
||||||
handled = true;
|
handled = true;
|
||||||
|
|
||||||
for (const auto& component_ : get_components())
|
for (const auto& component_ : get_components())
|
||||||
{
|
{
|
||||||
component_->post_unpack();
|
component_->post_unpack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void component_loader::pre_destroy()
|
void component_loader::pre_destroy()
|
||||||
{
|
{
|
||||||
static auto handled = false;
|
static auto handled = false;
|
||||||
if (handled) return;
|
if (handled) return;
|
||||||
handled = true;
|
handled = true;
|
||||||
|
|
||||||
for (const auto& component_ : get_components())
|
for (const auto& component_ : get_components())
|
||||||
{
|
{
|
||||||
component_->pre_destroy();
|
component_->pre_destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void component_loader::clean()
|
void component_loader::clean()
|
||||||
{
|
{
|
||||||
auto& components = get_components();
|
auto& components = get_components();
|
||||||
for (auto i = components.begin(); i != components.end();)
|
for (auto i = components.begin(); i != components.end();)
|
||||||
{
|
{
|
||||||
if (!(*i)->is_supported())
|
if (!(*i)->is_supported())
|
||||||
{
|
{
|
||||||
(*i)->pre_destroy();
|
(*i)->pre_destroy();
|
||||||
i = components.erase(i);
|
i = components.erase(i);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void* component_loader::load_import(const std::string& library, const std::string& function)
|
void* component_loader::load_import(const std::string& library, const std::string& function)
|
||||||
{
|
{
|
||||||
void* function_ptr = nullptr;
|
void* function_ptr = nullptr;
|
||||||
|
|
||||||
for (const auto& component_ : get_components())
|
for (const auto& component_ : get_components())
|
||||||
{
|
{
|
||||||
auto* const component_function_ptr = component_->load_import(library, function);
|
auto* const component_function_ptr = component_->load_import(library, function);
|
||||||
if (component_function_ptr)
|
if (component_function_ptr)
|
||||||
{
|
{
|
||||||
function_ptr = component_function_ptr;
|
function_ptr = component_function_ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return function_ptr;
|
return function_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::unique_ptr<component_interface>>& component_loader::get_components()
|
std::vector<std::unique_ptr<component_interface>>& component_loader::get_components()
|
||||||
{
|
{
|
||||||
using component_vector = std::vector<std::unique_ptr<component_interface>>;
|
using component_vector = std::vector<std::unique_ptr<component_interface>>;
|
||||||
using component_vector_container = std::unique_ptr<component_vector, std::function<void(component_vector*)>>;
|
using component_vector_container = std::unique_ptr<component_vector, std::function<void(component_vector*)>>;
|
||||||
|
|
||||||
static component_vector_container components(new component_vector, [](component_vector* component_vector)
|
static component_vector_container components(new component_vector, [](component_vector* component_vector)
|
||||||
{
|
{
|
||||||
pre_destroy();
|
pre_destroy();
|
||||||
delete component_vector;
|
delete component_vector;
|
||||||
});
|
});
|
||||||
|
|
||||||
return *components;
|
return *components;
|
||||||
}
|
}
|
||||||
|
@ -1,51 +1,51 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "component_interface.hpp"
|
#include "component_interface.hpp"
|
||||||
|
|
||||||
class component_loader final
|
class component_loader final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class installer final
|
class installer final
|
||||||
{
|
{
|
||||||
static_assert(std::is_base_of<component_interface, T>::value, "component has invalid base class");
|
static_assert(std::is_base_of<component_interface, T>::value, "component has invalid base class");
|
||||||
|
|
||||||
public:
|
public:
|
||||||
installer()
|
installer()
|
||||||
{
|
{
|
||||||
register_component(std::make_unique<T>());
|
register_component(std::make_unique<T>());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static T* get()
|
static T* get()
|
||||||
{
|
{
|
||||||
for (const auto& component_ : get_components())
|
for (const auto& component_ : get_components())
|
||||||
{
|
{
|
||||||
if (typeid(*component_.get()) == typeid(T))
|
if (typeid(*component_.get()) == typeid(T))
|
||||||
{
|
{
|
||||||
return reinterpret_cast<T*>(component_.get());
|
return reinterpret_cast<T*>(component_.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void register_component(std::unique_ptr<component_interface>&& component);
|
static void register_component(std::unique_ptr<component_interface>&& component);
|
||||||
|
|
||||||
static bool post_start();
|
static bool post_start();
|
||||||
static bool post_load();
|
static bool post_load();
|
||||||
static void post_unpack();
|
static void post_unpack();
|
||||||
static void pre_destroy();
|
static void pre_destroy();
|
||||||
static void clean();
|
static void clean();
|
||||||
|
|
||||||
static void* load_import(const std::string& library, const std::string& function);
|
static void* load_import(const std::string& library, const std::string& function);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::vector<std::unique_ptr<component_interface>>& get_components();
|
static std::vector<std::unique_ptr<component_interface>>& get_components();
|
||||||
};
|
};
|
||||||
|
|
||||||
#define REGISTER_COMPONENT(name) \
|
#define REGISTER_COMPONENT(name) \
|
||||||
namespace \
|
namespace \
|
||||||
{ \
|
{ \
|
||||||
static component_loader::installer<name> __component; \
|
static component_loader::installer<name> __component; \
|
||||||
}
|
}
|
||||||
|
142
src/stdinc.hpp
142
src/stdinc.hpp
@ -1,72 +1,72 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#pragma warning(disable: 6011)
|
#pragma warning(disable: 6011)
|
||||||
#pragma warning(disable: 6054)
|
#pragma warning(disable: 6054)
|
||||||
#pragma warning(disable: 6387)
|
#pragma warning(disable: 6387)
|
||||||
#pragma warning(disable: 26451)
|
#pragma warning(disable: 26451)
|
||||||
#pragma warning(disable: 26812)
|
#pragma warning(disable: 26812)
|
||||||
#pragma warning(disable: 28182)
|
#pragma warning(disable: 28182)
|
||||||
|
|
||||||
#pragma warning(disable: 4324)
|
#pragma warning(disable: 4324)
|
||||||
#pragma warning(disable: 4459)
|
#pragma warning(disable: 4459)
|
||||||
#pragma warning(disable: 4611)
|
#pragma warning(disable: 4611)
|
||||||
#pragma warning(error: 4409)
|
#pragma warning(error: 4409)
|
||||||
|
|
||||||
#define DLL_EXPORT extern "C" __declspec(dllexport)
|
#define DLL_EXPORT extern "C" __declspec(dllexport)
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <csetjmp>
|
#include <csetjmp>
|
||||||
#include <atlcomcli.h>
|
#include <atlcomcli.h>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <Psapi.h>
|
#include <Psapi.h>
|
||||||
#include <timeapi.h>
|
#include <timeapi.h>
|
||||||
|
|
||||||
#ifdef max
|
#ifdef max
|
||||||
#undef max
|
#undef max
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef min
|
#ifdef min
|
||||||
#undef min
|
#undef min
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <MinHook.h>
|
#include <MinHook.h>
|
||||||
#include <gsl/gsl>
|
#include <gsl/gsl>
|
||||||
|
|
||||||
#include <json.hpp>
|
#include <json.hpp>
|
||||||
|
|
||||||
#include <asmjit/core/jitruntime.h>
|
#include <asmjit/core/jitruntime.h>
|
||||||
#include <asmjit/x86/x86assembler.h>
|
#include <asmjit/x86/x86assembler.h>
|
||||||
|
|
||||||
#pragma comment(lib, "ntdll.lib")
|
#pragma comment(lib, "ntdll.lib")
|
||||||
#pragma comment(lib, "ws2_32.lib")
|
#pragma comment(lib, "ws2_32.lib")
|
||||||
#pragma comment(lib, "urlmon.lib" )
|
#pragma comment(lib, "urlmon.lib" )
|
||||||
#pragma comment(lib, "iphlpapi.lib")
|
#pragma comment(lib, "iphlpapi.lib")
|
||||||
#pragma comment(lib, "Crypt32.lib")
|
#pragma comment(lib, "Crypt32.lib")
|
||||||
#pragma comment(lib, "Winmm.lib")
|
#pragma comment(lib, "Winmm.lib")
|
||||||
|
|
||||||
#include "utils/hexrays_defs.h"
|
#include "utils/hexrays_defs.h"
|
||||||
|
|
||||||
#undef GetObject
|
#undef GetObject
|
||||||
|
|
||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
#include "game/enums.hpp"
|
#include "game/enums.hpp"
|
||||||
#include "game/structs.hpp"
|
#include "game/structs.hpp"
|
||||||
#include "game/symbols.hpp"
|
#include "game/symbols.hpp"
|
||||||
|
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
@ -1,170 +1,170 @@
|
|||||||
#include <stdinc.hpp>
|
#include <stdinc.hpp>
|
||||||
#include "memory.hpp"
|
#include "memory.hpp"
|
||||||
#include "compression.hpp"
|
#include "compression.hpp"
|
||||||
|
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include <zip.h>
|
#include <zip.h>
|
||||||
|
|
||||||
#include <gsl/gsl>
|
#include <gsl/gsl>
|
||||||
|
|
||||||
#include "io.hpp"
|
#include "io.hpp"
|
||||||
|
|
||||||
namespace utils::compression
|
namespace utils::compression
|
||||||
{
|
{
|
||||||
namespace zlib
|
namespace zlib
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
class zlib_stream
|
class zlib_stream
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
zlib_stream()
|
zlib_stream()
|
||||||
{
|
{
|
||||||
memset(&stream_, 0, sizeof(stream_));
|
memset(&stream_, 0, sizeof(stream_));
|
||||||
valid_ = inflateInit(&stream_) == Z_OK;
|
valid_ = inflateInit(&stream_) == Z_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
zlib_stream(zlib_stream&&) = delete;
|
zlib_stream(zlib_stream&&) = delete;
|
||||||
zlib_stream(const zlib_stream&) = delete;
|
zlib_stream(const zlib_stream&) = delete;
|
||||||
zlib_stream& operator=(zlib_stream&&) = delete;
|
zlib_stream& operator=(zlib_stream&&) = delete;
|
||||||
zlib_stream& operator=(const zlib_stream&) = delete;
|
zlib_stream& operator=(const zlib_stream&) = delete;
|
||||||
|
|
||||||
~zlib_stream()
|
~zlib_stream()
|
||||||
{
|
{
|
||||||
if (valid_)
|
if (valid_)
|
||||||
{
|
{
|
||||||
inflateEnd(&stream_);
|
inflateEnd(&stream_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
z_stream& get()
|
z_stream& get()
|
||||||
{
|
{
|
||||||
return stream_; //
|
return stream_; //
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_valid() const
|
bool is_valid() const
|
||||||
{
|
{
|
||||||
return valid_;
|
return valid_;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool valid_{false};
|
bool valid_{false};
|
||||||
z_stream stream_{};
|
z_stream stream_{};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string decompress(const std::string& data)
|
std::string decompress(const std::string& data)
|
||||||
{
|
{
|
||||||
std::string buffer{};
|
std::string buffer{};
|
||||||
zlib_stream stream_container{};
|
zlib_stream stream_container{};
|
||||||
if (!stream_container.is_valid())
|
if (!stream_container.is_valid())
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret{};
|
int ret{};
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
static thread_local uint8_t dest[CHUNK] = {0};
|
static thread_local uint8_t dest[CHUNK] = {0};
|
||||||
auto& stream = stream_container.get();
|
auto& stream = stream_container.get();
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
const auto input_size = std::min(sizeof(dest), data.size() - offset);
|
const auto input_size = std::min(sizeof(dest), data.size() - offset);
|
||||||
stream.avail_in = static_cast<uInt>(input_size);
|
stream.avail_in = static_cast<uInt>(input_size);
|
||||||
stream.next_in = reinterpret_cast<const Bytef*>(data.data()) + offset;
|
stream.next_in = reinterpret_cast<const Bytef*>(data.data()) + offset;
|
||||||
offset += stream.avail_in;
|
offset += stream.avail_in;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
stream.avail_out = sizeof(dest);
|
stream.avail_out = sizeof(dest);
|
||||||
stream.next_out = dest;
|
stream.next_out = dest;
|
||||||
|
|
||||||
ret = inflate(&stream, Z_NO_FLUSH);
|
ret = inflate(&stream, Z_NO_FLUSH);
|
||||||
if (ret != Z_OK && ret != Z_STREAM_END)
|
if (ret != Z_OK && ret != Z_STREAM_END)
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.insert(buffer.end(), dest, dest + sizeof(dest) - stream.avail_out);
|
buffer.insert(buffer.end(), dest, dest + sizeof(dest) - stream.avail_out);
|
||||||
}
|
}
|
||||||
while (stream.avail_out == 0);
|
while (stream.avail_out == 0);
|
||||||
}
|
}
|
||||||
while (ret != Z_STREAM_END);
|
while (ret != Z_STREAM_END);
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string compress(const std::string& data)
|
std::string compress(const std::string& data)
|
||||||
{
|
{
|
||||||
std::string result{};
|
std::string result{};
|
||||||
auto length = compressBound(static_cast<uLong>(data.size()));
|
auto length = compressBound(static_cast<uLong>(data.size()));
|
||||||
result.resize(length);
|
result.resize(length);
|
||||||
|
|
||||||
if (compress2(reinterpret_cast<Bytef*>(result.data()), &length,
|
if (compress2(reinterpret_cast<Bytef*>(result.data()), &length,
|
||||||
reinterpret_cast<const Bytef*>(data.data()), static_cast<uLong>(data.size()),
|
reinterpret_cast<const Bytef*>(data.data()), static_cast<uLong>(data.size()),
|
||||||
Z_BEST_COMPRESSION) != Z_OK)
|
Z_BEST_COMPRESSION) != Z_OK)
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
result.resize(length);
|
result.resize(length);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace zip
|
namespace zip
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
bool add_file(zipFile& zip_file, const std::string& filename, const std::string& data)
|
bool add_file(zipFile& zip_file, const std::string& filename, const std::string& data)
|
||||||
{
|
{
|
||||||
const auto zip_64 = data.size() > 0xffffffff ? 1 : 0;
|
const auto zip_64 = data.size() > 0xffffffff ? 1 : 0;
|
||||||
if (ZIP_OK != zipOpenNewFileInZip64(zip_file, filename.data(), nullptr, nullptr, 0, nullptr, 0, nullptr,
|
if (ZIP_OK != zipOpenNewFileInZip64(zip_file, filename.data(), nullptr, nullptr, 0, nullptr, 0, nullptr,
|
||||||
Z_DEFLATED, Z_BEST_COMPRESSION, zip_64))
|
Z_DEFLATED, Z_BEST_COMPRESSION, zip_64))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto _ = gsl::finally([&zip_file]()
|
const auto _ = gsl::finally([&zip_file]()
|
||||||
{
|
{
|
||||||
zipCloseFileInZip(zip_file);
|
zipCloseFileInZip(zip_file);
|
||||||
});
|
});
|
||||||
|
|
||||||
return ZIP_OK == zipWriteInFileInZip(zip_file, data.data(), static_cast<unsigned>(data.size()));
|
return ZIP_OK == zipWriteInFileInZip(zip_file, data.data(), static_cast<unsigned>(data.size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void archive::add(std::string filename, std::string data)
|
void archive::add(std::string filename, std::string data)
|
||||||
{
|
{
|
||||||
this->files_[std::move(filename)] = std::move(data);
|
this->files_[std::move(filename)] = std::move(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool archive::write(const std::string& filename, const std::string& comment)
|
bool archive::write(const std::string& filename, const std::string& comment)
|
||||||
{
|
{
|
||||||
// Hack to create the directory :3
|
// Hack to create the directory :3
|
||||||
io::write_file(filename, {});
|
io::write_file(filename, {});
|
||||||
io::remove_file(filename);
|
io::remove_file(filename);
|
||||||
|
|
||||||
auto* zip_file = zipOpen64(filename.data(), 0);
|
auto* zip_file = zipOpen64(filename.data(), 0);
|
||||||
if (!zip_file)
|
if (!zip_file)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto _ = gsl::finally([&zip_file, &comment]()
|
const auto _ = gsl::finally([&zip_file, &comment]()
|
||||||
{
|
{
|
||||||
zipClose(zip_file, comment.empty() ? nullptr : comment.data());
|
zipClose(zip_file, comment.empty() ? nullptr : comment.data());
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const auto& file : this->files_)
|
for (const auto& file : this->files_)
|
||||||
{
|
{
|
||||||
if (!add_file(zip_file, file.first, file.second))
|
if (!add_file(zip_file, file.first, file.second))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,28 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#define CHUNK 16384u
|
#define CHUNK 16384u
|
||||||
|
|
||||||
namespace utils::compression
|
namespace utils::compression
|
||||||
{
|
{
|
||||||
namespace zlib
|
namespace zlib
|
||||||
{
|
{
|
||||||
std::string compress(const std::string& data);
|
std::string compress(const std::string& data);
|
||||||
std::string decompress(const std::string& data);
|
std::string decompress(const std::string& data);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace zip
|
namespace zip
|
||||||
{
|
{
|
||||||
class archive
|
class archive
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void add(std::string filename, std::string data);
|
void add(std::string filename, std::string data);
|
||||||
bool write(const std::string& filename, const std::string& comment = {});
|
bool write(const std::string& filename, const std::string& comment = {});
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::string, std::string> files_;
|
std::unordered_map<std::string, std::string> files_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,46 +1,46 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
namespace utils::concurrency
|
namespace utils::concurrency
|
||||||
{
|
{
|
||||||
template <typename T, typename MutexType = std::mutex>
|
template <typename T, typename MutexType = std::mutex>
|
||||||
class container
|
class container
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
template <typename R = void, typename F>
|
template <typename R = void, typename F>
|
||||||
R access(F&& accessor) const
|
R access(F&& accessor) const
|
||||||
{
|
{
|
||||||
std::lock_guard<MutexType> _{mutex_};
|
std::lock_guard<MutexType> _{mutex_};
|
||||||
return accessor(object_);
|
return accessor(object_);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename R = void, typename F>
|
template <typename R = void, typename F>
|
||||||
R access(F&& accessor)
|
R access(F&& accessor)
|
||||||
{
|
{
|
||||||
std::lock_guard<MutexType> _{mutex_};
|
std::lock_guard<MutexType> _{mutex_};
|
||||||
return accessor(object_);
|
return accessor(object_);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename R = void, typename F>
|
template <typename R = void, typename F>
|
||||||
R access_with_lock(F&& accessor) const
|
R access_with_lock(F&& accessor) const
|
||||||
{
|
{
|
||||||
std::unique_lock<MutexType> lock{mutex_};
|
std::unique_lock<MutexType> lock{mutex_};
|
||||||
return accessor(object_, lock);
|
return accessor(object_, lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename R = void, typename F>
|
template <typename R = void, typename F>
|
||||||
R access_with_lock(F&& accessor)
|
R access_with_lock(F&& accessor)
|
||||||
{
|
{
|
||||||
std::unique_lock<MutexType> lock{mutex_};
|
std::unique_lock<MutexType> lock{mutex_};
|
||||||
return accessor(object_, lock);
|
return accessor(object_, lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
T& get_raw() { return object_; }
|
T& get_raw() { return object_; }
|
||||||
const T& get_raw() const { return object_; }
|
const T& get_raw() const { return object_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable MutexType mutex_{};
|
mutable MutexType mutex_{};
|
||||||
T object_{};
|
T object_{};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,54 +1,54 @@
|
|||||||
#include <stdinc.hpp>
|
#include <stdinc.hpp>
|
||||||
|
|
||||||
#include "flags.hpp"
|
#include "flags.hpp"
|
||||||
#include "string.hpp"
|
#include "string.hpp"
|
||||||
|
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
|
|
||||||
namespace utils::flags
|
namespace utils::flags
|
||||||
{
|
{
|
||||||
void parse_flags(std::vector<std::string>& flags)
|
void parse_flags(std::vector<std::string>& flags)
|
||||||
{
|
{
|
||||||
int num_args;
|
int num_args;
|
||||||
auto* const argv = CommandLineToArgvW(GetCommandLineW(), &num_args);
|
auto* const argv = CommandLineToArgvW(GetCommandLineW(), &num_args);
|
||||||
|
|
||||||
flags.clear();
|
flags.clear();
|
||||||
|
|
||||||
if (argv)
|
if (argv)
|
||||||
{
|
{
|
||||||
for (auto i = 0; i < num_args; ++i)
|
for (auto i = 0; i < num_args; ++i)
|
||||||
{
|
{
|
||||||
std::wstring wide_flag(argv[i]);
|
std::wstring wide_flag(argv[i]);
|
||||||
if (wide_flag[0] == L'-')
|
if (wide_flag[0] == L'-')
|
||||||
{
|
{
|
||||||
wide_flag.erase(wide_flag.begin());
|
wide_flag.erase(wide_flag.begin());
|
||||||
flags.emplace_back(string::convert(wide_flag));
|
flags.emplace_back(string::convert(wide_flag));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalFree(argv);
|
LocalFree(argv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_flag(const std::string& flag)
|
bool has_flag(const std::string& flag)
|
||||||
{
|
{
|
||||||
static auto parsed = false;
|
static auto parsed = false;
|
||||||
static std::vector<std::string> enabled_flags;
|
static std::vector<std::string> enabled_flags;
|
||||||
|
|
||||||
if (!parsed)
|
if (!parsed)
|
||||||
{
|
{
|
||||||
parse_flags(enabled_flags);
|
parse_flags(enabled_flags);
|
||||||
parsed = true;
|
parsed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& entry : enabled_flags)
|
for (const auto& entry : enabled_flags)
|
||||||
{
|
{
|
||||||
if (string::to_lower(entry) == string::to_lower(flag))
|
if (string::to_lower(entry) == string::to_lower(flag))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace utils::flags
|
namespace utils::flags
|
||||||
{
|
{
|
||||||
bool has_flag(const std::string& flag);
|
bool has_flag(const std::string& flag);
|
||||||
}
|
}
|
||||||
|
@ -10,26 +10,26 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
typedef long long ll;
|
typedef long long ll;
|
||||||
typedef unsigned long long ull;
|
typedef unsigned long long ull;
|
||||||
#define __int64 long long
|
#define __int64 long long
|
||||||
#define __int32 int
|
#define __int32 int
|
||||||
#define __int16 short
|
#define __int16 short
|
||||||
#define __int8 char
|
#define __int8 char
|
||||||
#define MAKELL(num) num ## LL
|
#define MAKELL(num) num ## LL
|
||||||
#define FMT_64 "ll"
|
#define FMT_64 "ll"
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
typedef __int64 ll;
|
typedef __int64 ll;
|
||||||
typedef unsigned __int64 ull;
|
typedef unsigned __int64 ull;
|
||||||
#define MAKELL(num) num ## i64
|
#define MAKELL(num) num ## i64
|
||||||
#define FMT_64 "I64"
|
#define FMT_64 "I64"
|
||||||
#elif defined (__BORLANDC__)
|
#elif defined (__BORLANDC__)
|
||||||
typedef __int64 ll;
|
typedef __int64 ll;
|
||||||
typedef unsigned __int64 ull;
|
typedef unsigned __int64 ull;
|
||||||
#define MAKELL(num) num ## i64
|
#define MAKELL(num) num ## i64
|
||||||
#define FMT_64 "L"
|
#define FMT_64 "L"
|
||||||
#else
|
#else
|
||||||
#error "unknown compiler"
|
#error "unknown compiler"
|
||||||
#endif
|
#endif
|
||||||
typedef unsigned int uint;
|
typedef unsigned int uint;
|
||||||
typedef unsigned char uchar;
|
typedef unsigned char uchar;
|
||||||
@ -152,9 +152,9 @@ typedef int bool; // we want to use bool in our C programs
|
|||||||
// Fill memory block with an integer value
|
// Fill memory block with an integer value
|
||||||
inline void memset32(void *ptr, uint32 value, int count)
|
inline void memset32(void *ptr, uint32 value, int count)
|
||||||
{
|
{
|
||||||
uint32 *p = (uint32 *)ptr;
|
uint32 *p = (uint32 *)ptr;
|
||||||
for ( int i=0; i < count; i++ )
|
for ( int i=0; i < count; i++ )
|
||||||
*p++ = value;
|
*p++ = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a reference to pair of operands
|
// Generate a reference to pair of operands
|
||||||
@ -168,112 +168,112 @@ template<class T> uint64 __PAIR__(uint32 high, T low) { return (((uint64)high) <
|
|||||||
// rotate left
|
// rotate left
|
||||||
template<class T> T __ROL__(T value, uint count)
|
template<class T> T __ROL__(T value, uint count)
|
||||||
{
|
{
|
||||||
const uint nbits = sizeof(T) * 8;
|
const uint nbits = sizeof(T) * 8;
|
||||||
count %= nbits;
|
count %= nbits;
|
||||||
|
|
||||||
T high = value >> (nbits - count);
|
T high = value >> (nbits - count);
|
||||||
value <<= count;
|
value <<= count;
|
||||||
value |= high;
|
value |= high;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// rotate right
|
// rotate right
|
||||||
template<class T> T __ROR__(T value, uint count)
|
template<class T> T __ROR__(T value, uint count)
|
||||||
{
|
{
|
||||||
const uint nbits = sizeof(T) * 8;
|
const uint nbits = sizeof(T) * 8;
|
||||||
count %= nbits;
|
count %= nbits;
|
||||||
|
|
||||||
T low = value << (nbits - count);
|
T low = value << (nbits - count);
|
||||||
value >>= count;
|
value >>= count;
|
||||||
value |= low;
|
value |= low;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// carry flag of left shift
|
// carry flag of left shift
|
||||||
template<class T> int8 __MKCSHL__(T value, uint count)
|
template<class T> int8 __MKCSHL__(T value, uint count)
|
||||||
{
|
{
|
||||||
const uint nbits = sizeof(T) * 8;
|
const uint nbits = sizeof(T) * 8;
|
||||||
count %= nbits;
|
count %= nbits;
|
||||||
|
|
||||||
return (value >> (nbits-count)) & 1;
|
return (value >> (nbits-count)) & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// carry flag of right shift
|
// carry flag of right shift
|
||||||
template<class T> int8 __MKCSHR__(T value, uint count)
|
template<class T> int8 __MKCSHR__(T value, uint count)
|
||||||
{
|
{
|
||||||
return (value >> (count-1)) & 1;
|
return (value >> (count-1)) & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sign flag
|
// sign flag
|
||||||
template<class T> int8 __SETS__(T x)
|
template<class T> int8 __SETS__(T x)
|
||||||
{
|
{
|
||||||
if ( sizeof(T) == 1 )
|
if ( sizeof(T) == 1 )
|
||||||
return int8(x) < 0;
|
return int8(x) < 0;
|
||||||
if ( sizeof(T) == 2 )
|
if ( sizeof(T) == 2 )
|
||||||
return int16(x) < 0;
|
return int16(x) < 0;
|
||||||
if ( sizeof(T) == 4 )
|
if ( sizeof(T) == 4 )
|
||||||
return int32(x) < 0;
|
return int32(x) < 0;
|
||||||
return int64(x) < 0;
|
return int64(x) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// overflow flag of subtraction (x-y)
|
// overflow flag of subtraction (x-y)
|
||||||
template<class T, class U> int8 __OFSUB__(T x, U y)
|
template<class T, class U> int8 __OFSUB__(T x, U y)
|
||||||
{
|
{
|
||||||
if ( sizeof(T) < sizeof(U) )
|
if ( sizeof(T) < sizeof(U) )
|
||||||
{
|
{
|
||||||
U x2 = x;
|
U x2 = x;
|
||||||
int8 sx = __SETS__(x2);
|
int8 sx = __SETS__(x2);
|
||||||
return (sx ^ __SETS__(y)) & (sx ^ __SETS__(x2-y));
|
return (sx ^ __SETS__(y)) & (sx ^ __SETS__(x2-y));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
T y2 = y;
|
T y2 = y;
|
||||||
int8 sx = __SETS__(x);
|
int8 sx = __SETS__(x);
|
||||||
return (sx ^ __SETS__(y2)) & (sx ^ __SETS__(x-y2));
|
return (sx ^ __SETS__(y2)) & (sx ^ __SETS__(x-y2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// overflow flag of addition (x+y)
|
// overflow flag of addition (x+y)
|
||||||
template<class T, class U> int8 __OFADD__(T x, U y)
|
template<class T, class U> int8 __OFADD__(T x, U y)
|
||||||
{
|
{
|
||||||
if ( sizeof(T) < sizeof(U) )
|
if ( sizeof(T) < sizeof(U) )
|
||||||
{
|
{
|
||||||
U x2 = x;
|
U x2 = x;
|
||||||
int8 sx = __SETS__(x2);
|
int8 sx = __SETS__(x2);
|
||||||
return ((1 ^ sx) ^ __SETS__(y)) & (sx ^ __SETS__(x2+y));
|
return ((1 ^ sx) ^ __SETS__(y)) & (sx ^ __SETS__(x2+y));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
T y2 = y;
|
T y2 = y;
|
||||||
int8 sx = __SETS__(x);
|
int8 sx = __SETS__(x);
|
||||||
return ((1 ^ sx) ^ __SETS__(y2)) & (sx ^ __SETS__(x+y2));
|
return ((1 ^ sx) ^ __SETS__(y2)) & (sx ^ __SETS__(x+y2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// carry flag of subtraction (x-y)
|
// carry flag of subtraction (x-y)
|
||||||
template<class T, class U> int8 __CFSUB__(T x, U y)
|
template<class T, class U> int8 __CFSUB__(T x, U y)
|
||||||
{
|
{
|
||||||
int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U);
|
int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U);
|
||||||
if ( size == 1 )
|
if ( size == 1 )
|
||||||
return uint8(x) < uint8(y);
|
return uint8(x) < uint8(y);
|
||||||
if ( size == 2 )
|
if ( size == 2 )
|
||||||
return uint16(x) < uint16(y);
|
return uint16(x) < uint16(y);
|
||||||
if ( size == 4 )
|
if ( size == 4 )
|
||||||
return uint32(x) < uint32(y);
|
return uint32(x) < uint32(y);
|
||||||
return uint64(x) < uint64(y);
|
return uint64(x) < uint64(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// carry flag of addition (x+y)
|
// carry flag of addition (x+y)
|
||||||
template<class T, class U> int8 __CFADD__(T x, U y)
|
template<class T, class U> int8 __CFADD__(T x, U y)
|
||||||
{
|
{
|
||||||
int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U);
|
int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U);
|
||||||
if ( size == 1 )
|
if ( size == 1 )
|
||||||
return uint8(x) > uint8(x+y);
|
return uint8(x) > uint8(x+y);
|
||||||
if ( size == 2 )
|
if ( size == 2 )
|
||||||
return uint16(x) > uint16(x+y);
|
return uint16(x) > uint16(x+y);
|
||||||
if ( size == 4 )
|
if ( size == 4 )
|
||||||
return uint32(x) > uint32(x+y);
|
return uint32(x) > uint32(x+y);
|
||||||
return uint64(x) > uint64(x+y);
|
return uint64(x) > uint64(x+y);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -1,252 +1,251 @@
|
|||||||
#include <stdinc.hpp>
|
#include <stdinc.hpp>
|
||||||
#include "hook.hpp"
|
#include "hook.hpp"
|
||||||
#include "string.hpp"
|
#include "string.hpp"
|
||||||
// iw6x-client
|
|
||||||
|
namespace utils::hook
|
||||||
namespace utils::hook
|
{
|
||||||
{
|
void signature::process()
|
||||||
void signature::process()
|
{
|
||||||
{
|
if (this->signatures_.empty()) return;
|
||||||
if (this->signatures_.empty()) return;
|
|
||||||
|
const auto start = static_cast<char*>(this->start_);
|
||||||
const auto start = static_cast<char*>(this->start_);
|
|
||||||
|
const unsigned int sig_count = this->signatures_.size();
|
||||||
const unsigned int sig_count = this->signatures_.size();
|
const auto containers = this->signatures_.data();
|
||||||
const auto containers = this->signatures_.data();
|
|
||||||
|
for (size_t i = 0; i < this->length_; ++i)
|
||||||
for (size_t i = 0; i < this->length_; ++i)
|
{
|
||||||
{
|
const auto address = start + i;
|
||||||
const auto address = start + i;
|
|
||||||
|
for (unsigned int k = 0; k < sig_count; ++k)
|
||||||
for (unsigned int k = 0; k < sig_count; ++k)
|
{
|
||||||
{
|
const auto container = &containers[k];
|
||||||
const auto container = &containers[k];
|
|
||||||
|
unsigned int j;
|
||||||
unsigned int j;
|
for (j = 0; j < static_cast<unsigned int>(container->mask.size()); ++j)
|
||||||
for (j = 0; j < static_cast<unsigned int>(container->mask.size()); ++j)
|
{
|
||||||
{
|
if (container->mask[j] != '?' && container->signature[j] != address[j])
|
||||||
if (container->mask[j] != '?' && container->signature[j] != address[j])
|
{
|
||||||
{
|
break;
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (j == container->mask.size())
|
||||||
if (j == container->mask.size())
|
{
|
||||||
{
|
container->callback(address);
|
||||||
container->callback(address);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
void signature::add(const container& container)
|
||||||
void signature::add(const container& container)
|
{
|
||||||
{
|
signatures_.push_back(container);
|
||||||
signatures_.push_back(container);
|
}
|
||||||
}
|
|
||||||
|
namespace
|
||||||
namespace
|
{
|
||||||
{
|
[[maybe_unused]] class _
|
||||||
[[maybe_unused]] class _
|
{
|
||||||
{
|
public:
|
||||||
public:
|
_()
|
||||||
_()
|
{
|
||||||
{
|
if (MH_Initialize() != MH_OK)
|
||||||
if (MH_Initialize() != MH_OK)
|
{
|
||||||
{
|
throw std::runtime_error("Failed to initialize MinHook");
|
||||||
throw std::runtime_error("Failed to initialize MinHook");
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
~_()
|
||||||
~_()
|
{
|
||||||
{
|
MH_Uninitialize();
|
||||||
MH_Uninitialize();
|
}
|
||||||
}
|
} __;
|
||||||
} __;
|
}
|
||||||
}
|
|
||||||
|
asmjit::Error assembler::call(void* target)
|
||||||
asmjit::Error assembler::call(void* target)
|
{
|
||||||
{
|
return Assembler::call(size_t(target));
|
||||||
return Assembler::call(size_t(target));
|
}
|
||||||
}
|
|
||||||
|
asmjit::Error assembler::jmp(void* target)
|
||||||
asmjit::Error assembler::jmp(void* target)
|
{
|
||||||
{
|
return Assembler::jmp(size_t(target));
|
||||||
return Assembler::jmp(size_t(target));
|
}
|
||||||
}
|
|
||||||
|
detour::detour(const size_t place, void* target) : detour(reinterpret_cast<void*>(place), target)
|
||||||
detour::detour(const size_t place, void* target) : detour(reinterpret_cast<void*>(place), target)
|
{
|
||||||
{
|
}
|
||||||
}
|
|
||||||
|
detour::detour(void* place, void* target)
|
||||||
detour::detour(void* place, void* target)
|
{
|
||||||
{
|
this->create(place, target);
|
||||||
this->create(place, target);
|
}
|
||||||
}
|
|
||||||
|
detour::~detour()
|
||||||
detour::~detour()
|
{
|
||||||
{
|
this->clear();
|
||||||
this->clear();
|
}
|
||||||
}
|
|
||||||
|
void detour::enable() const
|
||||||
void detour::enable() const
|
{
|
||||||
{
|
MH_EnableHook(this->place_);
|
||||||
MH_EnableHook(this->place_);
|
}
|
||||||
}
|
|
||||||
|
void detour::disable() const
|
||||||
void detour::disable() const
|
{
|
||||||
{
|
MH_DisableHook(this->place_);
|
||||||
MH_DisableHook(this->place_);
|
}
|
||||||
}
|
|
||||||
|
void detour::create(void* place, void* target)
|
||||||
void detour::create(void* place, void* target)
|
{
|
||||||
{
|
this->clear();
|
||||||
this->clear();
|
this->place_ = place;
|
||||||
this->place_ = place;
|
|
||||||
|
if (MH_CreateHook(this->place_, target, &this->original_) != MH_OK)
|
||||||
if (MH_CreateHook(this->place_, target, &this->original_) != MH_OK)
|
{
|
||||||
{
|
throw std::runtime_error(string::va("Unable to create hook at location: %p", this->place_));
|
||||||
throw std::runtime_error(string::va("Unable to create hook at location: %p", this->place_));
|
}
|
||||||
}
|
|
||||||
|
this->enable();
|
||||||
this->enable();
|
}
|
||||||
}
|
|
||||||
|
void detour::create(const size_t place, void* target)
|
||||||
void detour::create(const size_t place, void* target)
|
{
|
||||||
{
|
this->create(reinterpret_cast<void*>(place), target);
|
||||||
this->create(reinterpret_cast<void*>(place), target);
|
}
|
||||||
}
|
|
||||||
|
void detour::clear()
|
||||||
void detour::clear()
|
{
|
||||||
{
|
if (this->place_)
|
||||||
if (this->place_)
|
{
|
||||||
{
|
MH_RemoveHook(this->place_);
|
||||||
MH_RemoveHook(this->place_);
|
}
|
||||||
}
|
|
||||||
|
this->place_ = nullptr;
|
||||||
this->place_ = nullptr;
|
this->original_ = nullptr;
|
||||||
this->original_ = nullptr;
|
}
|
||||||
}
|
|
||||||
|
void* detour::get_original() const
|
||||||
void* detour::get_original() const
|
{
|
||||||
{
|
return this->original_;
|
||||||
return this->original_;
|
}
|
||||||
}
|
|
||||||
|
void nop(void* place, const size_t length)
|
||||||
void nop(void* place, const size_t length)
|
{
|
||||||
{
|
DWORD old_protect{};
|
||||||
DWORD old_protect{};
|
VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect);
|
||||||
VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect);
|
|
||||||
|
std::memset(place, 0x90, length);
|
||||||
std::memset(place, 0x90, length);
|
|
||||||
|
VirtualProtect(place, length, old_protect, &old_protect);
|
||||||
VirtualProtect(place, length, old_protect, &old_protect);
|
FlushInstructionCache(GetCurrentProcess(), place, length);
|
||||||
FlushInstructionCache(GetCurrentProcess(), place, length);
|
}
|
||||||
}
|
|
||||||
|
void nop(const size_t place, const size_t length)
|
||||||
void nop(const size_t place, const size_t length)
|
{
|
||||||
{
|
nop(reinterpret_cast<void*>(place), length);
|
||||||
nop(reinterpret_cast<void*>(place), length);
|
}
|
||||||
}
|
|
||||||
|
void copy(void* place, const void* data, const size_t length)
|
||||||
void copy(void* place, const void* data, const size_t length)
|
{
|
||||||
{
|
DWORD old_protect{};
|
||||||
DWORD old_protect{};
|
VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect);
|
||||||
VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect);
|
|
||||||
|
std::memmove(place, data, length);
|
||||||
std::memmove(place, data, length);
|
|
||||||
|
VirtualProtect(place, length, old_protect, &old_protect);
|
||||||
VirtualProtect(place, length, old_protect, &old_protect);
|
FlushInstructionCache(GetCurrentProcess(), place, length);
|
||||||
FlushInstructionCache(GetCurrentProcess(), place, length);
|
}
|
||||||
}
|
|
||||||
|
void copy(const size_t place, const void* data, const size_t length)
|
||||||
void copy(const size_t place, const void* data, const size_t length)
|
{
|
||||||
{
|
copy(reinterpret_cast<void*>(place), data, length);
|
||||||
copy(reinterpret_cast<void*>(place), data, length);
|
}
|
||||||
}
|
|
||||||
|
bool is_relatively_far(const void* pointer, const void* data, int offset)
|
||||||
bool is_relatively_far(const void* pointer, const void* data, int offset)
|
{
|
||||||
{
|
const int64_t diff = size_t(data) - (size_t(pointer) + offset);
|
||||||
const int64_t diff = size_t(data) - (size_t(pointer) + offset);
|
const auto small_diff = int32_t(diff);
|
||||||
const auto small_diff = int32_t(diff);
|
return diff != int64_t(small_diff);
|
||||||
return diff != int64_t(small_diff);
|
}
|
||||||
}
|
|
||||||
|
void call(void* pointer, void* data)
|
||||||
void call(void* pointer, void* data)
|
{
|
||||||
{
|
if (is_relatively_far(pointer, data))
|
||||||
if (is_relatively_far(pointer, data))
|
{
|
||||||
{
|
throw std::runtime_error("Too far away to create 32bit relative branch");
|
||||||
throw std::runtime_error("Too far away to create 32bit relative branch");
|
}
|
||||||
}
|
|
||||||
|
auto* patch_pointer = PBYTE(pointer);
|
||||||
auto* patch_pointer = PBYTE(pointer);
|
set<uint8_t>(patch_pointer, 0xE8);
|
||||||
set<uint8_t>(patch_pointer, 0xE8);
|
set<int32_t>(patch_pointer + 1, int32_t(size_t(data) - (size_t(pointer) + 5)));
|
||||||
set<int32_t>(patch_pointer + 1, int32_t(size_t(data) - (size_t(pointer) + 5)));
|
}
|
||||||
}
|
|
||||||
|
void call(const size_t pointer, void* data)
|
||||||
void call(const size_t pointer, void* data)
|
{
|
||||||
{
|
return call(reinterpret_cast<void*>(pointer), data);
|
||||||
return call(reinterpret_cast<void*>(pointer), data);
|
}
|
||||||
}
|
|
||||||
|
void call(const size_t pointer, const size_t data)
|
||||||
void call(const size_t pointer, const size_t data)
|
{
|
||||||
{
|
return call(pointer, reinterpret_cast<void*>(data));
|
||||||
return call(pointer, reinterpret_cast<void*>(data));
|
}
|
||||||
}
|
|
||||||
|
void set(std::uintptr_t address, std::vector<std::uint8_t>&& bytes)
|
||||||
void set(std::uintptr_t address, std::vector<std::uint8_t>&& bytes)
|
{
|
||||||
{
|
DWORD oldProtect = 0;
|
||||||
DWORD oldProtect = 0;
|
|
||||||
|
auto* place = reinterpret_cast<void*>(address);
|
||||||
auto* place = reinterpret_cast<void*>(address);
|
VirtualProtect(place, bytes.size(), PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||||
VirtualProtect(place, bytes.size(), PAGE_EXECUTE_READWRITE, &oldProtect);
|
memcpy(place, bytes.data(), bytes.size());
|
||||||
memcpy(place, bytes.data(), bytes.size());
|
VirtualProtect(place, bytes.size(), oldProtect, &oldProtect);
|
||||||
VirtualProtect(place, bytes.size(), oldProtect, &oldProtect);
|
FlushInstructionCache(GetCurrentProcess(), place, bytes.size());
|
||||||
FlushInstructionCache(GetCurrentProcess(), place, bytes.size());
|
}
|
||||||
}
|
|
||||||
|
void set(std::uintptr_t address, void* buffer, size_t size)
|
||||||
void set(std::uintptr_t address, void* buffer, size_t size)
|
{
|
||||||
{
|
DWORD oldProtect = 0;
|
||||||
DWORD oldProtect = 0;
|
|
||||||
|
auto* place = reinterpret_cast<void*>(address);
|
||||||
auto* place = reinterpret_cast<void*>(address);
|
VirtualProtect(place, size, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||||
VirtualProtect(place, size, PAGE_EXECUTE_READWRITE, &oldProtect);
|
memcpy(place, buffer, size);
|
||||||
memcpy(place, buffer, size);
|
VirtualProtect(place, size, oldProtect, &oldProtect);
|
||||||
VirtualProtect(place, size, oldProtect, &oldProtect);
|
FlushInstructionCache(GetCurrentProcess(), place, size);
|
||||||
FlushInstructionCache(GetCurrentProcess(), place, size);
|
}
|
||||||
}
|
|
||||||
|
void jump(std::uintptr_t address, void* destination)
|
||||||
void jump(std::uintptr_t address, void* destination)
|
{
|
||||||
{
|
if (!address) return;
|
||||||
if (!address) return;
|
|
||||||
|
std::uint8_t* bytes = new std::uint8_t[5];
|
||||||
std::uint8_t* bytes = new std::uint8_t[5];
|
*bytes = 0xE9;
|
||||||
*bytes = 0xE9;
|
*reinterpret_cast<std::uint32_t*>(bytes + 1) = CalculateRelativeJMPAddress(address, destination);
|
||||||
*reinterpret_cast<std::uint32_t*>(bytes + 1) = CalculateRelativeJMPAddress(address, destination);
|
|
||||||
|
set(address, bytes, 5);
|
||||||
set(address, bytes, 5);
|
|
||||||
|
delete[] bytes;
|
||||||
delete[] bytes;
|
}
|
||||||
}
|
|
||||||
|
void* assemble(const std::function<void(assembler&)>& asm_function)
|
||||||
void* assemble(const std::function<void(assembler&)>& asm_function)
|
{
|
||||||
{
|
static asmjit::JitRuntime runtime;
|
||||||
static asmjit::JitRuntime runtime;
|
|
||||||
|
asmjit::CodeHolder code;
|
||||||
asmjit::CodeHolder code;
|
code.init(runtime.environment());
|
||||||
code.init(runtime.environment());
|
|
||||||
|
assembler a(&code);
|
||||||
assembler a(&code);
|
|
||||||
|
asm_function(a);
|
||||||
asm_function(a);
|
|
||||||
|
void* result = nullptr;
|
||||||
void* result = nullptr;
|
runtime.add(&result, &code);
|
||||||
runtime.add(&result, &code);
|
|
||||||
|
return result;
|
||||||
return result;
|
}
|
||||||
}
|
|
||||||
|
void* get_displacement_addr(int original)
|
||||||
void* get_displacement_addr(int original)
|
{
|
||||||
{
|
return reinterpret_cast<void*>(*reinterpret_cast<int*>(original + 1) + original + 5);
|
||||||
return reinterpret_cast<void*>(*reinterpret_cast<int*>(original + 1) + original + 5);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,233 +1,233 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define CalculateRelativeJMPAddress(X, Y) (((std::uintptr_t)Y - (std::uintptr_t)X) - 5)
|
#define CalculateRelativeJMPAddress(X, Y) (((std::uintptr_t)Y - (std::uintptr_t)X) - 5)
|
||||||
|
|
||||||
#include <asmjit/core/jitruntime.h>
|
#include <asmjit/core/jitruntime.h>
|
||||||
#include <asmjit/x86/x86assembler.h>
|
#include <asmjit/x86/x86assembler.h>
|
||||||
|
|
||||||
using namespace asmjit::x86;
|
using namespace asmjit::x86;
|
||||||
|
|
||||||
namespace utils::hook
|
namespace utils::hook
|
||||||
{
|
{
|
||||||
class signature final
|
class signature final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct container final
|
struct container final
|
||||||
{
|
{
|
||||||
std::string signature;
|
std::string signature;
|
||||||
std::string mask;
|
std::string mask;
|
||||||
std::function<void(char*)> callback;
|
std::function<void(char*)> callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
signature(void* start, const size_t length) : start_(start), length_(length)
|
signature(void* start, const size_t length) : start_(start), length_(length)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
signature(const DWORD start, const size_t length) : signature(reinterpret_cast<void*>(start), length)
|
signature(const DWORD start, const size_t length) : signature(reinterpret_cast<void*>(start), length)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
signature() : signature(0x400000, 0x800000)
|
signature() : signature(0x400000, 0x800000)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
void add(const container& container);
|
void add(const container& container);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void* start_;
|
void* start_;
|
||||||
size_t length_;
|
size_t length_;
|
||||||
std::vector<container> signatures_;
|
std::vector<container> signatures_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class assembler : public Assembler
|
class assembler : public Assembler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using Assembler::Assembler;
|
using Assembler::Assembler;
|
||||||
using Assembler::call;
|
using Assembler::call;
|
||||||
using Assembler::jmp;
|
using Assembler::jmp;
|
||||||
|
|
||||||
asmjit::Error call(void* target);
|
asmjit::Error call(void* target);
|
||||||
asmjit::Error jmp(void* target);
|
asmjit::Error jmp(void* target);
|
||||||
};
|
};
|
||||||
|
|
||||||
class detour
|
class detour
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
detour() = default;
|
detour() = default;
|
||||||
detour(void* place, void* target);
|
detour(void* place, void* target);
|
||||||
detour(size_t place, void* target);
|
detour(size_t place, void* target);
|
||||||
~detour();
|
~detour();
|
||||||
|
|
||||||
detour(detour&& other) noexcept
|
detour(detour&& other) noexcept
|
||||||
{
|
{
|
||||||
this->operator=(std::move(other));
|
this->operator=(std::move(other));
|
||||||
}
|
}
|
||||||
|
|
||||||
detour& operator= (detour&& other) noexcept
|
detour& operator= (detour&& other) noexcept
|
||||||
{
|
{
|
||||||
if (this != &other)
|
if (this != &other)
|
||||||
{
|
{
|
||||||
this->~detour();
|
this->~detour();
|
||||||
|
|
||||||
this->place_ = other.place_;
|
this->place_ = other.place_;
|
||||||
this->original_ = other.original_;
|
this->original_ = other.original_;
|
||||||
|
|
||||||
other.place_ = nullptr;
|
other.place_ = nullptr;
|
||||||
other.original_ = nullptr;
|
other.original_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
detour(const detour&) = delete;
|
detour(const detour&) = delete;
|
||||||
detour& operator= (const detour&) = delete;
|
detour& operator= (const detour&) = delete;
|
||||||
|
|
||||||
void enable() const;
|
void enable() const;
|
||||||
void disable() const;
|
void disable() const;
|
||||||
|
|
||||||
void create(void* place, void* target);
|
void create(void* place, void* target);
|
||||||
void create(size_t place, void* target);
|
void create(size_t place, void* target);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T* get() const
|
T* get() const
|
||||||
{
|
{
|
||||||
return static_cast<T*>(this->get_original());
|
return static_cast<T*>(this->get_original());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
T invoke(Args... args)
|
T invoke(Args... args)
|
||||||
{
|
{
|
||||||
return static_cast<T(__cdecl*)(Args ...)>(this->get_original())(args...);
|
return static_cast<T(__cdecl*)(Args ...)>(this->get_original())(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
T invoke_pascal(Args... args)
|
T invoke_pascal(Args... args)
|
||||||
{
|
{
|
||||||
return static_cast<T(__stdcall*)(Args ...)>(this->get_original())(args...);
|
return static_cast<T(__stdcall*)(Args ...)>(this->get_original())(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
T invoke_this(Args... args)
|
T invoke_this(Args... args)
|
||||||
{
|
{
|
||||||
return static_cast<T(__thiscall*)(Args ...)>(this->get_original())(args...);
|
return static_cast<T(__thiscall*)(Args ...)>(this->get_original())(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
T invoke_fast(Args... args)
|
T invoke_fast(Args... args)
|
||||||
{
|
{
|
||||||
return static_cast<T(__fastcall*)(Args ...)>(this->get_original())(args...);
|
return static_cast<T(__fastcall*)(Args ...)>(this->get_original())(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] void* get_original() const;
|
[[nodiscard]] void* get_original() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void* place_{};
|
void* place_{};
|
||||||
void* original_{};
|
void* original_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
void nop(void* place, size_t length);
|
void nop(void* place, size_t length);
|
||||||
void nop(size_t place, size_t length);
|
void nop(size_t place, size_t length);
|
||||||
|
|
||||||
void copy(void* place, const void* data, size_t length);
|
void copy(void* place, const void* data, size_t length);
|
||||||
void copy(size_t place, const void* data, size_t length);
|
void copy(size_t place, const void* data, size_t length);
|
||||||
|
|
||||||
bool is_relatively_far(const void* pointer, const void* data, int offset = 5);
|
bool is_relatively_far(const void* pointer, const void* data, int offset = 5);
|
||||||
|
|
||||||
void call(void* pointer, void* data);
|
void call(void* pointer, void* data);
|
||||||
void call(size_t pointer, void* data);
|
void call(size_t pointer, void* data);
|
||||||
void call(size_t pointer, size_t data);
|
void call(size_t pointer, size_t data);
|
||||||
|
|
||||||
void jump(std::uintptr_t address, void* destination);
|
void jump(std::uintptr_t address, void* destination);
|
||||||
|
|
||||||
void* assemble(const std::function<void(assembler&)>& asm_function);
|
void* assemble(const std::function<void(assembler&)>& asm_function);
|
||||||
|
|
||||||
void* get_displacement_addr(int original);
|
void* get_displacement_addr(int original);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T extract(void* address)
|
T extract(void* address)
|
||||||
{
|
{
|
||||||
const auto data = static_cast<uint8_t*>(address);
|
const auto data = static_cast<uint8_t*>(address);
|
||||||
const auto offset = *reinterpret_cast<int32_t*>(data);
|
const auto offset = *reinterpret_cast<int32_t*>(data);
|
||||||
return reinterpret_cast<T>(data + offset + 4);
|
return reinterpret_cast<T>(data + offset + 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static void set(void* place, T value)
|
static void set(void* place, T value)
|
||||||
{
|
{
|
||||||
DWORD old_protect;
|
DWORD old_protect;
|
||||||
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &old_protect);
|
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &old_protect);
|
||||||
|
|
||||||
*static_cast<T*>(place) = value;
|
*static_cast<T*>(place) = value;
|
||||||
|
|
||||||
VirtualProtect(place, sizeof(T), old_protect, &old_protect);
|
VirtualProtect(place, sizeof(T), old_protect, &old_protect);
|
||||||
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
|
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static void set(const size_t place, T value)
|
static void set(const size_t place, T value)
|
||||||
{
|
{
|
||||||
return set<T>(reinterpret_cast<void*>(place), value);
|
return set<T>(reinterpret_cast<void*>(place), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static T get(void* place)
|
static T get(void* place)
|
||||||
{
|
{
|
||||||
return *static_cast<T*>(place);
|
return *static_cast<T*>(place);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static T get(const size_t place)
|
static T get(const size_t place)
|
||||||
{
|
{
|
||||||
return get<T>(reinterpret_cast<void*>(place));
|
return get<T>(reinterpret_cast<void*>(place));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
static T invoke(size_t func, Args... args)
|
static T invoke(size_t func, Args... args)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<T(__cdecl*)(Args ...)>(func)(args...);
|
return reinterpret_cast<T(__cdecl*)(Args ...)>(func)(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
static T invoke(void* func, Args... args)
|
static T invoke(void* func, Args... args)
|
||||||
{
|
{
|
||||||
return static_cast<T(__cdecl*)(Args ...)>(func)(args...);
|
return static_cast<T(__cdecl*)(Args ...)>(func)(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
static T invoke_pascal(size_t func, Args... args)
|
static T invoke_pascal(size_t func, Args... args)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<T(__stdcall*)(Args ...)>(func)(args...);
|
return reinterpret_cast<T(__stdcall*)(Args ...)>(func)(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
static T invoke_pascal(void* func, Args... args)
|
static T invoke_pascal(void* func, Args... args)
|
||||||
{
|
{
|
||||||
return static_cast<T(__stdcall*)(Args ...)>(func)(args...);
|
return static_cast<T(__stdcall*)(Args ...)>(func)(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
static T invoke_this(size_t func, Args... args)
|
static T invoke_this(size_t func, Args... args)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<T(__thiscall*)(Args ...)>(func)(args...);
|
return reinterpret_cast<T(__thiscall*)(Args ...)>(func)(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
static T invoke_this(void* func, Args... args)
|
static T invoke_this(void* func, Args... args)
|
||||||
{
|
{
|
||||||
return static_cast<T(__thiscall*)(Args ...)>(func)(args...);
|
return static_cast<T(__thiscall*)(Args ...)>(func)(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
static T invoke_fast(size_t func, Args... args)
|
static T invoke_fast(size_t func, Args... args)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<T(__fastcall*)(Args ...)>(func)(args...);
|
return reinterpret_cast<T(__fastcall*)(Args ...)>(func)(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
static T invoke_fast(void* func, Args... args)
|
static T invoke_fast(void* func, Args... args)
|
||||||
{
|
{
|
||||||
return static_cast<T(__fastcall*)(Args ...)>(func)(args...);
|
return static_cast<T(__fastcall*)(Args ...)>(func)(args...);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,91 +1,91 @@
|
|||||||
#include <stdinc.hpp>
|
#include <stdinc.hpp>
|
||||||
#include "http.hpp"
|
#include "http.hpp"
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#include <gsl/gsl>
|
#include <gsl/gsl>
|
||||||
|
|
||||||
#pragma comment(lib, "ws2_32.lib")
|
#pragma comment(lib, "ws2_32.lib")
|
||||||
|
|
||||||
namespace utils::http
|
namespace utils::http
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
struct progress_helper
|
struct progress_helper
|
||||||
{
|
{
|
||||||
const std::function<bool(size_t)>* callback{};
|
const std::function<bool(size_t)>* callback{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable: 4244)
|
#pragma warning(disable: 4244)
|
||||||
int progress_callback(void* clientp, const curl_off_t /*dltotal*/, const curl_off_t dlnow, const curl_off_t /*ultotal*/, const curl_off_t /*ulnow*/)
|
int progress_callback(void* clientp, const curl_off_t /*dltotal*/, const curl_off_t dlnow, const curl_off_t /*ultotal*/, const curl_off_t /*ulnow*/)
|
||||||
{
|
{
|
||||||
auto* helper = static_cast<progress_helper*>(clientp);
|
auto* helper = static_cast<progress_helper*>(clientp);
|
||||||
|
|
||||||
if (*helper->callback && !(*helper->callback)(dlnow))
|
if (*helper->callback && !(*helper->callback)(dlnow))
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
|
|
||||||
size_t write_callback(void* contents, const size_t size, const size_t nmemb, void* userp)
|
size_t write_callback(void* contents, const size_t size, const size_t nmemb, void* userp)
|
||||||
{
|
{
|
||||||
auto* buffer = static_cast<std::string*>(userp);
|
auto* buffer = static_cast<std::string*>(userp);
|
||||||
|
|
||||||
const auto total_size = size * nmemb;
|
const auto total_size = size * nmemb;
|
||||||
buffer->append(static_cast<char*>(contents), total_size);
|
buffer->append(static_cast<char*>(contents), total_size);
|
||||||
return total_size;
|
return total_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> get_data(const std::string& url, const headers& headers, const std::function<bool(size_t)>& callback)
|
std::optional<std::string> get_data(const std::string& url, const headers& headers, const std::function<bool(size_t)>& callback)
|
||||||
{
|
{
|
||||||
curl_slist* header_list = nullptr;
|
curl_slist* header_list = nullptr;
|
||||||
auto* curl = curl_easy_init();
|
auto* curl = curl_easy_init();
|
||||||
if (!curl)
|
if (!curl)
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto _ = gsl::finally([&]()
|
auto _ = gsl::finally([&]()
|
||||||
{
|
{
|
||||||
curl_slist_free_all(header_list);
|
curl_slist_free_all(header_list);
|
||||||
curl_easy_cleanup(curl);
|
curl_easy_cleanup(curl);
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const auto& header : headers)
|
for (const auto& header : headers)
|
||||||
{
|
{
|
||||||
auto data = header.first + ": " + header.second;
|
auto data = header.first + ": " + header.second;
|
||||||
header_list = curl_slist_append(header_list, data.data());
|
header_list = curl_slist_append(header_list, data.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string buffer{};
|
std::string buffer{};
|
||||||
progress_helper helper{};
|
progress_helper helper{};
|
||||||
helper.callback = &callback;
|
helper.callback = &callback;
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);
|
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, url.data());
|
curl_easy_setopt(curl, CURLOPT_URL, url.data());
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
|
||||||
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback);
|
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback);
|
||||||
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &helper);
|
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &helper);
|
||||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
|
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
|
||||||
|
|
||||||
if (curl_easy_perform(curl) == CURLE_OK)
|
if (curl_easy_perform(curl) == CURLE_OK)
|
||||||
{
|
{
|
||||||
return {std::move(buffer)};
|
return {std::move(buffer)};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::future<std::optional<std::string>> get_data_async(const std::string& url, const headers& headers)
|
std::future<std::optional<std::string>> get_data_async(const std::string& url, const headers& headers)
|
||||||
{
|
{
|
||||||
return std::async(std::launch::async, [url, headers]()
|
return std::async(std::launch::async, [url, headers]()
|
||||||
{
|
{
|
||||||
return get_data(url, headers);
|
return get_data(url, headers);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,13 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <future>
|
#include <future>
|
||||||
|
|
||||||
namespace utils::http
|
namespace utils::http
|
||||||
{
|
{
|
||||||
using headers = std::unordered_map<std::string, std::string>;
|
using headers = std::unordered_map<std::string, std::string>;
|
||||||
|
|
||||||
std::optional<std::string> get_data(const std::string& url, const headers& headers = {}, const std::function<bool(size_t)>& callback = {});
|
std::optional<std::string> get_data(const std::string& url, const headers& headers = {}, const std::function<bool(size_t)>& callback = {});
|
||||||
std::future<std::optional<std::string>> get_data_async(const std::string& url, const headers& headers = {});
|
std::future<std::optional<std::string>> get_data_async(const std::string& url, const headers& headers = {});
|
||||||
}
|
}
|
234
src/utils/io.cpp
234
src/utils/io.cpp
@ -1,118 +1,118 @@
|
|||||||
#include <stdinc.hpp>
|
#include <stdinc.hpp>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include "io.hpp"
|
#include "io.hpp"
|
||||||
|
|
||||||
namespace utils::io
|
namespace utils::io
|
||||||
{
|
{
|
||||||
bool remove_file(const std::string& file)
|
bool remove_file(const std::string& file)
|
||||||
{
|
{
|
||||||
return DeleteFileA(file.data()) == TRUE;
|
return DeleteFileA(file.data()) == TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool file_exists(const std::string& file)
|
bool file_exists(const std::string& file)
|
||||||
{
|
{
|
||||||
return std::ifstream(file).good();
|
return std::ifstream(file).good();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool write_file(const std::string& file, const std::string& data, const bool append)
|
bool write_file(const std::string& file, const std::string& data, const bool append)
|
||||||
{
|
{
|
||||||
const auto pos = file.find_last_of("/\\");
|
const auto pos = file.find_last_of("/\\");
|
||||||
if (pos != std::string::npos)
|
if (pos != std::string::npos)
|
||||||
{
|
{
|
||||||
create_directory(file.substr(0, pos));
|
create_directory(file.substr(0, pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ofstream stream(
|
std::ofstream stream(
|
||||||
file, std::ios::binary | std::ofstream::out | (append ? std::ofstream::app : 0));
|
file, std::ios::binary | std::ofstream::out | (append ? std::ofstream::app : 0));
|
||||||
|
|
||||||
if (stream.is_open())
|
if (stream.is_open())
|
||||||
{
|
{
|
||||||
stream.write(data.data(), data.size());
|
stream.write(data.data(), data.size());
|
||||||
stream.close();
|
stream.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string read_file(const std::string& file)
|
std::string read_file(const std::string& file)
|
||||||
{
|
{
|
||||||
std::string data;
|
std::string data;
|
||||||
read_file(file, &data);
|
read_file(file, &data);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool read_file(const std::string& file, std::string* data)
|
bool read_file(const std::string& file, std::string* data)
|
||||||
{
|
{
|
||||||
if (!data) return false;
|
if (!data) return false;
|
||||||
data->clear();
|
data->clear();
|
||||||
|
|
||||||
if (file_exists(file))
|
if (file_exists(file))
|
||||||
{
|
{
|
||||||
std::ifstream stream(file, std::ios::binary);
|
std::ifstream stream(file, std::ios::binary);
|
||||||
if (!stream.is_open()) return false;
|
if (!stream.is_open()) return false;
|
||||||
|
|
||||||
stream.seekg(0, std::ios::end);
|
stream.seekg(0, std::ios::end);
|
||||||
const std::streamsize size = stream.tellg();
|
const std::streamsize size = stream.tellg();
|
||||||
stream.seekg(0, std::ios::beg);
|
stream.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
if (size > -1)
|
if (size > -1)
|
||||||
{
|
{
|
||||||
data->resize(static_cast<uint32_t>(size));
|
data->resize(static_cast<uint32_t>(size));
|
||||||
stream.read(const_cast<char*>(data->data()), size);
|
stream.read(const_cast<char*>(data->data()), size);
|
||||||
stream.close();
|
stream.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t file_size(const std::string& file)
|
size_t file_size(const std::string& file)
|
||||||
{
|
{
|
||||||
if (file_exists(file))
|
if (file_exists(file))
|
||||||
{
|
{
|
||||||
std::ifstream stream(file, std::ios::binary);
|
std::ifstream stream(file, std::ios::binary);
|
||||||
|
|
||||||
if (stream.good())
|
if (stream.good())
|
||||||
{
|
{
|
||||||
stream.seekg(0, std::ios::end);
|
stream.seekg(0, std::ios::end);
|
||||||
return static_cast<size_t>(stream.tellg());
|
return static_cast<size_t>(stream.tellg());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool create_directory(const std::string& directory)
|
bool create_directory(const std::string& directory)
|
||||||
{
|
{
|
||||||
return std::filesystem::create_directories(directory);
|
return std::filesystem::create_directories(directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool directory_exists(const std::string& directory)
|
bool directory_exists(const std::string& directory)
|
||||||
{
|
{
|
||||||
return std::filesystem::is_directory(directory);
|
return std::filesystem::is_directory(directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool directory_is_empty(const std::string& directory)
|
bool directory_is_empty(const std::string& directory)
|
||||||
{
|
{
|
||||||
return std::filesystem::is_empty(directory);
|
return std::filesystem::is_empty(directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> list_files(const std::string& directory)
|
std::vector<std::string> list_files(const std::string& directory)
|
||||||
{
|
{
|
||||||
std::vector<std::string> files;
|
std::vector<std::string> files;
|
||||||
|
|
||||||
for (auto& file : std::filesystem::directory_iterator(directory))
|
for (auto& file : std::filesystem::directory_iterator(directory))
|
||||||
{
|
{
|
||||||
files.push_back(file.path().generic_string());
|
files.push_back(file.path().generic_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target)
|
void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target)
|
||||||
{
|
{
|
||||||
std::filesystem::copy(src, target, std::filesystem::copy_options::overwrite_existing | std::filesystem::copy_options::recursive);
|
std::filesystem::copy(src, target, std::filesystem::copy_options::overwrite_existing | std::filesystem::copy_options::recursive);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,20 +1,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
namespace utils::io
|
namespace utils::io
|
||||||
{
|
{
|
||||||
bool remove_file(const std::string& file);
|
bool remove_file(const std::string& file);
|
||||||
bool file_exists(const std::string& file);
|
bool file_exists(const std::string& file);
|
||||||
bool write_file(const std::string& file, const std::string& data, bool append = false);
|
bool write_file(const std::string& file, const std::string& data, bool append = false);
|
||||||
bool read_file(const std::string& file, std::string* data);
|
bool read_file(const std::string& file, std::string* data);
|
||||||
std::string read_file(const std::string& file);
|
std::string read_file(const std::string& file);
|
||||||
size_t file_size(const std::string& file);
|
size_t file_size(const std::string& file);
|
||||||
bool create_directory(const std::string& directory);
|
bool create_directory(const std::string& directory);
|
||||||
bool directory_exists(const std::string& directory);
|
bool directory_exists(const std::string& directory);
|
||||||
bool directory_is_empty(const std::string& directory);
|
bool directory_is_empty(const std::string& directory);
|
||||||
std::vector<std::string> list_files(const std::string& directory);
|
std::vector<std::string> list_files(const std::string& directory);
|
||||||
void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target);
|
void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target);
|
||||||
}
|
}
|
||||||
|
@ -1,109 +1,109 @@
|
|||||||
#include <stdinc.hpp>
|
#include <stdinc.hpp>
|
||||||
#include "memory.hpp"
|
#include "memory.hpp"
|
||||||
|
|
||||||
namespace utils
|
namespace utils
|
||||||
{
|
{
|
||||||
memory::allocator memory::mem_allocator_;
|
memory::allocator memory::mem_allocator_;
|
||||||
|
|
||||||
memory::allocator::~allocator()
|
memory::allocator::~allocator()
|
||||||
{
|
{
|
||||||
this->clear();
|
this->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void memory::allocator::clear()
|
void memory::allocator::clear()
|
||||||
{
|
{
|
||||||
std::lock_guard _(this->mutex_);
|
std::lock_guard _(this->mutex_);
|
||||||
|
|
||||||
for (auto& data : this->pool_)
|
for (auto& data : this->pool_)
|
||||||
{
|
{
|
||||||
memory::free(data);
|
memory::free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->pool_.clear();
|
this->pool_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void memory::allocator::free(void* data)
|
void memory::allocator::free(void* data)
|
||||||
{
|
{
|
||||||
std::lock_guard _(this->mutex_);
|
std::lock_guard _(this->mutex_);
|
||||||
|
|
||||||
const auto j = std::find(this->pool_.begin(), this->pool_.end(), data);
|
const auto j = std::find(this->pool_.begin(), this->pool_.end(), data);
|
||||||
if (j != this->pool_.end())
|
if (j != this->pool_.end())
|
||||||
{
|
{
|
||||||
memory::free(data);
|
memory::free(data);
|
||||||
this->pool_.erase(j);
|
this->pool_.erase(j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void memory::allocator::free(const void* data)
|
void memory::allocator::free(const void* data)
|
||||||
{
|
{
|
||||||
this->free(const_cast<void*>(data));
|
this->free(const_cast<void*>(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
void* memory::allocator::allocate(const size_t length)
|
void* memory::allocator::allocate(const size_t length)
|
||||||
{
|
{
|
||||||
std::lock_guard _(this->mutex_);
|
std::lock_guard _(this->mutex_);
|
||||||
|
|
||||||
const auto data = memory::allocate(length);
|
const auto data = memory::allocate(length);
|
||||||
this->pool_.push_back(data);
|
this->pool_.push_back(data);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool memory::allocator::empty() const
|
bool memory::allocator::empty() const
|
||||||
{
|
{
|
||||||
return this->pool_.empty();
|
return this->pool_.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
char* memory::allocator::duplicate_string(const std::string& string)
|
char* memory::allocator::duplicate_string(const std::string& string)
|
||||||
{
|
{
|
||||||
std::lock_guard _(this->mutex_);
|
std::lock_guard _(this->mutex_);
|
||||||
|
|
||||||
const auto data = memory::duplicate_string(string);
|
const auto data = memory::duplicate_string(string);
|
||||||
this->pool_.push_back(data);
|
this->pool_.push_back(data);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* memory::allocate(const size_t length)
|
void* memory::allocate(const size_t length)
|
||||||
{
|
{
|
||||||
return calloc(length, 1);
|
return calloc(length, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* memory::duplicate_string(const std::string& string)
|
char* memory::duplicate_string(const std::string& string)
|
||||||
{
|
{
|
||||||
const auto new_string = allocate_array<char>(string.size() + 1);
|
const auto new_string = allocate_array<char>(string.size() + 1);
|
||||||
std::memcpy(new_string, string.data(), string.size());
|
std::memcpy(new_string, string.data(), string.size());
|
||||||
return new_string;
|
return new_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
void memory::free(void* data)
|
void memory::free(void* data)
|
||||||
{
|
{
|
||||||
if (data)
|
if (data)
|
||||||
{
|
{
|
||||||
::free(data);
|
::free(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void memory::free(const void* data)
|
void memory::free(const void* data)
|
||||||
{
|
{
|
||||||
free(const_cast<void*>(data));
|
free(const_cast<void*>(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool memory::is_set(const void* mem, const char chr, const size_t length)
|
bool memory::is_set(const void* mem, const char chr, const size_t length)
|
||||||
{
|
{
|
||||||
const auto mem_arr = static_cast<const char*>(mem);
|
const auto mem_arr = static_cast<const char*>(mem);
|
||||||
|
|
||||||
for (size_t i = 0; i < length; ++i)
|
for (size_t i = 0; i < length; ++i)
|
||||||
{
|
{
|
||||||
if (mem_arr[i] != chr)
|
if (mem_arr[i] != chr)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
memory::allocator* memory::get_allocator()
|
memory::allocator* memory::get_allocator()
|
||||||
{
|
{
|
||||||
return &memory::mem_allocator_;
|
return &memory::mem_allocator_;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,75 +1,75 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace utils
|
namespace utils
|
||||||
{
|
{
|
||||||
class memory final
|
class memory final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
class allocator final
|
class allocator final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
~allocator();
|
~allocator();
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
void free(void* data);
|
void free(void* data);
|
||||||
|
|
||||||
void free(const void* data);
|
void free(const void* data);
|
||||||
|
|
||||||
void* allocate(size_t length);
|
void* allocate(size_t length);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline T* allocate()
|
inline T* allocate()
|
||||||
{
|
{
|
||||||
return this->allocate_array<T>(1);
|
return this->allocate_array<T>(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline T* allocate_array(const size_t count = 1)
|
inline T* allocate_array(const size_t count = 1)
|
||||||
{
|
{
|
||||||
return static_cast<T*>(this->allocate(count * sizeof(T)));
|
return static_cast<T*>(this->allocate(count * sizeof(T)));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const;
|
bool empty() const;
|
||||||
|
|
||||||
char* duplicate_string(const std::string& string);
|
char* duplicate_string(const std::string& string);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
std::vector<void*> pool_;
|
std::vector<void*> pool_;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void* allocate(size_t length);
|
static void* allocate(size_t length);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static inline T* allocate()
|
static inline T* allocate()
|
||||||
{
|
{
|
||||||
return allocate_array<T>(1);
|
return allocate_array<T>(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static inline T* allocate_array(const size_t count = 1)
|
static inline T* allocate_array(const size_t count = 1)
|
||||||
{
|
{
|
||||||
return static_cast<T*>(allocate(count * sizeof(T)));
|
return static_cast<T*>(allocate(count * sizeof(T)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static char* duplicate_string(const std::string& string);
|
static char* duplicate_string(const std::string& string);
|
||||||
|
|
||||||
static void free(void* data);
|
static void free(void* data);
|
||||||
static void free(const void* data);
|
static void free(const void* data);
|
||||||
|
|
||||||
static bool is_set(const void* mem, char chr, size_t length);
|
static bool is_set(const void* mem, char chr, size_t length);
|
||||||
|
|
||||||
static bool is_bad_read_ptr(const void* ptr);
|
static bool is_bad_read_ptr(const void* ptr);
|
||||||
static bool is_bad_code_ptr(const void* ptr);
|
static bool is_bad_code_ptr(const void* ptr);
|
||||||
static bool is_rdata_ptr(void* ptr);
|
static bool is_rdata_ptr(void* ptr);
|
||||||
|
|
||||||
static allocator* get_allocator();
|
static allocator* get_allocator();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static allocator mem_allocator_;
|
static allocator mem_allocator_;
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -1,172 +1,172 @@
|
|||||||
#include <stdinc.hpp>
|
#include <stdinc.hpp>
|
||||||
#include "string.hpp"
|
#include "string.hpp"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace utils::string
|
namespace utils::string
|
||||||
{
|
{
|
||||||
const char* va(const char* fmt, ...)
|
const char* va(const char* fmt, ...)
|
||||||
{
|
{
|
||||||
static thread_local va_provider<8, 256> provider;
|
static thread_local va_provider<8, 256> provider;
|
||||||
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
|
|
||||||
const char* result = provider.get(fmt, ap);
|
const char* result = provider.get(fmt, ap);
|
||||||
|
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> split(const std::string& s, const char delim)
|
std::vector<std::string> split(const std::string& s, const char delim)
|
||||||
{
|
{
|
||||||
std::stringstream ss(s);
|
std::stringstream ss(s);
|
||||||
std::string item;
|
std::string item;
|
||||||
std::vector<std::string> elems;
|
std::vector<std::string> elems;
|
||||||
|
|
||||||
while (std::getline(ss, item, delim))
|
while (std::getline(ss, item, delim))
|
||||||
{
|
{
|
||||||
elems.push_back(item); // elems.push_back(std::move(item)); // if C++11 (based on comment from @mchiasson)
|
elems.push_back(item); // elems.push_back(std::move(item)); // if C++11 (based on comment from @mchiasson)
|
||||||
}
|
}
|
||||||
|
|
||||||
return elems;
|
return elems;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_lower(std::string text)
|
std::string to_lower(std::string text)
|
||||||
{
|
{
|
||||||
std::transform(text.begin(), text.end(), text.begin(), [](const char input)
|
std::transform(text.begin(), text.end(), text.begin(), [](const char input)
|
||||||
{
|
{
|
||||||
return static_cast<char>(tolower(input));
|
return static_cast<char>(tolower(input));
|
||||||
});
|
});
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_upper(std::string text)
|
std::string to_upper(std::string text)
|
||||||
{
|
{
|
||||||
std::transform(text.begin(), text.end(), text.begin(), [](const char input)
|
std::transform(text.begin(), text.end(), text.begin(), [](const char input)
|
||||||
{
|
{
|
||||||
return static_cast<char>(toupper(input));
|
return static_cast<char>(toupper(input));
|
||||||
});
|
});
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool starts_with(const std::string& text, const std::string& substring)
|
bool starts_with(const std::string& text, const std::string& substring)
|
||||||
{
|
{
|
||||||
return text.find(substring) == 0;
|
return text.find(substring) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ends_with(const std::string& text, const std::string& substring)
|
bool ends_with(const std::string& text, const std::string& substring)
|
||||||
{
|
{
|
||||||
if (substring.size() > text.size()) return false;
|
if (substring.size() > text.size()) return false;
|
||||||
return std::equal(substring.rbegin(), substring.rend(), text.rbegin());
|
return std::equal(substring.rbegin(), substring.rend(), text.rbegin());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_numeric(const std::string& text)
|
bool is_numeric(const std::string& text)
|
||||||
{
|
{
|
||||||
return std::to_string(atoi(text.data())) == text;
|
return std::to_string(atoi(text.data())) == text;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string dump_hex(const std::string& data, const std::string& separator)
|
std::string dump_hex(const std::string& data, const std::string& separator)
|
||||||
{
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < data.size(); ++i)
|
for (unsigned int i = 0; i < data.size(); ++i)
|
||||||
{
|
{
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
{
|
{
|
||||||
result.append(separator);
|
result.append(separator);
|
||||||
}
|
}
|
||||||
|
|
||||||
result.append(va("%02X", data[i] & 0xFF));
|
result.append(va("%02X", data[i] & 0xFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void strip(const char* in, char* out, int max)
|
void strip(const char* in, char* out, int max)
|
||||||
{
|
{
|
||||||
if (!in || !out) return;
|
if (!in || !out) return;
|
||||||
|
|
||||||
max--;
|
max--;
|
||||||
auto current = 0;
|
auto current = 0;
|
||||||
while (*in != 0 && current < max)
|
while (*in != 0 && current < max)
|
||||||
{
|
{
|
||||||
const auto color_index = (*(in + 1) - 48) >= 0xC ? 7 : (*(in + 1) - 48);
|
const auto color_index = (*(in + 1) - 48) >= 0xC ? 7 : (*(in + 1) - 48);
|
||||||
|
|
||||||
if (*in == '^' && (color_index != 7 || *(in + 1) == '7'))
|
if (*in == '^' && (color_index != 7 || *(in + 1) == '7'))
|
||||||
{
|
{
|
||||||
++in;
|
++in;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*out = *in;
|
*out = *in;
|
||||||
++out;
|
++out;
|
||||||
++current;
|
++current;
|
||||||
}
|
}
|
||||||
|
|
||||||
++in;
|
++in;
|
||||||
}
|
}
|
||||||
*out = '\0';
|
*out = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable: 4100)
|
#pragma warning(disable: 4100)
|
||||||
std::string convert(const std::wstring& wstr)
|
std::string convert(const std::wstring& wstr)
|
||||||
{
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
result.reserve(wstr.size());
|
result.reserve(wstr.size());
|
||||||
|
|
||||||
for (const auto& chr : wstr)
|
for (const auto& chr : wstr)
|
||||||
{
|
{
|
||||||
result.push_back(static_cast<char>(chr));
|
result.push_back(static_cast<char>(chr));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring convert(const std::string& str)
|
std::wstring convert(const std::string& str)
|
||||||
{
|
{
|
||||||
std::wstring result;
|
std::wstring result;
|
||||||
result.reserve(str.size());
|
result.reserve(str.size());
|
||||||
|
|
||||||
for (const auto& chr : str)
|
for (const auto& chr : str)
|
||||||
{
|
{
|
||||||
result.push_back(static_cast<wchar_t>(chr));
|
result.push_back(static_cast<wchar_t>(chr));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
|
|
||||||
std::string replace(std::string str, const std::string& from, const std::string& to)
|
std::string replace(std::string str, const std::string& from, const std::string& to)
|
||||||
{
|
{
|
||||||
if (from.empty())
|
if (from.empty())
|
||||||
{
|
{
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t start_pos = 0;
|
size_t start_pos = 0;
|
||||||
while ((start_pos = str.find(from, start_pos)) != std::string::npos)
|
while ((start_pos = str.find(from, start_pos)) != std::string::npos)
|
||||||
{
|
{
|
||||||
str.replace(start_pos, from.length(), to);
|
str.replace(start_pos, from.length(), to);
|
||||||
start_pos += to.length();
|
start_pos += to.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_timestamp()
|
std::string get_timestamp()
|
||||||
{
|
{
|
||||||
tm ltime{};
|
tm ltime{};
|
||||||
char timestamp[MAX_PATH] = { 0 };
|
char timestamp[MAX_PATH] = { 0 };
|
||||||
const auto time = _time64(nullptr);
|
const auto time = _time64(nullptr);
|
||||||
|
|
||||||
_localtime64_s(<ime, &time);
|
_localtime64_s(<ime, &time);
|
||||||
strftime(timestamp, sizeof(timestamp) - 1, "%Y-%m-%d-%H-%M-%S", <ime);
|
strftime(timestamp, sizeof(timestamp) - 1, "%Y-%m-%d-%H-%M-%S", <ime);
|
||||||
|
|
||||||
return timestamp;
|
return timestamp;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,101 +1,101 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "memory.hpp"
|
#include "memory.hpp"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#ifndef ARRAYSIZE
|
#ifndef ARRAYSIZE
|
||||||
template <class Type, size_t n>
|
template <class Type, size_t n>
|
||||||
size_t ARRAYSIZE(Type(&)[n]) { return n; }
|
size_t ARRAYSIZE(Type(&)[n]) { return n; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace utils::string
|
namespace utils::string
|
||||||
{
|
{
|
||||||
template <size_t Buffers, size_t MinBufferSize>
|
template <size_t Buffers, size_t MinBufferSize>
|
||||||
class va_provider final
|
class va_provider final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static_assert(Buffers != 0 && MinBufferSize != 0, "Buffers and MinBufferSize mustn't be 0");
|
static_assert(Buffers != 0 && MinBufferSize != 0, "Buffers and MinBufferSize mustn't be 0");
|
||||||
|
|
||||||
va_provider() : current_buffer_(0)
|
va_provider() : current_buffer_(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
char* get(const char* format, const va_list ap)
|
char* get(const char* format, const va_list ap)
|
||||||
{
|
{
|
||||||
++this->current_buffer_ %= ARRAYSIZE(this->string_pool_);
|
++this->current_buffer_ %= ARRAYSIZE(this->string_pool_);
|
||||||
auto entry = &this->string_pool_[this->current_buffer_];
|
auto entry = &this->string_pool_[this->current_buffer_];
|
||||||
|
|
||||||
if (!entry->size || !entry->buffer)
|
if (!entry->size || !entry->buffer)
|
||||||
{
|
{
|
||||||
throw std::runtime_error("String pool not initialized");
|
throw std::runtime_error("String pool not initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
const int res = vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap);
|
const int res = vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap);
|
||||||
if (res > 0) break; // Success
|
if (res > 0) break; // Success
|
||||||
if (res == 0) return nullptr; // Error
|
if (res == 0) return nullptr; // Error
|
||||||
|
|
||||||
entry->double_size();
|
entry->double_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
return entry->buffer;
|
return entry->buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class entry final
|
class entry final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit entry(const size_t _size = MinBufferSize) : size(_size), buffer(nullptr)
|
explicit entry(const size_t _size = MinBufferSize) : size(_size), buffer(nullptr)
|
||||||
{
|
{
|
||||||
if (this->size < MinBufferSize) this->size = MinBufferSize;
|
if (this->size < MinBufferSize) this->size = MinBufferSize;
|
||||||
this->allocate();
|
this->allocate();
|
||||||
}
|
}
|
||||||
|
|
||||||
~entry()
|
~entry()
|
||||||
{
|
{
|
||||||
if (this->buffer) memory::get_allocator()->free(this->buffer);
|
if (this->buffer) memory::get_allocator()->free(this->buffer);
|
||||||
this->size = 0;
|
this->size = 0;
|
||||||
this->buffer = nullptr;
|
this->buffer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void allocate()
|
void allocate()
|
||||||
{
|
{
|
||||||
if (this->buffer) memory::get_allocator()->free(this->buffer);
|
if (this->buffer) memory::get_allocator()->free(this->buffer);
|
||||||
this->buffer = memory::get_allocator()->allocate_array<char>(this->size + 1);
|
this->buffer = memory::get_allocator()->allocate_array<char>(this->size + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void double_size()
|
void double_size()
|
||||||
{
|
{
|
||||||
this->size *= 2;
|
this->size *= 2;
|
||||||
this->allocate();
|
this->allocate();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size;
|
size_t size;
|
||||||
char* buffer;
|
char* buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t current_buffer_;
|
size_t current_buffer_;
|
||||||
entry string_pool_[Buffers];
|
entry string_pool_[Buffers];
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* va(const char* fmt, ...);
|
const char* va(const char* fmt, ...);
|
||||||
|
|
||||||
std::vector<std::string> split(const std::string& s, char delim);
|
std::vector<std::string> split(const std::string& s, char delim);
|
||||||
|
|
||||||
std::string to_lower(std::string text);
|
std::string to_lower(std::string text);
|
||||||
std::string to_upper(std::string text);
|
std::string to_upper(std::string text);
|
||||||
bool starts_with(const std::string& text, const std::string& substring);
|
bool starts_with(const std::string& text, const std::string& substring);
|
||||||
bool ends_with(const std::string& text, const std::string& substring);
|
bool ends_with(const std::string& text, const std::string& substring);
|
||||||
bool is_numeric(const std::string& text);
|
bool is_numeric(const std::string& text);
|
||||||
|
|
||||||
std::string dump_hex(const std::string& data, const std::string& separator = " ");
|
std::string dump_hex(const std::string& data, const std::string& separator = " ");
|
||||||
|
|
||||||
void strip(const char* in, char* out, int max);
|
void strip(const char* in, char* out, int max);
|
||||||
|
|
||||||
std::string convert(const std::wstring& wstr);
|
std::string convert(const std::wstring& wstr);
|
||||||
std::wstring convert(const std::string& str);
|
std::wstring convert(const std::string& str);
|
||||||
|
|
||||||
std::string replace(std::string str, const std::string& from, const std::string& to);
|
std::string replace(std::string str, const std::string& from, const std::string& to);
|
||||||
|
|
||||||
std::string get_timestamp();
|
std::string get_timestamp();
|
||||||
}
|
}
|
@ -1,89 +1,89 @@
|
|||||||
#include <stdinc.hpp>
|
#include <stdinc.hpp>
|
||||||
#include "thread.hpp"
|
#include "thread.hpp"
|
||||||
#include "string.hpp"
|
#include "string.hpp"
|
||||||
|
|
||||||
#include <TlHelp32.h>
|
#include <TlHelp32.h>
|
||||||
|
|
||||||
#include <gsl/gsl>
|
#include <gsl/gsl>
|
||||||
|
|
||||||
namespace utils::thread
|
namespace utils::thread
|
||||||
{
|
{
|
||||||
std::vector<DWORD> get_thread_ids()
|
std::vector<DWORD> get_thread_ids()
|
||||||
{
|
{
|
||||||
auto* const h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, GetCurrentProcessId());
|
auto* const h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, GetCurrentProcessId());
|
||||||
if (h == INVALID_HANDLE_VALUE)
|
if (h == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto _ = gsl::finally([h]()
|
const auto _ = gsl::finally([h]()
|
||||||
{
|
{
|
||||||
CloseHandle(h);
|
CloseHandle(h);
|
||||||
});
|
});
|
||||||
|
|
||||||
THREADENTRY32 entry{};
|
THREADENTRY32 entry{};
|
||||||
entry.dwSize = sizeof(entry);
|
entry.dwSize = sizeof(entry);
|
||||||
if (!Thread32First(h, &entry))
|
if (!Thread32First(h, &entry))
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<DWORD> ids{};
|
std::vector<DWORD> ids{};
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
const auto check_size = entry.dwSize < FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID)
|
const auto check_size = entry.dwSize < FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID)
|
||||||
+ sizeof(entry.th32OwnerProcessID);
|
+ sizeof(entry.th32OwnerProcessID);
|
||||||
entry.dwSize = sizeof(entry);
|
entry.dwSize = sizeof(entry);
|
||||||
|
|
||||||
if (check_size && entry.th32OwnerProcessID == GetCurrentProcessId())
|
if (check_size && entry.th32OwnerProcessID == GetCurrentProcessId())
|
||||||
{
|
{
|
||||||
ids.emplace_back(entry.th32ThreadID);
|
ids.emplace_back(entry.th32ThreadID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (Thread32Next(h, &entry));
|
while (Thread32Next(h, &entry));
|
||||||
|
|
||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
void for_each_thread(const std::function<void(HANDLE)>& callback)
|
void for_each_thread(const std::function<void(HANDLE)>& callback)
|
||||||
{
|
{
|
||||||
const auto ids = get_thread_ids();
|
const auto ids = get_thread_ids();
|
||||||
|
|
||||||
for (const auto& id : ids)
|
for (const auto& id : ids)
|
||||||
{
|
{
|
||||||
auto* const thread = OpenThread(THREAD_ALL_ACCESS, FALSE, id);
|
auto* const thread = OpenThread(THREAD_ALL_ACCESS, FALSE, id);
|
||||||
if (thread != nullptr)
|
if (thread != nullptr)
|
||||||
{
|
{
|
||||||
const auto _ = gsl::finally([thread]()
|
const auto _ = gsl::finally([thread]()
|
||||||
{
|
{
|
||||||
CloseHandle(thread);
|
CloseHandle(thread);
|
||||||
});
|
});
|
||||||
|
|
||||||
callback(thread);
|
callback(thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void suspend_other_threads()
|
void suspend_other_threads()
|
||||||
{
|
{
|
||||||
for_each_thread([](const HANDLE thread)
|
for_each_thread([](const HANDLE thread)
|
||||||
{
|
{
|
||||||
if (GetThreadId(thread) != GetCurrentThreadId())
|
if (GetThreadId(thread) != GetCurrentThreadId())
|
||||||
{
|
{
|
||||||
SuspendThread(thread);
|
SuspendThread(thread);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void resume_other_threads()
|
void resume_other_threads()
|
||||||
{
|
{
|
||||||
for_each_thread([](const HANDLE thread)
|
for_each_thread([](const HANDLE thread)
|
||||||
{
|
{
|
||||||
if (GetThreadId(thread) != GetCurrentThreadId())
|
if (GetThreadId(thread) != GetCurrentThreadId())
|
||||||
{
|
{
|
||||||
ResumeThread(thread);
|
ResumeThread(thread);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
namespace utils::thread
|
namespace utils::thread
|
||||||
{
|
{
|
||||||
template <typename ...Args>
|
template <typename ...Args>
|
||||||
std::thread create_named_thread(const std::string& name, Args&&... args)
|
std::thread create_named_thread(const std::string& name, Args&&... args)
|
||||||
{
|
{
|
||||||
auto t = std::thread(std::forward<Args>(args)...);
|
auto t = std::thread(std::forward<Args>(args)...);
|
||||||
set_name(t, name);
|
set_name(t, name);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<DWORD> get_thread_ids();
|
std::vector<DWORD> get_thread_ids();
|
||||||
void for_each_thread(const std::function<void(HANDLE)>& callback);
|
void for_each_thread(const std::function<void(HANDLE)>& callback);
|
||||||
|
|
||||||
void suspend_other_threads();
|
void suspend_other_threads();
|
||||||
void resume_other_threads();
|
void resume_other_threads();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user