diff --git a/src/filesystem.cpp b/src/filesystem.cpp index a7a2554..b54a7a7 100644 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -10,25 +10,30 @@ namespace filesystem { void create_nested_dirs(const char *path) { + if (!path || !*path) + return; + char temp_path[256]; - strncpy(temp_path, path, sizeof(temp_path)); + strncpy(temp_path, path, sizeof(temp_path) - 1); + temp_path[sizeof(temp_path) - 1] = '\0'; char *p = temp_path; - while (*p) + + // Skip leading drive letter (e.g., "C:\") or "game:\" prefix + if ((p[0] && p[1] == ':') || strncmp(p, "game:\\", 6) == 0) + p += (p[1] == ':' ? 3 : 6); // Move past "C:\" or "game:\" + + for (; *p; p++) { if (*p == '\\' || *p == '/') { *p = '\0'; - - // Create the directory if it doesn't exist - _mkdir(temp_path); - + _mkdir(temp_path); // Attempt to create the directory *p = '\\'; } - p++; } - _mkdir(temp_path); + _mkdir(temp_path); // Create final directory } /** diff --git a/src/game/mp_main.cpp b/src/game/mp_main.cpp index de6e6e6..fc5b724 100644 --- a/src/game/mp_main.cpp +++ b/src/game/mp_main.cpp @@ -45,6 +45,10 @@ namespace mp Cmd_AddCommandInternal_t Cmd_AddCommandInternal = reinterpret_cast(0x8223ADE0); Com_Printf_t Com_Printf = reinterpret_cast(0x82237000); + Com_PrintError_t Com_PrintError = reinterpret_cast(0x82235C50); + Com_PrintWarning_t Com_PrintWarning = reinterpret_cast(0x822356B8); + + DB_EnumXAssets_FastFile_t DB_EnumXAssets_FastFile = reinterpret_cast(0x8229ED48); Load_MapEntsPtr_t Load_MapEntsPtr = reinterpret_cast(0x822A9648); @@ -158,22 +162,8 @@ namespace mp char *Scr_ReadFile_FastFile_Hook(const char *filename, const char *extFilename, const char *codePos, bool archive) { - xbox::DbgPrint("Scr_ReadFile_FastFile_Hook extFilename=%s \n", extFilename); - auto contents = Scr_ReadFile_FastFile_Detour.GetOriginal()(filename, extFilename, codePos, archive); - - // Dump the file to disk if it exists - // It might not exist if it's not a stock file - if (contents != nullptr) - { - // Dump the file to disk - std::string file_path = "game:\\dump\\"; - file_path += extFilename; - std::replace(file_path.begin(), file_path.end(), '/', '\\'); // Replace forward slashes with backslashes - filesystem::write_file_to_disk(file_path.c_str(), contents, strlen(contents)); - } - std::string raw_file_path = "game:\\raw\\"; raw_file_path += extFilename; std::replace(raw_file_path.begin(), raw_file_path.end(), '/', '\\'); // Replace forward slashes with backslashes @@ -203,12 +193,56 @@ namespace mp } } - return contents; + return Scr_ReadFile_FastFile_Detour.GetOriginal()(filename, extFilename, codePos, archive); + } + + const unsigned int MAX_RAWFILES = 2048; + struct RawFileList + { + unsigned int count; + RawFile *files[MAX_RAWFILES]; + }; + + void R_AddRawFileToList(void *asset, void *inData) + { + RawFileList *rawFileList = reinterpret_cast(inData); + RawFile *rawFile = reinterpret_cast(asset); + + if (!rawFile) + { + Com_PrintError(CON_CHANNEL_ERROR, "R_AddRawFileToList: Null RawFile!\n"); + return; + } + + if (rawFileList->count >= MAX_RAWFILES) + { + Com_PrintError(CON_CHANNEL_ERROR, "R_AddRawFileToList: RawFileList is full!\n"); + return; + } + + rawFileList->files[rawFileList->count++] = rawFile; + } + + void R_GetRawFileList(RawFileList *rawFileList) + { + rawFileList->count = 0; + DB_EnumXAssets_FastFile(ASSET_TYPE_RAWFILE, R_AddRawFileToList, rawFileList, true); } - void Cmd_test_f() + void Cmd_rawfilesdump() { - xbox::DbgPrint("test command\n"); + RawFileList rawFileList; + R_GetRawFileList(&rawFileList); + + Com_Printf(CON_CHANNEL_CONSOLEONLY, "Dumping %d raw files to `raw\\` %d\n", rawFileList.count); + + for (unsigned int i = 0; i < rawFileList.count; i++) + { + auto rawfile = rawFileList.files[i]; + std::string asset_name = rawfile->name; + std::replace(asset_name.begin(), asset_name.end(), '/', '\\'); // Replace forward slashes with backslashes + filesystem::write_file_to_disk(("game:\\dump\\" + asset_name).c_str(), rawfile->buffer, rawfile->len); + } } void init() @@ -227,8 +261,7 @@ namespace mp Scr_ReadFile_FastFile_Detour = Detour(Scr_ReadFile_FastFile, Scr_ReadFile_FastFile_Hook); Scr_ReadFile_FastFile_Detour.Install(); - cmd_function_s *test_cmd = new cmd_function_s; - - Cmd_AddCommandInternal("test", Cmd_test_f, test_cmd); + cmd_function_s *rawfilesdump_VAR = new cmd_function_s; + Cmd_AddCommandInternal("rawfilesdump", Cmd_rawfilesdump, rawfilesdump_VAR); } } diff --git a/src/game/mp_structs.h b/src/game/mp_structs.h index e55935d..ffda4ed 100644 --- a/src/game/mp_structs.h +++ b/src/game/mp_structs.h @@ -2,7 +2,6 @@ namespace mp { - struct cmd_function_s { cmd_function_s *next; @@ -157,6 +156,118 @@ namespace mp int numEntityChars; }; + enum XAssetType : __int32 + { + ASSET_TYPE_XMODELPIECES = 0x0, + ASSET_TYPE_PHYSPRESET = 0x1, + ASSET_TYPE_XANIMPARTS = 0x2, + ASSET_TYPE_XMODEL = 0x3, + ASSET_TYPE_MATERIAL = 0x4, + ASSET_TYPE_PIXELSHADER = 0x5, + ASSET_TYPE_TECHNIQUE_SET = 0x6, + ASSET_TYPE_IMAGE = 0x7, + ASSET_TYPE_SOUND = 0x8, + ASSET_TYPE_SOUND_CURVE = 0x9, + ASSET_TYPE_LOADED_SOUND = 0xA, + ASSET_TYPE_CLIPMAP = 0xB, + ASSET_TYPE_CLIPMAP_PVS = 0xC, + ASSET_TYPE_COMWORLD = 0xD, + ASSET_TYPE_GAMEWORLD_SP = 0xE, + ASSET_TYPE_GAMEWORLD_MP = 0xF, + ASSET_TYPE_MAP_ENTS = 0x10, + ASSET_TYPE_GFXWORLD = 0x11, + ASSET_TYPE_LIGHT_DEF = 0x12, + ASSET_TYPE_UI_MAP = 0x13, + ASSET_TYPE_FONT = 0x14, + ASSET_TYPE_MENULIST = 0x15, + ASSET_TYPE_MENU = 0x16, + ASSET_TYPE_LOCALIZE_ENTRY = 0x17, + ASSET_TYPE_WEAPON = 0x18, + ASSET_TYPE_SNDDRIVER_GLOBALS = 0x19, + ASSET_TYPE_FX = 0x1A, + ASSET_TYPE_IMPACT_FX = 0x1B, + ASSET_TYPE_AITYPE = 0x1C, + ASSET_TYPE_MPTYPE = 0x1D, + ASSET_TYPE_CHARACTER = 0x1E, + ASSET_TYPE_XMODELALIAS = 0x1F, + ASSET_TYPE_RAWFILE = 0x20, + ASSET_TYPE_STRINGTABLE = 0x21, + ASSET_TYPE_COUNT = 0x22, + ASSET_TYPE_STRING = 0x22, + ASSET_TYPE_ASSETLIST = 0x23, + }; + + struct RawFile + { + const char *name; + int len; + const char *buffer; + }; + + union XAssetHeader + { + // XModelPieces *xmodelPieces; + // PhysPreset *physPreset; + // XAnimParts *parts; + // XModel *model; + // Material *material; + // MaterialPixelShader *pixelShader; + // MaterialVertexShader *vertexShader; + // MaterialTechniqueSet *techniqueSet; + // GfxImage *image; + // snd_alias_list_t *sound; + // SndCurve *sndCurve; + // LoadedSound *loadSnd; + // clipMap_t *clipMap; + // ComWorld *comWorld; + // GameWorldSp *gameWorldSp; + // GameWorldMp *gameWorldMp; + // MapEnts *mapEnts; + // GfxWorld *gfxWorld; + // GfxLightDef *lightDef; + // Font_s *font; + // MenuList *menuList; + // menuDef_t *menu; + // LocalizeEntry *localize; + // WeaponDef *weapon; + // SndDriverGlobals *sndDriverGlobals; + // const FxEffectDef *fx; + // FxImpactTable *impactFx; + RawFile *rawfile; + // StringTable *stringTable; + void *data; + }; + + enum conChannel_t : __int32 + { + CON_CHANNEL_DONT_FILTER = 0x0, + CON_CHANNEL_ERROR = 0x1, + CON_CHANNEL_GAMENOTIFY = 0x2, + CON_CHANNEL_BOLDGAME = 0x3, + CON_CHANNEL_SUBTITLE = 0x4, + CON_CHANNEL_OBITUARY = 0x5, + CON_CHANNEL_LOGFILEONLY = 0x6, + CON_CHANNEL_CONSOLEONLY = 0x7, + CON_CHANNEL_GFX = 0x8, + CON_CHANNEL_SOUND = 0x9, + CON_CHANNEL_FILES = 0xA, + CON_CHANNEL_DEVGUI = 0xB, + CON_CHANNEL_PROFILE = 0xC, + CON_CHANNEL_UI = 0xD, + CON_CHANNEL_CLIENT = 0xE, + CON_CHANNEL_SERVER = 0xF, + CON_CHANNEL_SYSTEM = 0x10, + CON_CHANNEL_PLAYERWEAP = 0x11, + CON_CHANNEL_AI = 0x12, + CON_CHANNEL_ANIM = 0x13, + CON_CHANNEL_PHYS = 0x14, + CON_CHANNEL_FX = 0x15, + CON_CHANNEL_LEADERBOARDS = 0x16, + CON_CHANNEL_PARSERSCRIPT = 0x17, + CON_CHANNEL_SCRIPT = 0x18, + CON_BUILTIN_CHANNEL_COUNT = 0x19, + }; + typedef void (*Cbuf_AddText_t)(int localClientNum, const char *text); typedef void (*CL_ConsolePrint_t)(int localClientNum, int channel, const char *txt, int duration, int pixelWidth, int flags); @@ -164,7 +275,12 @@ namespace mp typedef void (*Cmd_AddCommandInternal_t)(const char *cmdName, void (*function)(), cmd_function_s *allocedCmd); - typedef void (*Com_Printf_t)(int channel, const char *fmt, ...); + typedef void (*Com_PrintError_t)(conChannel_t channel, const char *fmt, ...); + typedef void (*Com_PrintMessage_t)(conChannel_t channel, const char *msg, int error); + typedef void (*Com_Printf_t)(conChannel_t channel, const char *fmt, ...); + typedef void (*Com_PrintWarning_t)(conChannel_t channel, const char *fmt, ...); + + typedef void (*DB_EnumXAssets_FastFile_t)(XAssetType type, void (*func)(void *asset, void *inData), void *inData, bool includeOverride); typedef void (*Load_MapEntsPtr_t)(); diff --git a/src/game/sp_main.cpp b/src/game/sp_main.cpp index 4e98e64..d0673a1 100644 --- a/src/game/sp_main.cpp +++ b/src/game/sp_main.cpp @@ -44,7 +44,11 @@ namespace sp Cmd_AddCommandInternal_t Cmd_AddCommandInternal = reinterpret_cast(0x821DFAD0); + Com_PrintError_t Com_PrintError = reinterpret_cast(0x821DAC90); Com_Printf_t Com_Printf = reinterpret_cast(0x821DC0A0); + Com_PrintWarning_t Com_PrintWarning = reinterpret_cast(0x821DA798); + + DB_EnumXAssets_FastFile_t DB_EnumXAssets_FastFile = reinterpret_cast(0x822AEF88); Scr_AddSourceBuffer_t Scr_AddSourceBuffer = reinterpret_cast(0x821C5A18); Scr_ReadFile_FastFile_t Scr_ReadFile_FastFile = reinterpret_cast(0x821C5978); @@ -89,19 +93,6 @@ namespace sp { xbox::DbgPrint("Scr_ReadFile_FastFile_Hook extFilename=%s \n", extFilename); - auto contents = Scr_ReadFile_FastFile_Detour.GetOriginal()(filename, extFilename, codePos, archive); - - // Dump the file to disk if it exists - // It might not exist if it's not a stock file - if (contents != nullptr) - { - // Dump the file to disk - std::string file_path = "game:\\dump\\"; - file_path += extFilename; - std::replace(file_path.begin(), file_path.end(), '/', '\\'); // Replace forward slashes with backslashes - filesystem::write_file_to_disk(file_path.c_str(), contents, strlen(contents)); - } - std::string raw_file_path = "game:\\raw\\"; raw_file_path += extFilename; std::replace(raw_file_path.begin(), raw_file_path.end(), '/', '\\'); // Replace forward slashes with backslashes @@ -131,12 +122,56 @@ namespace sp } } - return contents; + return Scr_ReadFile_FastFile_Detour.GetOriginal()(filename, extFilename, codePos, archive); } - void Cmd_test_f() + const unsigned int MAX_RAWFILES = 2048; + struct RawFileList + { + unsigned int count; + RawFile *files[MAX_RAWFILES]; + }; + + void R_AddRawFileToList(void *asset, void *inData) { - xbox::DbgPrint("test command\n"); + RawFileList *rawFileList = reinterpret_cast(inData); + RawFile *rawFile = reinterpret_cast(asset); + + if (!rawFile) + { + Com_PrintError(CON_CHANNEL_ERROR, "R_AddRawFileToList: Null RawFile!\n"); + return; + } + + if (rawFileList->count >= MAX_RAWFILES) + { + Com_PrintError(CON_CHANNEL_ERROR, "R_AddRawFileToList: RawFileList is full!\n"); + return; + } + + rawFileList->files[rawFileList->count++] = rawFile; + } + + void R_GetRawFileList(RawFileList *rawFileList) + { + rawFileList->count = 0; + DB_EnumXAssets_FastFile(ASSET_TYPE_RAWFILE, R_AddRawFileToList, rawFileList, true); + } + + void Cmd_rawfilesdump() + { + RawFileList rawFileList; + R_GetRawFileList(&rawFileList); + + Com_Printf(CON_CHANNEL_CONSOLEONLY, "Dumping %d raw files to `raw\\` %d\n", rawFileList.count); + + for (unsigned int i = 0; i < rawFileList.count; i++) + { + auto rawfile = rawFileList.files[i]; + std::string asset_name = rawfile->name; + std::replace(asset_name.begin(), asset_name.end(), '/', '\\'); // Replace forward slashes with backslashes + filesystem::write_file_to_disk(("game:\\dump\\" + asset_name).c_str(), rawfile->buffer, rawfile->len); + } } void init() @@ -152,8 +187,7 @@ namespace sp Scr_ReadFile_FastFile_Detour = Detour(Scr_ReadFile_FastFile, Scr_ReadFile_FastFile_Hook); Scr_ReadFile_FastFile_Detour.Install(); - cmd_function_s *test_cmd = new cmd_function_s; - - Cmd_AddCommandInternal("test", Cmd_test_f, test_cmd); + cmd_function_s *rawfilesdump_VAR = new cmd_function_s; + Cmd_AddCommandInternal("rawfilesdump", Cmd_rawfilesdump, rawfilesdump_VAR); } } diff --git a/src/game/sp_structs.h b/src/game/sp_structs.h index 5553ac2..6a95cf5 100644 --- a/src/game/sp_structs.h +++ b/src/game/sp_structs.h @@ -149,6 +149,118 @@ namespace sp void(__fastcall *function)(); }; + enum XAssetType : __int32 + { + ASSET_TYPE_XMODELPIECES = 0x0, + ASSET_TYPE_PHYSPRESET = 0x1, + ASSET_TYPE_XANIMPARTS = 0x2, + ASSET_TYPE_XMODEL = 0x3, + ASSET_TYPE_MATERIAL = 0x4, + ASSET_TYPE_PIXELSHADER = 0x5, + ASSET_TYPE_TECHNIQUE_SET = 0x6, + ASSET_TYPE_IMAGE = 0x7, + ASSET_TYPE_SOUND = 0x8, + ASSET_TYPE_SOUND_CURVE = 0x9, + ASSET_TYPE_LOADED_SOUND = 0xA, + ASSET_TYPE_CLIPMAP = 0xB, + ASSET_TYPE_CLIPMAP_PVS = 0xC, + ASSET_TYPE_COMWORLD = 0xD, + ASSET_TYPE_GAMEWORLD_SP = 0xE, + ASSET_TYPE_GAMEWORLD_MP = 0xF, + ASSET_TYPE_MAP_ENTS = 0x10, + ASSET_TYPE_GFXWORLD = 0x11, + ASSET_TYPE_LIGHT_DEF = 0x12, + ASSET_TYPE_UI_MAP = 0x13, + ASSET_TYPE_FONT = 0x14, + ASSET_TYPE_MENULIST = 0x15, + ASSET_TYPE_MENU = 0x16, + ASSET_TYPE_LOCALIZE_ENTRY = 0x17, + ASSET_TYPE_WEAPON = 0x18, + ASSET_TYPE_SNDDRIVER_GLOBALS = 0x19, + ASSET_TYPE_FX = 0x1A, + ASSET_TYPE_IMPACT_FX = 0x1B, + ASSET_TYPE_AITYPE = 0x1C, + ASSET_TYPE_MPTYPE = 0x1D, + ASSET_TYPE_CHARACTER = 0x1E, + ASSET_TYPE_XMODELALIAS = 0x1F, + ASSET_TYPE_RAWFILE = 0x20, + ASSET_TYPE_STRINGTABLE = 0x21, + ASSET_TYPE_COUNT = 0x22, + ASSET_TYPE_STRING = 0x22, + ASSET_TYPE_ASSETLIST = 0x23, + }; + + struct RawFile + { + const char *name; + int len; + const char *buffer; + }; + + union XAssetHeader + { + // XModelPieces *xmodelPieces; + // PhysPreset *physPreset; + // XAnimParts *parts; + // XModel *model; + // Material *material; + // MaterialPixelShader *pixelShader; + // MaterialVertexShader *vertexShader; + // MaterialTechniqueSet *techniqueSet; + // GfxImage *image; + // snd_alias_list_t *sound; + // SndCurve *sndCurve; + // LoadedSound *loadSnd; + // clipMap_t *clipMap; + // ComWorld *comWorld; + // GameWorldSp *gameWorldSp; + // GameWorldMp *gameWorldMp; + // MapEnts *mapEnts; + // GfxWorld *gfxWorld; + // GfxLightDef *lightDef; + // Font_s *font; + // MenuList *menuList; + // menuDef_t *menu; + // LocalizeEntry *localize; + // WeaponDef *weapon; + // SndDriverGlobals *sndDriverGlobals; + // const FxEffectDef *fx; + // FxImpactTable *impactFx; + RawFile *rawfile; + // StringTable *stringTable; + void *data; + }; + + enum conChannel_t : __int32 + { + CON_CHANNEL_DONT_FILTER = 0x0, + CON_CHANNEL_ERROR = 0x1, + CON_CHANNEL_GAMENOTIFY = 0x2, + CON_CHANNEL_BOLDGAME = 0x3, + CON_CHANNEL_SUBTITLE = 0x4, + CON_CHANNEL_OBITUARY = 0x5, + CON_CHANNEL_LOGFILEONLY = 0x6, + CON_CHANNEL_CONSOLEONLY = 0x7, + CON_CHANNEL_GFX = 0x8, + CON_CHANNEL_SOUND = 0x9, + CON_CHANNEL_FILES = 0xA, + CON_CHANNEL_DEVGUI = 0xB, + CON_CHANNEL_PROFILE = 0xC, + CON_CHANNEL_UI = 0xD, + CON_CHANNEL_CLIENT = 0xE, + CON_CHANNEL_SERVER = 0xF, + CON_CHANNEL_SYSTEM = 0x10, + CON_CHANNEL_PLAYERWEAP = 0x11, + CON_CHANNEL_AI = 0x12, + CON_CHANNEL_ANIM = 0x13, + CON_CHANNEL_PHYS = 0x14, + CON_CHANNEL_FX = 0x15, + CON_CHANNEL_LEADERBOARDS = 0x16, + CON_CHANNEL_PARSERSCRIPT = 0x17, + CON_CHANNEL_SCRIPT = 0x18, + CON_BUILTIN_CHANNEL_COUNT = 0x19, + }; + typedef void (*Cbuf_AddText_t)(int localClientNum, const char *text); typedef void (*CL_ConsolePrint_t)(int localClientNum, int channel, const char *txt, int duration, int pixelWidth, int flags); @@ -156,7 +268,12 @@ namespace sp typedef void (*Cmd_AddCommandInternal_t)(const char *cmdName, void (*function)(), cmd_function_s *allocedCmd); - typedef void (*Com_Printf_t)(int channel, const char *fmt, ...); + typedef void (*Com_PrintError_t)(conChannel_t channel, const char *fmt, ...); + typedef void (*Com_PrintMessage_t)(conChannel_t channel, const char *msg, int error); + typedef void (*Com_Printf_t)(conChannel_t channel, const char *fmt, ...); + typedef void (*Com_PrintWarning_t)(conChannel_t channel, const char *fmt, ...); + + typedef void (*DB_EnumXAssets_FastFile_t)(XAssetType type, void (*func)(void *asset, void *inData), void *inData, bool includeOverride); typedef char *(*Scr_AddSourceBuffer_t)(const char *filename, const char *extFilename, const char *codePos, bool archive); typedef char *(*Scr_ReadFile_FastFile_t)(const char *filename, const char *extFilename, const char *codePos, bool archive);