fix line endings and tabs

This commit is contained in:
ineed bots 2023-09-01 10:50:11 -06:00
parent b17a56a7fd
commit bb216441bf
40 changed files with 22114 additions and 22115 deletions

View File

@ -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

View File

@ -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

View File

@ -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;
} }
} }

View File

@ -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);
} }
} }

View File

@ -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)

View File

@ -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)

View File

@ -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);
} }

View File

@ -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)

View File

@ -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;
} }

View File

@ -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);
} }
} }

View File

@ -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);
} }

File diff suppressed because it is too large Load Diff

View File

@ -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
{ {
} }
} }

View File

@ -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_;
}; };
} }

File diff suppressed because it is too large Load Diff

View File

@ -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};
} }
} }

View File

@ -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;
} }
}; };

View File

@ -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;
} }

View File

@ -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; \
} }

View File

@ -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;

View File

@ -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;
} }
} }
} }

View File

@ -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_;
}; };
} }
}; };

View File

@ -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_{};
}; };
} }

View File

@ -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;
} }
} }

View File

@ -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);
} }

View File

@ -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

View File

@ -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); }
}
} }

View File

@ -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...);
} }
} }

View File

@ -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);
}); });
} }
} }

View File

@ -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 = {});
} }

View File

@ -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);
} }
} }

View File

@ -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);
} }

View File

@ -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_;
} }
} }

View File

@ -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_;
}; };
} }

View File

@ -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(&ltime, &time); _localtime64_s(&ltime, &time);
strftime(timestamp, sizeof(timestamp) - 1, "%Y-%m-%d-%H-%M-%S", &ltime); strftime(timestamp, sizeof(timestamp) - 1, "%Y-%m-%d-%H-%M-%S", &ltime);
return timestamp; return timestamp;
} }
} }

View File

@ -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();
} }

View File

@ -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);
} }
}); });
} }
} }

View File

@ -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();
} }