/* ================ SV_EntityScript get entity script for current map ================ */ char *SV_EntityScript( void ) { string entfilename; char *ents; size_t ft1, ft2; if( !sv.worldmodel ) return NULL; // check for entfile too Q_strncpy( entfilename, sv.worldmodel->name, sizeof( entfilename )); FS_StripExtension( entfilename ); FS_DefaultExtension( entfilename, ".ent" ); // make sure what entity patch is never than bsp ft1 = FS_FileTime( sv.worldmodel->name, false ); ft2 = FS_FileTime( entfilename, true ); if( ft2 != -1 ) { if( ft1 > ft2 ) { MsgDev( D_INFO, "^1Entity patch is older than BSP. Ignored.\n", entfilename ); } else if(( ents = FS_LoadFile( entfilename, NULL, true )) != NULL ) { MsgDev( D_INFO, "^2Read entity patch:^7 %s\n", entfilename ); return ents; } } // use internal entities return sv.worldmodel->entities; }
qboolean HPAK_ResourceForIndex( const char *filename, int index, resource_t *pRes ) { file_t *f; hpak_header_t hdr; hpak_container_t hpakcontainer; string pakname; if( !filename || !filename[0] ) return false; Q_strncpy( pakname, filename, sizeof( pakname )); FS_StripExtension( pakname ); FS_DefaultExtension( pakname, ".hpk" ); f = FS_Open( pakname, "rb", false ); FS_Read( f, &hdr, sizeof( hdr )); if( hdr.ident != IDCUSTOMHEADER ) { MsgDev( D_ERROR, "HPAK_ResourceForIndex: %s it's not a HPK file.\n", pakname ); FS_Close( f ); return false; } if( hdr.version != IDCUSTOM_VERSION ) { MsgDev( D_ERROR, "HPAK_ResourceForIndex: %s has invalid version (%i should be %i).\n", pakname, hdr.version, IDCUSTOM_VERSION ); FS_Close( f ); return false; } FS_Seek( f, hdr.seek, SEEK_SET ); FS_Read( f, &hpakcontainer.count, sizeof( hpakcontainer.count )); if( hpakcontainer.count < 1 || hpakcontainer.count > MAX_FILES_IN_WAD ) { MsgDev( D_ERROR, "HPAK_ResourceForIndex: %s has too many lumps %u.\n", pakname, hpakcontainer.count ); FS_Close( f ); return false; } if( index < 1 || index > hpakcontainer.count ) { MsgDev( D_ERROR, "HPAK_ResourceForIndex: %s, lump with index %i doesn't exist.\n", pakname, index ); FS_Close( f ); return false; } hpakcontainer.dirs = Z_Malloc( sizeof( hpak_dir_t ) * hpakcontainer.count ); // we could just seek the right data... FS_Read( f, hpakcontainer.dirs, sizeof( hpak_dir_t ) * hpakcontainer.count ); *pRes = hpakcontainer.dirs[index-1].DirectoryResource; Mem_Free( hpakcontainer.dirs ); FS_Close( f ); return true; }
/* ===================================== Cmd_GetSoundList Prints or complete sound filename ===================================== */ qboolean Cmd_GetSoundList( const char *s, char *completedname, int length ) { search_t *t; string matchbuf; int i, numsounds; const char *snddir = "sound/"; // constant t = FS_Search( va( "%s%s*.*", snddir, s ), true, false ); if( !t ) return false; Q_strncpy( matchbuf, t->filenames[0] + Q_strlen( snddir ), MAX_STRING ); FS_StripExtension( matchbuf ); if( completedname && length ) Q_strncpy( completedname, matchbuf, length ); if( t->numfilenames == 1 ) return true; for(i = 0, numsounds = 0; i < t->numfilenames; i++) { const char *ext = FS_FileExtension( t->filenames[i] ); if( !Q_stricmp( ext, "wav" ) || !Q_stricmp( ext, "mp3" )); else continue; Q_strncpy( matchbuf, t->filenames[i] + Q_strlen(snddir), MAX_STRING ); FS_StripExtension( matchbuf ); Msg( "%16s\n", matchbuf ); numsounds++; } Msg( "\n^3 %i sounds found.\n", numsounds ); Mem_Free( t ); // cut shortestMatch to the amount common with s if( completedname && length ) { for( i = 0; matchbuf[i]; i++ ) { if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) completedname[i] = 0; } } return true; }
void HPAK_CheckIntegrity( const char *filename ) { string pakname; if( !filename || !filename[0] ) return; Q_strncpy( pakname, filename, sizeof( pakname )); FS_StripExtension( pakname ); FS_DefaultExtension( pakname, ".hpk" ); HPAK_ValidatePak( pakname ); }
/* ==================== CL_UpdateTexture Update texture top and bottom colors ==================== */ void CL_UpdateTexture( mstudiotexture_t *ptexture, int topcolor, int bottomcolor ) { gltexture_t *glt; rgbdata_t *pic; texture_t *tx = NULL; char texname[128], name[128], mdlname[128]; int i, index; size_t size; byte paletteBackup[768]; byte *raw, *pal; // save of the real texture index glt = R_GetTexture( ptexture->index ); // build name of original texture Q_strncpy( mdlname, RI.currentmodel->name, sizeof( mdlname )); FS_FileBase( ptexture->name, name ); FS_StripExtension( mdlname ); Q_snprintf( texname, sizeof( texname ), "#%s/%s.mdl", mdlname, name ); index = GL_FindTexture( texname ); if( !index ) return; // couldn't find texture // search for pixels for( i = 0; i < RI.currentmodel->numtextures; i++ ) { tx = RI.currentmodel->textures[i]; if( tx->gl_texturenum == index ) break; // found } ASSERT( tx != NULL ); // backup original palette pal = (byte *)(tx + 1) + (tx->width * tx->height); Q_memcpy( paletteBackup, pal, 768 ); raw = CL_CreateRawTextureFromPixels( tx, &size, topcolor, bottomcolor ); pic = FS_LoadImage( glt->name, raw, size ); if( !pic ) { MsgDev( D_ERROR, "Couldn't update texture %s\n", glt->name ); return; } index = GL_LoadTextureInternal( glt->name, pic, 0, true ); FS_FreeImage( pic ); // restore original palette Q_memcpy( pal, paletteBackup, 768 ); ASSERT( index == ptexture->index ); }
void HPAK_CheckSize( const char *filename ) { string pakname; int maxsize; maxsize = hpk_maxsize->integer; if( maxsize <= 0 ) return; if( !filename || !filename[0] ) return; Q_strncpy( pakname, filename, sizeof( pakname )); FS_StripExtension( pakname ); FS_DefaultExtension( pakname, ".hpk" ); if( FS_FileSize( pakname, false ) > ( maxsize * 1000000 )) MsgDev( D_ERROR, "HPAK_CheckSize: %s is too large.\n", filename ); }
/* ================ FS_OpenStream open and reading basic info from sound stream ================ */ stream_t *FS_OpenStream( const char *filename ) { const char *ext = FS_FileExtension( filename ); string path, loadname; qboolean anyformat = true; const streamfmt_t *format; stream_t *stream; Sound_Reset(); // clear old streaminfo Q_strncpy( loadname, filename, sizeof( loadname )); if( Q_stricmp( ext, "" )) { // we needs to compare file extension with list of supported formats // and be sure what is real extension, not a filename with dot for( format = sound.streamformat; format && format->formatstring; format++ ) { if( !Q_stricmp( format->ext, ext )) { FS_StripExtension( loadname ); anyformat = false; break; } } } // now try all the formats in the selected list for( format = sound.streamformat; format && format->formatstring; format++) { if( anyformat || !Q_stricmp( ext, format->ext )) { Q_sprintf( path, format->formatstring, loadname, "", format->ext ); if(( stream = format->openfunc( path )) != NULL ) { stream->format = format; return stream; // done } } } if( !sound.streamformat || sound.streamformat->ext == NULL ) MsgDev( D_NOTE, "FS_OpenStream: soundlib offline\n" ); else MsgDev( D_NOTE, "FS_OpenStream: couldn't open \"%s\"\n", loadname ); return NULL; }
void R_NewMap( void ) { texture_t *tx; int i; R_ClearDecals(); // clear all level decals // upload detailtextures if( r_detailtextures->integer ) { string mapname, filepath; Q_strncpy( mapname, cl.worldmodel->name, sizeof( mapname )); FS_StripExtension( mapname ); Q_sprintf( filepath, "%s_detail.txt", mapname ); R_ParseDetailTextures( filepath ); } // clear out efrags in case the level hasn't been reloaded for( i = 0; i < cl.worldmodel->numleafs; i++ ) cl.worldmodel->leafs[i+1].efrags = NULL; tr.skytexturenum = -1; r_viewleaf = r_oldviewleaf = NULL; // clearing texture chains for( i = 0; i < cl.worldmodel->numtextures; i++ ) { if( !cl.worldmodel->textures[i] ) continue; tx = cl.worldmodel->textures[i]; if( !Q_strncmp( tx->name, "sky", 3 ) && tx->width == 256 && tx->height == 128) tr.skytexturenum = i; tx->texturechain = NULL; } R_SetupSky( cl.refdef.movevars->skyName ); GL_BuildLightmaps (); R_GenerateVBO(); }
/* ==================== SV_Record_f record <demoname> ==================== */ void SV_MVD_Record_f (void) { int c; char name[MAX_OSPATH+MAX_MVD_NAME]; char newname[MAX_MVD_NAME]; dir_t dir; c = Cmd_Argc(); if (c != 2) { Com_Printf ("mvdrecord <demoname>\n"); return; } if (sv.state != ss_game){ Com_Printf ("Not active yet.\n"); return; } dir = Sys_listdir(va("%s/%s", fs_gamedir, sv_demoDir.string), ".*", false); if (sv_demoMaxDirSize.value && dir.size > sv_demoMaxDirSize.value*1024) { Com_Printf("insufficient directory space, increase sv_demoMaxDirSize\n"); return; } Q_strncpyz(newname, va("%s%s", sv_demoPrefix.string, SV_CleanName(Cmd_Argv(1))), sizeof(newname) - strlen(sv_demoSuffix.string) - 5); Q_strncatz(newname, sv_demoSuffix.string, MAX_MVD_NAME); _snprintf (name, MAX_OSPATH+MAX_MVD_NAME, "%s/%s/%s", fs_gamedir, sv_demoDir.string, newname); FS_StripExtension(name, name, sizeof(name)); FS_DefaultExtension(name, ".mvd", sizeof(name)); // FS_CreatePath(name); // // open the demo file and start recording // SV_MVD_Record (SV_InitRecordFile(name)); }
/* ================= WriteSurfaceExtraFile writes out a surface info file (<map>.srf) ================= */ void WriteSurfaceExtraFile( const char *path ) { char srfPath[MAX_SYSPATH]; file_t *sf; surfaceExtra_t *se; int i; if( path == NULL || path[0] == '\0' ) return; MsgDev( D_NOTE, "--- WriteSurfaceExtraFile ---\n" ); com.snprintf( srfPath, sizeof( srfPath ), "maps/%s", path ); FS_StripExtension( srfPath ); FS_DefaultExtension( srfPath, ".srf" ); Msg( "Writing %s\n", srfPath ); sf = FS_Open( srfPath, "w" ); if( !sf ) Sys_Error( "Error opening %s for writing", srfPath ); for( i = -1; i < numSurfaceExtras; i++ ) { se = GetSurfaceExtra( i ); if( i < 0 ) FS_Printf( sf, "default" ); else FS_Printf( sf, "%d", i ); if( se->mds == NULL ) FS_Printf( sf, "\n" ); else { FS_Printf( sf, " // %s V: %d I: %d %s\n", surfaceTypes[se->mds->type], se->mds->numVerts, se->mds->numIndexes, (se->mds->planar ? "planar" : "")); } FS_Printf( sf, "{\n" ); if( se->si != NULL ) FS_Printf( sf, "\tshader %s\n", se->si->shader ); if( se->parentSurfaceNum != seDefault.parentSurfaceNum ) FS_Printf( sf, "\tparent %d\n", se->parentSurfaceNum ); if( se->entityNum != seDefault.entityNum ) FS_Printf( sf, "\tentity %d\n", se->entityNum ); if( se->castShadows != seDefault.castShadows || se == &seDefault ) FS_Printf( sf, "\tcastShadows %d\n", se->castShadows ); if( se->recvShadows != seDefault.recvShadows || se == &seDefault ) FS_Printf( sf, "\treceiveShadows %d\n", se->recvShadows ); if( se->sampleSize != seDefault.sampleSize || se == &seDefault ) FS_Printf( sf, "\tsampleSize %d\n", se->sampleSize ); if( se->longestCurve != seDefault.longestCurve || se == &seDefault ) FS_Printf( sf, "\tlongestCurve %f\n", se->longestCurve ); if( VectorCompare( se->lightmapAxis, seDefault.lightmapAxis ) == false ) FS_Printf( sf, "\tlightmapAxis ( %f %f %f )\n", se->lightmapAxis[0], se->lightmapAxis[1], se->lightmapAxis[2] ); FS_Printf( sf, "}\n\n" ); } FS_Close( sf ); }
qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir ) { byte buf[MAX_SYSPATH]; char *buffer; string result; int i, size; search_t *t; file_t *f; if( FS_FileSize( "maps.lst", onlyingamedir ) > 0 && !fRefresh ) { MsgDev( D_NOTE, "maps.lst is exist: %s\n", onlyingamedir ? "basedir" : "gamedir" ); return true; // exist } t = FS_Search( "maps/*.bsp", false, onlyingamedir ); if( !t ) { if( onlyingamedir ) { // mod doesn't contain any maps (probably this is a bot) return Cmd_CheckMapsList_R( fRefresh, false ); } return false; } buffer = Mem_Alloc( host.mempool, t->numfilenames * 2 * sizeof( result )); for( i = 0; i < t->numfilenames; i++ ) { char *ents = NULL, *pfile; int ver = -1, lumpofs = 0, lumplen = 0; string mapname, message, entfilename; const char *ext = FS_FileExtension( t->filenames[i] ); if( Q_stricmp( ext, "bsp" )) continue; f = FS_Open( t->filenames[i], "rb", onlyingamedir ); FS_FileBase( t->filenames[i], mapname ); if( f ) { int num_spawnpoints = 0; dheader_t *header; Q_memset( buf, 0, MAX_SYSPATH ); FS_Read( f, buf, MAX_SYSPATH ); ver = *(uint *)buf; switch( ver ) { case Q1BSP_VERSION: case HLBSP_VERSION: case XTBSP_VERSION: header = (dheader_t *)buf; if( header->lumps[LUMP_ENTITIES].fileofs <= 1024 ) { lumpofs = header->lumps[LUMP_PLANES].fileofs; lumplen = header->lumps[LUMP_PLANES].filelen; } else { lumpofs = header->lumps[LUMP_ENTITIES].fileofs; lumplen = header->lumps[LUMP_ENTITIES].filelen; } break; } Q_strncpy( entfilename, t->filenames[i], sizeof( entfilename )); FS_StripExtension( entfilename ); FS_DefaultExtension( entfilename, ".ent" ); ents = FS_LoadFile( entfilename, NULL, true ); if( !ents && lumplen >= 10 ) { FS_Seek( f, lumpofs, SEEK_SET ); ents = (char *)Mem_Alloc( host.mempool, lumplen + 1 ); FS_Read( f, ents, lumplen ); } if( ents ) { // if there are entities to parse, a missing message key just // means there is no title, so clear the message string now char token[2048]; qboolean worldspawn = true; Q_strncpy( message, "No Title", MAX_STRING ); pfile = ents; while(( pfile = COM_ParseFile( pfile, token )) != NULL ) { if( token[0] == '}' && worldspawn ) worldspawn = false; else if( !Q_strcmp( token, "message" ) && worldspawn ) { // get the message contents pfile = COM_ParseFile( pfile, message ); } else if( !Q_strcmp( token, "classname" )) { pfile = COM_ParseFile( pfile, token ); if( !Q_strcmp( token, GI->mp_entity )) num_spawnpoints++; } if( num_spawnpoints ) break; // valid map } Mem_Free( ents ); } if( f ) FS_Close( f ); if( num_spawnpoints ) { // format: mapname "maptitle"\n Q_sprintf( result, "%s \"%s\"\n", mapname, message ); Q_strcat( buffer, result ); // add new string } } } if( t ) Mem_Free( t ); // free search result size = Q_strlen( buffer ); if( !size ) { if( buffer ) Mem_Free( buffer ); if( onlyingamedir ) return Cmd_CheckMapsList_R( fRefresh, false ); return false; } // write generated maps.lst if( FS_WriteFile( "maps.lst", buffer, Q_strlen( buffer ))) { if( buffer ) Mem_Free( buffer ); return true; } return false; }
/* ===================================== Cmd_GetMapList Prints or complete map filename ===================================== */ qboolean Cmd_GetMapList( const char *s, char *completedname, int length ) { search_t *t; file_t *f; string message; string matchbuf; byte buf[MAX_SYSPATH]; // 1 kb int i, nummaps; t = FS_Search( va( "maps/%s*.bsp", s ), true, con_gamemaps->integer ); if( !t ) return false; FS_FileBase( t->filenames[0], matchbuf ); Q_strncpy( completedname, matchbuf, length ); if( t->numfilenames == 1 ) return true; for( i = 0, nummaps = 0; i < t->numfilenames; i++ ) { char entfilename[CS_SIZE]; int ver = -1, mapver = -1, lumpofs = 0, lumplen = 0; const char *ext = FS_FileExtension( t->filenames[i] ); char *ents = NULL, *pfile; qboolean paranoia = false; qboolean gearbox = false; if( Q_stricmp( ext, "bsp" )) continue; Q_strncpy( message, "^1error^7", sizeof( message )); f = FS_Open( t->filenames[i], "rb", con_gamemaps->integer ); if( f ) { dheader_t *header; dextrahdr_t *hdrext; Q_memset( buf, 0, sizeof( buf )); FS_Read( f, buf, sizeof( buf )); header = (dheader_t *)buf; ver = header->version; switch( ver ) { case Q1BSP_VERSION: case HLBSP_VERSION: case XTBSP_VERSION: if( header->lumps[LUMP_ENTITIES].fileofs <= 1024 && !(header->lumps[LUMP_ENTITIES].filelen % sizeof(dplane_t))) { lumpofs = header->lumps[LUMP_PLANES].fileofs; lumplen = header->lumps[LUMP_PLANES].filelen; gearbox = true; } else { lumpofs = header->lumps[LUMP_ENTITIES].fileofs; lumplen = header->lumps[LUMP_ENTITIES].filelen; gearbox = false; } break; } if( ver == XTBSP_VERSION ) hdrext = (dextrahdr_t *)((byte *)buf + sizeof( dheader31_t )); else hdrext = (dextrahdr_t *)((byte *)buf + sizeof( dheader_t )); if( hdrext->id == IDEXTRAHEADER && hdrext->version == EXTRA_VERSION ) paranoia = true; Q_strncpy( entfilename, t->filenames[i], sizeof( entfilename )); FS_StripExtension( entfilename ); FS_DefaultExtension( entfilename, ".ent" ); ents = FS_LoadFile( entfilename, NULL, true ); if( !ents && lumplen >= 10 ) { FS_Seek( f, lumpofs, SEEK_SET ); ents = (char *)Mem_Alloc( host.mempool, lumplen + 1 ); FS_Read( f, ents, lumplen ); } if( ents ) { // if there are entities to parse, a missing message key just // means there is no title, so clear the message string now char token[2048]; message[0] = 0; pfile = ents; while(( pfile = COM_ParseFile( pfile, token )) != NULL ) { if( !Q_strcmp( token, "{" )) continue; else if(!Q_strcmp( token, "}" )) break; else if(!Q_strcmp( token, "message" )) { // get the message contents pfile = COM_ParseFile( pfile, message ); } else if(!Q_strcmp( token, "mapversion" )) { // get the message contents pfile = COM_ParseFile( pfile, token ); mapver = Q_atoi( token ); } } Mem_Free( ents ); } } if( f ) FS_Close(f); FS_FileBase( t->filenames[i], matchbuf ); switch( ver ) { case Q1BSP_VERSION: if( mapver == 220 ) Q_strncpy( buf, "Half-Life Alpha", sizeof( buf )); else Q_strncpy( buf, "Quake", sizeof( buf )); break; case HLBSP_VERSION: if( gearbox ) Q_strncpy( buf, "Blue-Shift", sizeof( buf )); else if( paranoia ) Q_strncpy( buf, "Paranoia 2", sizeof( buf )); else Q_strncpy( buf, "Half-Life", sizeof( buf )); break; case XTBSP_VERSION: if( paranoia ) Q_strncpy( buf, "Paranoia 2", sizeof( buf )); else Q_strncpy( buf, "Xash3D", sizeof( buf )); break; default: Q_strncpy( buf, "??", sizeof( buf )); break; } Msg( "%16s (%s) ^3%s^7\n", matchbuf, buf, message ); nummaps++; } Msg( "\n^3 %i maps found.\n", nummaps ); Mem_Free( t ); // cut shortestMatch to the amount common with s for( i = 0; matchbuf[i]; i++ ) { if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) completedname[i] = 0; } return true; }
void HPAK_CreatePak( const char *filename, resource_t *DirEnt, byte *data, file_t *f ) { int filelocation; string pakname; char md5[16]; char *temp; MD5Context_t MD5_Hash; file_t *fout; if( !filename || !filename[0] ) { MsgDev( D_ERROR, "HPAK_CreatePak: NULL name\n" ); return; } if(( f != NULL && data != NULL ) || ( f == NULL && data == NULL )) { MsgDev( D_ERROR, "HPAK_CreatePak: too many sources, please leave one.\n" ); return; } Q_strncpy( pakname, filename, sizeof( pakname )); FS_StripExtension( pakname ); FS_DefaultExtension( pakname, ".hpk" ); MsgDev( D_INFO, "creating HPAK %s.\n", pakname ); fout = FS_Open( pakname, "wb", false ); if( !fout ) { MsgDev( D_ERROR, "HPAK_CreatePak: can't write %s.\n", pakname ); return; } // let's hash it. Q_memset( &MD5_Hash, 0, sizeof( MD5Context_t )); MD5Init( &MD5_Hash ); if( data == NULL ) { // there are better ways filelocation = FS_Tell( f ); temp = Z_Malloc( DirEnt->nDownloadSize ); FS_Read( f, temp, DirEnt->nDownloadSize ); FS_Seek( f, filelocation, SEEK_SET ); MD5Update( &MD5_Hash, temp, DirEnt->nDownloadSize ); Mem_Free( temp ); } else { MD5Update( &MD5_Hash, data, DirEnt->nDownloadSize ); } MD5Final( md5, &MD5_Hash ); if( Q_memcmp( md5, DirEnt->rgucMD5_hash, 16 )) { MsgDev( D_ERROR, "HPAK_CreatePak: bad checksum for %s. Ignored\n", pakname ); return; } hash_pack_header.ident = IDCUSTOMHEADER; hash_pack_header.version = IDCUSTOM_VERSION; hash_pack_header.seek = 0; FS_Write( fout, &hash_pack_header, sizeof( hash_pack_header )); hash_pack_dir.count = 1; hash_pack_dir.dirs = Z_Malloc( sizeof( hpak_dir_t )); hash_pack_dir.dirs[0].DirectoryResource = *DirEnt; hash_pack_dir.dirs[0].seek = FS_Tell( fout ); hash_pack_dir.dirs[0].size = DirEnt->nDownloadSize; if( data == NULL ) { HPAK_FileCopy( fout, f, hash_pack_dir.dirs[0].size ); } else { FS_Write( fout, data, hash_pack_dir.dirs[0].size ); } filelocation = FS_Tell( fout ); FS_Write( fout, &hash_pack_dir.count, sizeof( hash_pack_dir.count )); FS_Write( fout, &hash_pack_dir.dirs[0], sizeof( hpak_dir_t )); Mem_Free( hash_pack_dir.dirs ); Q_memset( &hash_pack_dir, 0, sizeof( hpak_container_t )); hash_pack_header.seek = filelocation; FS_Seek( fout, 0, SEEK_SET ); FS_Write( fout, &hash_pack_header, sizeof( hpak_header_t )); FS_Close( fout ); }
bool FS_ParseLiblistGam(const char *filename, const char *gamedir, gameinfo_t *GameInfo) { char *pfile; string token; if(!GameInfo) return false; char *afile = mpFileSystem->LoadFile(filename, NULL, false); if(!afile) return false; // setup default values GameInfo->max_edicts = 900; // default value if not specified GameInfo->max_tents = 500; GameInfo->max_beams = 128; GameInfo->soundclip_dist = 1536; GameInfo->max_particles = 4096; GameInfo->version = 1.0f; GameInfo->falldir[0] = '\0'; GameInfo->title = "New Game"; GameInfo->gamedir = gamedir; GameInfo->basedir = SI.ModuleName; GameInfo->sp_entity = "info_player_start"; GameInfo->mp_entity = "info_player_deathmatch"; GameInfo->game_dll = "dlls/hl.dll"; GameInfo->startmap = "newmap"; GameInfo->dll_path = "cl_dlls"; GameInfo->iconpath = "game.ico"; VectorSet(GameInfo->client_mins[0], 0, 0, 0 ); VectorSet(GameInfo->client_maxs[0], 0, 0, 0 ); VectorSet(GameInfo->client_mins[1], -16, -16, -36); VectorSet(GameInfo->client_maxs[1], 16, 16, 36); VectorSet(GameInfo->client_mins[2], -32, -32, -32); VectorSet(GameInfo->client_maxs[2], 32, 32, 32); VectorSet(GameInfo->client_mins[3], -16, -16, -18); VectorSet(GameInfo->client_maxs[3], 16, 16, 18); pfile = afile; while((pfile = COM_ParseFile(pfile, token)) != NULL) { if(token == "game") pfile = COM_ParseFile(pfile, GameInfo->msTitle); if(token == "gamedir") pfile = COM_ParseFile(pfile, GameInfo->msGameDir); if(token == "fallback_dir") pfile = COM_ParseFile(pfile, GameInfo->msFallDir); else if(token == "startmap") { pfile = COM_ParseFile(pfile, GameInfo->msStartMap); FS_StripExtension(GameInfo->msStartMap); // HQ2:Amen has extension .bsp } else if(token == "trainmap" || token == "trainingmap") { pfile = COM_ParseFile(pfile, GameInfo->msTrainMap); FS_StripExtension(GameInfo->msTrainMap); // HQ2:Amen has extension .bsp } else if(token == "url_info") pfile = COM_ParseFile(pfile, GameInfo->msGameURL); else if(token == "url_dl") pfile = COM_ParseFile(pfile, GameInfo->msUpdateURL); else if(token == "gamedll") { pfile = COM_ParseFile(pfile, GameInfo->msGameDLL); COM_FixSlashes(GameInfo->msGameDLL); } else if(token == "icon") { pfile = COM_ParseFile(pfile, GameInfo->msIconPath); COM_FixSlashes(GameInfo->msIconPath); FS_DefaultExtension(GameInfo->msIconPath, ".ico"); } else if(token == "type") { pfile = COM_ParseFile(pfile, token); if(token == "singleplayer_only") { GameInfo->gamemode = 1; strncpy(GameInfo->type, "Single", sizeof(GameInfo->type)); } else if(token == "multiplayer_only") { GameInfo->gamemode = 2; strncpy(GameInfo->type, "Multiplayer", sizeof(GameInfo->type)); } else { // pass type without changes GameInfo->gamemode = 0; strncpy(GameInfo->type, token, sizeof(GameInfo->type)); }; } else if(token == "version") { pfile = COM_ParseFile(pfile, token); GameInfo->version = Q_atof(token); } else if(token == "size") { pfile = COM_ParseFile(pfile, token); GameInfo->size = Q_atoi(token); } else if(token == "mpentity") pfile = COM_ParseFile(pfile, GameInfo->mp_entity); else if(token == "secure") { pfile = COM_ParseFile(pfile, token); GameInfo->secure = Q_atoi(token); } else if(token == "nomodels") { pfile = COM_ParseFile(pfile, token); GameInfo->nomodels = Q_atoi(token); }; }; if(!mpFileSystem->IsSysFolderExists(va("%s\\%s", host.rootdir, GameInfo->gamedir))) GameInfo->msGameDir = gamedir; if(!mpFileSystem->IsSysFolderExists(va("%s\\%s", host.rootdir, GameInfo->falldir))) GameInfo->msFallDir = ""; if(afile != NULL) Mem_Free(afile); return true; };
/* ================ Image_Save writes image as any known format ================ */ qboolean FS_SaveImage( const char *filename, rgbdata_t *pix ) { const char *ext = FS_FileExtension( filename ); qboolean anyformat = !Q_stricmp( ext, "" ) ? true : false; string path, savename; const savepixformat_t *format; if( !pix || !pix->buffer || anyformat ) { // clear any force flags image.force_flags = 0; return false; } Q_strncpy( savename, filename, sizeof( savename )); FS_StripExtension( savename ); // remove extension if needed if( pix->flags & (IMAGE_CUBEMAP|IMAGE_SKYBOX)) { size_t realSize = pix->size; // keep real pic size byte *picBuffer; // to avoid corrupt memory on free data const suffix_t *box; int i; if( pix->flags & IMAGE_SKYBOX ) box = skybox_qv1; else if( pix->flags & IMAGE_CUBEMAP ) box = cubemap_v2; else { // clear any force flags image.force_flags = 0; return false; // do not happens } pix->size /= 6; // now set as side size picBuffer = pix->buffer; // save all sides seperately for( format = image.saveformats; format && format->formatstring; format++ ) { if( !Q_stricmp( ext, format->ext )) { for( i = 0; i < 6; i++ ) { Q_sprintf( path, format->formatstring, savename, box[i].suf, format->ext ); if( !format->savefunc( path, pix )) break; // there were errors pix->buffer += pix->size; // move pointer } // restore pointers pix->size = realSize; pix->buffer = picBuffer; // clear any force flags image.force_flags = 0; return ( i == 6 ); } } } else { for( format = image.saveformats; format && format->formatstring; format++ ) { if( !Q_stricmp( ext, format->ext )) { Q_sprintf( path, format->formatstring, savename, "", format->ext ); if( format->savefunc( path, pix )) { // clear any force flags image.force_flags = 0; return true; // saved } } } } // clear any force flags image.force_flags = 0; return false; }
qboolean HPAK_ResourceForHash( const char *filename, char *inHash, resource_t *pRes ) { file_t *f; hpak_t *hpak; hpak_container_t hpakcontainer; hpak_header_t hdr; string pakname; int ret; if( !filename || !filename[0] ) return false; for( hpak = hpak_queue; hpak != NULL; hpak = hpak->next ) { if( !Q_stricmp( hpak->name, filename ) && !Q_memcmp( hpak->HpakResource.rgucMD5_hash, inHash, 0x10 )) { if( pRes != NULL ) *pRes = hpak->HpakResource; return true; } } Q_strncpy( pakname, filename, sizeof( pakname )); FS_StripExtension( pakname ); FS_DefaultExtension( pakname, ".hpk" ); f = FS_Open( pakname, "rb", false ); if( !f ) return false; FS_Read( f, &hdr, sizeof( hdr )); if( hdr.ident != IDCUSTOMHEADER ) { MsgDev( D_ERROR, "HPAK_ResourceForHash: %s it's not a HPK file.\n", pakname ); FS_Close( f ); return false; } if( hdr.version != IDCUSTOM_VERSION ) { MsgDev( D_ERROR, "HPAK_ResourceForHash: %s has invalid version (%i should be %i).\n", pakname, hdr.version, IDCUSTOM_VERSION ); FS_Close( f ); return false; } FS_Seek( f, hdr.seek, SEEK_SET ); FS_Read( f, &hpakcontainer.count, sizeof( hpakcontainer.count )); if( hpakcontainer.count < 1 || hpakcontainer.count > MAX_FILES_IN_WAD ) { MsgDev( D_ERROR, "HPAK_ResourceForHash: %s has too many lumps %u.\n", pakname, hpakcontainer.count ); FS_Close( f ); return false; } hpakcontainer.dirs = Z_Malloc( sizeof( hpak_dir_t ) * hpakcontainer.count ); FS_Read( f, hpakcontainer.dirs, sizeof( hpak_dir_t ) * hpakcontainer.count ); ret = HPAK_FindResource( &hpakcontainer, inHash, pRes ); Mem_Free( hpakcontainer.dirs ); FS_Close( f ); return(ret); }
static qboolean HPAK_Validate( const char *filename, qboolean quiet ) { file_t *f; hpak_dir_t *dataDir; hpak_header_t hdr; byte *dataPak; int i, num_lumps; MD5Context_t MD5_Hash; string pakname; resource_t *pRes; char md5[16]; if( quiet ) HPAK_FlushHostQueue(); // not an error - just flush queue if( !filename || !*filename ) return true; Q_strncpy( pakname, filename, sizeof( pakname )); FS_StripExtension( pakname ); FS_DefaultExtension( pakname, ".hpk" ); f = FS_Open( pakname, "rb", false ); if( !f ) { MsgDev( D_INFO, "Couldn't find %s.\n", pakname ); return true; } if( !quiet ) MsgDev( D_INFO, "Validating %s\n", pakname ); FS_Read( f, &hdr, sizeof( hdr )); if( hdr.ident != IDCUSTOMHEADER || hdr.version != IDCUSTOM_VERSION ) { MsgDev( D_ERROR, "HPAK_ValidatePak: %s does not have a valid HPAK header.\n", pakname ); FS_Close( f ); return false; } FS_Seek( f, hdr.seek, SEEK_SET ); FS_Read( f, &num_lumps, sizeof( num_lumps )); if( num_lumps < 1 || num_lumps > MAX_FILES_IN_WAD ) { MsgDev( D_ERROR, "HPAK_ValidatePak: %s has too many lumps %u.\n", pakname, num_lumps ); FS_Close( f ); return false; } if( !quiet ) MsgDev( D_INFO, "# of Entries: %i\n", num_lumps ); dataDir = Z_Malloc( sizeof( hpak_dir_t ) * num_lumps ); FS_Read( f, dataDir, sizeof( hpak_dir_t ) * num_lumps ); if( !quiet ) MsgDev( D_INFO, "# Type Size FileName : MD5 Hash\n" ); for( i = 0; i < num_lumps; i++ ) { if( dataDir[i].size < 1 || dataDir[i].size > 131071 ) { // odd max size MsgDev( D_ERROR, "HPAK_ValidatePak: lump %i has invalid size %s\n", i, Q_pretifymem( dataDir[i].size, 2 )); Mem_Free( dataDir ); FS_Close(f); return false; } dataPak = Z_Malloc( dataDir[i].size ); FS_Seek( f, dataDir[i].seek, SEEK_SET ); FS_Read( f, dataPak, dataDir[i].size ); Q_memset( &MD5_Hash, 0, sizeof( MD5Context_t )); MD5Init( &MD5_Hash ); MD5Update( &MD5_Hash, dataPak, dataDir[i].size ); MD5Final( md5, &MD5_Hash ); pRes = &dataDir[i].DirectoryResource; MsgDev( D_INFO, "%i: %s %s %s: ", i, HPAK_TypeFromIndex( pRes->type ), Q_pretifymem( pRes->nDownloadSize, 2 ), pRes->szFileName ); if( Q_memcmp( md5, pRes->rgucMD5_hash, 0x10 )) { if( quiet ) { MsgDev( D_ERROR, "HPAK_ValidatePak: %s has invalid checksum.\n", pakname ); Mem_Free( dataPak ); Mem_Free( dataDir ); FS_Close( f ); return false; } else MsgDev( D_INFO, "failed\n" ); } else { if( !quiet ) MsgDev( D_INFO, "OK\n" ); } // at this point, it's passed our checks. Mem_Free( dataPak ); } Mem_Free( dataDir ); FS_Close( f ); return true; }
void HPAK_AddLump( qboolean add_to_queue, const char *name, resource_t *DirEnt, byte *data, file_t *f ) { int i, position, length; string pakname1, pakname2; char md5[16]; MD5Context_t MD5_Hash; hpak_container_t hpak1, hpak2; file_t *f1, *f2; hpak_dir_t *dirs; byte *temp; if( !name || !name[0] ) { MsgDev( D_ERROR, "HPAK_AddLump: NULL name\n" ); return; } if( !DirEnt ) { MsgDev( D_ERROR, "HPAK_AddLump: invalid lump\n" ); return; } if( data == NULL && f == NULL ) { MsgDev( D_ERROR, "HPAK_AddLump: missing lump data\n" ); return; } if( DirEnt->nDownloadSize < 1024 || DirEnt->nDownloadSize > 131072 ) { MsgDev( D_ERROR, "HPAK_AddLump: invalid size %s\n", Q_pretifymem( DirEnt->nDownloadSize, 2 )); return; } // hash it Q_memset( &MD5_Hash, 0, sizeof( MD5Context_t )); MD5Init( &MD5_Hash ); if( data == NULL ) { // there are better ways position = FS_Tell( f ); temp = Z_Malloc( DirEnt->nDownloadSize ); FS_Read( f, temp, DirEnt->nDownloadSize ); FS_Seek( f, position, SEEK_SET ); MD5Update( &MD5_Hash, temp, DirEnt->nDownloadSize ); Mem_Free( temp ); } else { MD5Update( &MD5_Hash, data, DirEnt->nDownloadSize ); } MD5Final( md5, &MD5_Hash ); if( Q_memcmp( md5, DirEnt->rgucMD5_hash, 0x10 )) { MsgDev( D_ERROR, "HPAK_AddLump: bad checksum for %s. Ignored\n", DirEnt->szFileName ); return; } if( add_to_queue ) { HPAK_AddToQueue( name, DirEnt, data, f ); return; } Q_strncpy( pakname1, name, sizeof( pakname1 )); FS_StripExtension( pakname1 ); FS_DefaultExtension( pakname1, ".hpk" ); f1 = FS_Open( pakname1, "rb", false ); if( !f1 ) { // create new pack HPAK_CreatePak( name, DirEnt, data, f ); return; } Q_strncpy( pakname2, pakname1, sizeof( pakname2 )); FS_StripExtension( pakname2 ); FS_DefaultExtension( pakname2, ".hp2" ); f2 = FS_Open( pakname2, "w+b", false ); if( !f2 ) { MsgDev( D_ERROR, "HPAK_AddLump: couldn't open %s.\n", pakname2 ); FS_Close( f1 ); return; } // load headers FS_Read( f1, &hash_pack_header, sizeof( hpak_header_t )); if( hash_pack_header.version != IDCUSTOM_VERSION ) { // we don't check the HPAK bit for some reason. MsgDev( D_ERROR, "HPAK_AddLump: %s does not have a valid header.\n", pakname2 ); FS_Close( f1 ); FS_Close( f2 ); } length = FS_FileLength( f1 ); HPAK_FileCopy( f2, f1, length ); FS_Seek( f1, hash_pack_header.seek, SEEK_SET ); FS_Read( f1, &hpak1.count, sizeof( hpak1.count )); if( hpak1.count < 1 || hpak1.count > MAX_FILES_IN_WAD ) { MsgDev( D_ERROR, "HPAK_AddLump: %s contain too many lumps.\n", pakname1 ); FS_Close( f1 ); FS_Close( f2 ); return; } // load the data hpak1.dirs = Z_Malloc( sizeof( hpak_dir_t ) * hpak1.count ); FS_Read( f1, hpak1.dirs, sizeof( hpak_dir_t ) * hpak1.count ); FS_Close( f1 ); if( HPAK_FindResource( &hpak1, DirEnt->rgucMD5_hash, NULL )) { Mem_Free( hpak1.dirs ); FS_Close( f2 ); } // make a new container hpak2.count = hpak1.count; hpak2.dirs = Z_Malloc( sizeof( hpak_dir_t ) * hpak2.count ); Q_memcpy( hpak2.dirs, hpak1.dirs, hpak1.count ); for( i = 0, dirs = NULL; i < hpak1.count; i++ ) { if( Q_memcmp( hpak1.dirs[i].DirectoryResource.rgucMD5_hash, DirEnt->rgucMD5_hash, 16 ) < 0 ) { dirs = &hpak1.dirs[i]; while( i < hpak1.count ) { hpak2.dirs[i+1] = hpak1.dirs[i]; i++; } break; } } if( dirs == NULL ) dirs = &hpak2.dirs[hpak2.count-1]; Q_memset( dirs, 0, sizeof( hpak_dir_t )); FS_Seek( f2, hash_pack_header.seek, SEEK_SET ); dirs->DirectoryResource = *DirEnt; dirs->seek = FS_Tell( f2 ); dirs->size = DirEnt->nDownloadSize; if( !data ) HPAK_FileCopy( f2, f, dirs->size ); else FS_Write( f2, data, dirs->size ); hash_pack_header.seek = FS_Tell( f2 ); FS_Write( f2, &hpak2.count, sizeof( hpak2.count )); for( i = 0; i < hpak2.count; i++ ) { FS_Write( f2, &hpak2.dirs[i], sizeof( hpak_dir_t )); } // finalize Mem_Free( hpak1.dirs ); Mem_Free( hpak2.dirs ); FS_Seek( f2, 0, SEEK_SET ); FS_Write( f2, &hash_pack_header, sizeof( hpak_header_t )); FS_Close( f2 ); FS_Delete( pakname1 ); FS_Rename( pakname2, pakname1 ); }
/* ================= LoadSurfaceExtraFile reads a surface info file (<map>.srf) ================= */ void LoadSurfaceExtraFile( const char *path ) { char srfPath[MAX_SYSPATH]; surfaceExtra_t *se; int surfaceNum; script_t *script; token_t token; if( path == NULL || path[0] == '\0' ) return; com.strcpy( srfPath, path ); FS_StripExtension( srfPath ); FS_DefaultExtension( srfPath, ".srf" ); Msg( "Loading %s\n", srfPath ); script = (void *)Com_OpenScript( srfPath, NULL, 0 ); if( !script ) Sys_Break( "unable to load %s\n", srfPath ); // q3map is always crashed if this missed while( 1 ) { if( !Com_ReadToken( script, SC_ALLOW_NEWLINES|SC_PARSE_GENERIC, &token )) break; if( !com.stricmp( token.string, "default" )) se = &seDefault; else { surfaceNum = com.atoi( token.string ); if( surfaceNum < 0 || surfaceNum > MAX_MAP_DRAW_SURFS ) Sys_Error( "ReadSurfaceExtraFile(): %s, line %d: bogus surface num %d", srfPath, token.line, surfaceNum ); while( surfaceNum >= numSurfaceExtras ) se = AllocSurfaceExtra(); se = &surfaceExtras[surfaceNum]; } // handle { } section if( !Com_ReadToken( script, SC_ALLOW_NEWLINES|SC_PARSE_GENERIC, &token ) || com.strcmp( token.string, "{" )) Sys_Error( "ReadSurfaceExtraFile(): %s, line %d: { not found\n", srfPath, token.line ); while( 1 ) { if( !Com_ReadToken( script, SC_ALLOW_NEWLINES|SC_PARSE_GENERIC, &token )) break; if( !com.strcmp( token.string, "}" )) break; if( !com.stricmp( token.string, "shader" )) { Com_ReadToken( script, SC_ALLOW_PATHNAMES|SC_PARSE_GENERIC, &token ); se->si = ShaderInfoForShader( token.string ); } else if( !com.stricmp( token.string, "parent" )) { Com_ReadLong( script, false, &se->parentSurfaceNum ); } else if( !com.stricmp( token.string, "entity" )) { Com_ReadLong( script, false, &se->entityNum ); } else if( !com.stricmp( token.string, "castShadows" )) { Com_ReadLong( script, false, &se->castShadows ); } else if( !com.stricmp( token.string, "receiveShadows" )) { Com_ReadLong( script, false, &se->recvShadows ); } else if( !com.stricmp( token.string, "sampleSize" )) { Com_ReadLong( script, false, &se->sampleSize ); } else if( !com.stricmp( token.string, "longestCurve" )) { Com_ReadFloat( script, false, &se->longestCurve ); } else if( !com.stricmp( token.string, "lightmapAxis" )) Com_Parse1DMatrix( script, 3, se->lightmapAxis ); // ignore all other tokens on the line Com_SkipRestOfLine( script ); } } Com_CloseScript( script ); }
qboolean HPAK_GetDataPointer( const char *filename, resource_t *pResource, byte **buffer, int *size ) { file_t *f; int i, num_lumps; hpak_dir_t *direntries; byte *tmpbuf; string pakname; hpak_t *queue; hpak_header_t hdr; if( !filename || !filename[0] ) return false; if( buffer ) *buffer = NULL; if( size ) *size = 0; for( queue = hpak_queue; queue != NULL; queue = queue->next ) { if( !Q_stricmp(queue->name, filename ) && !Q_memcmp( queue->HpakResource.rgucMD5_hash, pResource->rgucMD5_hash, 16 )) { if( buffer ) { tmpbuf = Z_Malloc( queue->size ); Q_memcpy( tmpbuf, queue->data, queue->size ); *buffer = tmpbuf; } if( size ) *size = queue->size; return true; } } Q_strncpy( pakname, filename, sizeof( pakname )); FS_StripExtension( pakname ); FS_DefaultExtension( pakname, ".hpk" ); f = FS_Open( pakname, "rb", false ); if( !f ) return false; FS_Read( f, &hdr, sizeof( hdr )); if( hdr.ident != IDCUSTOMHEADER ) { MsgDev( D_ERROR, "HPAK_GetDataPointer: %s it's not a HPK file.\n", pakname ); FS_Close( f ); return false; } if( hdr.version != IDCUSTOM_VERSION ) { MsgDev( D_ERROR, "HPAK_GetDataPointer: %s has invalid version (%i should be %i).\n", pakname, hdr.version, IDCUSTOM_VERSION ); FS_Close( f ); return false; } FS_Seek( f, hdr.seek, SEEK_SET ); FS_Read( f, &num_lumps, sizeof( num_lumps )); if( num_lumps < 1 || num_lumps > MAX_FILES_IN_WAD ) { MsgDev( D_ERROR, "HPAK_GetDataPointer: %s has too many lumps %u.\n", filename, num_lumps ); FS_Close( f ); return false; } direntries = Z_Malloc( sizeof( hpak_dir_t ) * num_lumps ); FS_Read( f, direntries, sizeof( hpak_dir_t ) * num_lumps ); for( i = 0; i < num_lumps; i++ ) { if( !Q_memcmp( direntries[i].DirectoryResource.rgucMD5_hash, pResource->rgucMD5_hash, 16 )) { FS_Seek( f, direntries[i].seek, SEEK_SET ); if( buffer && direntries[i].size > 0 ) { tmpbuf = Z_Malloc( direntries[i].size ); FS_Read( f, tmpbuf, direntries[i].size ); *buffer = tmpbuf; } Mem_Free( direntries ); FS_Close( f ); return true; } } Mem_Free( direntries ); FS_Close( f ); return false; }
/* ================= VID_CubemapShot ================= */ qboolean VID_CubemapShot( const char *base, uint size, const float *vieworg, qboolean skyshot ) { rgbdata_t *r_shot, *r_side; byte *temp = NULL; byte *buffer = NULL; string basename; int i = 1, flags, result; if( !RI.drawWorld || !cl.worldmodel ) return false; // make sure the specified size is valid while( i < size ) i<<=1; if( i != size ) return false; if( size > glState.width || size > glState.height ) return false; // setup refdef RI.params |= RP_ENVVIEW; // do not render non-bmodel entities // alloc space temp = Mem_Alloc( r_temppool, size * size * 3 ); buffer = Mem_Alloc( r_temppool, size * size * 3 * 6 ); r_shot = Mem_Alloc( r_temppool, sizeof( rgbdata_t )); r_side = Mem_Alloc( r_temppool, sizeof( rgbdata_t )); // use client vieworg if( !vieworg ) vieworg = cl.refdef.vieworg; for( i = 0; i < 6; i++ ) { // go into 3d mode R_Set2DMode( false ); if( skyshot ) { R_DrawCubemapView( vieworg, r_skyBoxInfo[i].angles, size ); flags = r_skyBoxInfo[i].flags; } else { R_DrawCubemapView( vieworg, r_envMapInfo[i].angles, size ); flags = r_envMapInfo[i].flags; } pglReadPixels( 0, 0, size, size, GL_RGB, GL_UNSIGNED_BYTE, temp ); r_side->flags = IMAGE_HAS_COLOR; r_side->width = r_side->height = size; r_side->type = PF_RGB_24; r_side->size = r_side->width * r_side->height * 3; r_side->buffer = temp; if( flags ) Image_Process( &r_side, 0, 0, 0.0f, flags, NULL ); Q_memcpy( buffer + (size * size * 3 * i), r_side->buffer, size * size * 3 ); } RI.params &= ~RP_ENVVIEW; r_shot->flags = IMAGE_HAS_COLOR; r_shot->flags |= (skyshot) ? IMAGE_SKYBOX : IMAGE_CUBEMAP; r_shot->width = size; r_shot->height = size; r_shot->type = PF_RGB_24; r_shot->size = r_shot->width * r_shot->height * 3 * 6; r_shot->palette = NULL; r_shot->buffer = buffer; // make sure what we have right extension Q_strncpy( basename, base, MAX_STRING ); FS_StripExtension( basename ); FS_DefaultExtension( basename, ".tga" ); // write image as 6 sides result = FS_SaveImage( basename, r_shot ); FS_FreeImage( r_shot ); FS_FreeImage( r_side ); return result; }
void HPAK_RemoveLump( const char *name, resource_t *resource ) { string read_path; string save_path; file_t *f1, *f2; hpak_container_t hpak_read; hpak_container_t hpak_save; int i, j; if( !name || !name[0] || !resource ) return; HPAK_FlushHostQueue(); Q_strncpy( read_path, name, sizeof( read_path )); FS_StripExtension( read_path ); FS_DefaultExtension( read_path, ".hpk" ); f1 = FS_Open( read_path, "rb", false ); if( !f1 ) { MsgDev( D_ERROR, "HPAK_RemoveLump: %s couldn't open.\n", read_path ); return; } Q_strncpy( save_path, read_path, sizeof( save_path )); FS_StripExtension( save_path ); FS_DefaultExtension( save_path, ".hp2" ); f2 = FS_Open( save_path, "w+b", false ); if( !f2 ) { MsgDev( D_ERROR, "HPAK_RemoveLump: %s couldn't open.\n", save_path ); FS_Close( f1 ); return; } FS_Seek( f1, 0, SEEK_SET ); FS_Seek( f2, 0, SEEK_SET ); // header copy FS_Read( f1, &hash_pack_header, sizeof( hpak_header_t )); FS_Write( f2, &hash_pack_header, sizeof( hpak_header_t )); if( hash_pack_header.ident != IDCUSTOMHEADER || hash_pack_header.version != IDCUSTOM_VERSION ) { MsgDev( D_ERROR, "HPAK_RemoveLump: %s has invalid header.\n", read_path ); FS_Close( f1 ); FS_Close( f2 ); FS_Delete( save_path ); // delete temp file return; } FS_Seek( f1, hash_pack_header.seek, SEEK_SET ); FS_Read( f1, &hpak_read.count, sizeof( hpak_read.count )); if( hpak_read.count < 1 || hpak_read.count > MAX_FILES_IN_WAD ) { MsgDev( D_ERROR, "HPAK_RemoveLump: %s has invalid number of lumps.\n", read_path ); FS_Close( f1 ); FS_Close( f2 ); FS_Delete( save_path ); // delete temp file return; } if( hpak_read.count == 1 ) { MsgDev( D_ERROR, "HPAK_RemoveLump: %s only has one element, so it's not deleted.\n", read_path ); FS_Close( f1 ); FS_Close( f2 ); FS_Delete( read_path ); FS_Delete( save_path ); return; } hpak_save.count = hpak_read.count - 1; hpak_read.dirs = Z_Malloc( sizeof( hpak_dir_t ) * hpak_read.count ); hpak_save.dirs = Z_Malloc( sizeof( hpak_dir_t ) * hpak_save.count ); FS_Read( f1, hpak_read.dirs, sizeof( hpak_dir_t ) * hpak_read.count ); if( !HPAK_FindResource( &hpak_read, resource->rgucMD5_hash, NULL )) { MsgDev( D_ERROR, "HPAK_RemoveLump: Couldn't find the lump %s in hpak %s.n", resource->szFileName, read_path ); Mem_Free( hpak_read.dirs ); Mem_Free( hpak_save.dirs ); FS_Close( f1 ); FS_Close( f2 ); FS_Delete( save_path ); return; } MsgDev( D_INFO, "Removing lump %s from %s.\n", resource->szFileName, read_path ); // If there's a collision, we've just corrupted this hpak. for( i = 0, j = 0; i < hpak_read.count; i++ ) { if( !Q_memcmp( hpak_read.dirs[i].DirectoryResource.rgucMD5_hash, resource->rgucMD5_hash, 16 )) continue; hpak_save.dirs[j] = hpak_read.dirs[i]; hpak_save.dirs[j].seek = FS_Tell( f2 ); FS_Seek( f1, hpak_read.dirs[j].seek, SEEK_SET ); HPAK_FileCopy( f2, f1, hpak_save.dirs[j].size ); j++; } hash_pack_header.seek = FS_Tell( f2 ); FS_Write( f2, &hpak_save.count, ( hpak_save.count )); for( i = 0; i < hpak_save.count; i++ ) { FS_Write( f2, &hpak_save.dirs[i], sizeof( hpak_dir_t )); } FS_Seek( f2, 0, SEEK_SET ); FS_Write( f2, &hash_pack_header, sizeof( hpak_header_t )); Mem_Free( hpak_read.dirs ); Mem_Free( hpak_save.dirs ); FS_Close( f1 ); FS_Close( f2 ); FS_Delete( read_path ); FS_Rename( save_path, read_path ); }
/* ================ FS_LoadImage loading and unpack to rgba any known image ================ */ rgbdata_t *FS_LoadImage( const char *filename, const byte *buffer, size_t size ) { const char *ext = FS_FileExtension( filename ); string path, loadname, sidename; qboolean anyformat = true; int i, filesize = 0; const loadpixformat_t *format; const cubepack_t *cmap; byte *f; Image_Reset(); // clear old image Q_strncpy( loadname, filename, sizeof( loadname )); if( Q_stricmp( ext, "" )) { // we needs to compare file extension with list of supported formats // and be sure what is real extension, not a filename with dot for( format = image.loadformats; format && format->formatstring; format++ ) { if( !Q_stricmp( format->ext, ext )) { FS_StripExtension( loadname ); anyformat = false; break; } } } // HACKHACK: skip any checks, load file from buffer if( filename[0] == '#' && buffer && size ) goto load_internal; // now try all the formats in the selected list for( format = image.loadformats; format && format->formatstring; format++) { if( anyformat || !Q_stricmp( ext, format->ext )) { Q_sprintf( path, format->formatstring, loadname, "", format->ext ); image.hint = format->hint; f = FS_LoadFile( path, &filesize, false ); if( f && filesize > 0 ) { if( format->loadfunc( path, f, filesize )) { Mem_Free( f ); // release buffer return ImagePack(); // loaded } else Mem_Free(f); // release buffer } } } // check all cubemap sides with package suffix for( cmap = load_cubemap; cmap && cmap->type; cmap++ ) { for( i = 0; i < 6; i++ ) { // for support mixed cubemaps e.g. sky_ft.bmp, sky_rt.tga // NOTE: all loaders must keep sides in one format for all for( format = image.loadformats; format && format->formatstring; format++ ) { if( anyformat || !Q_stricmp( ext, format->ext )) { Q_sprintf( path, format->formatstring, loadname, cmap->type[i].suf, format->ext ); image.hint = cmap->type[i].hint; // side hint f = FS_LoadFile( path, &filesize, false ); if( f && filesize > 0 ) { // this name will be used only for tell user about problems if( format->loadfunc( path, f, filesize )) { Q_snprintf( sidename, sizeof( sidename ), "%s%s.%s", loadname, cmap->type[i].suf, format->ext ); if( FS_AddSideToPack( sidename, cmap->type[i].flags )) // process flags to flip some sides { Mem_Free( f ); break; // loaded } } Mem_Free( f ); } } } if( image.num_sides != i + 1 ) // check side { // first side not found, probably it's not cubemap // it contain info about image_type and dimensions, don't generate black cubemaps if( !image.cubemap ) break; MsgDev( D_ERROR, "FS_LoadImage: couldn't load (%s%s), create black image\n", loadname, cmap->type[i].suf ); // Mem_Alloc already filled memblock with 0x00, no need to do it again image.cubemap = Mem_Realloc( host.imagepool, image.cubemap, image.ptr + image.size ); image.ptr += image.size; // move to next image.num_sides++; // merge counter } } // make sure what all sides is loaded if( image.num_sides != 6 ) { // unexpected errors ? if( image.cubemap ) Mem_Free( image.cubemap ); Image_Reset(); } else break; } if( image.cubemap ) return ImagePack(); // all done load_internal: for( format = image.loadformats; format && format->formatstring; format++ ) { if( anyformat || !Q_stricmp( ext, format->ext )) { image.hint = format->hint; if( buffer && size > 0 ) { if( format->loadfunc( loadname, buffer, size )) return ImagePack(); // loaded } } } if( !image.loadformats || image.loadformats->ext == NULL ) MsgDev( D_NOTE, "FS_LoadImage: imagelib offline\n" ); else if( filename[0] != '#' ) MsgDev( D_WARN, "FS_LoadImage: couldn't load \"%s\"\n", loadname ); // clear any force flags image.force_flags = 0; return NULL; }
/* ================ FS_LoadSound loading and unpack to wav any known sound ================ */ wavdata_t *FS_LoadSound( const char *filename, const byte *buffer, size_t size ) { const char *ext = FS_FileExtension( filename ); string path, loadname; qboolean anyformat = true; int filesize = 0; const loadwavfmt_t *format; byte *f; Sound_Reset(); // clear old sounddata Q_strncpy( loadname, filename, sizeof( loadname )); if( Q_stricmp( ext, "" )) { // we needs to compare file extension with list of supported formats // and be sure what is real extension, not a filename with dot for( format = sound.loadformats; format && format->formatstring; format++ ) { if( !Q_stricmp( format->ext, ext )) { FS_StripExtension( loadname ); anyformat = false; break; } } } // HACKHACK: skip any checks, load file from buffer if( filename[0] == '#' && buffer && size ) goto load_internal; // now try all the formats in the selected list for( format = sound.loadformats; format && format->formatstring; format++) { if( anyformat || !Q_stricmp( ext, format->ext )) { Q_sprintf( path, format->formatstring, loadname, "", format->ext ); f = FS_LoadFile( path, &filesize, false ); if( f && filesize > 0 ) { if( format->loadfunc( path, f, filesize )) { Mem_Free(f); // release buffer return SoundPack(); // loaded } else Mem_Free(f); // release buffer } } } load_internal: for( format = sound.loadformats; format && format->formatstring; format++ ) { if( anyformat || !Q_stricmp( ext, format->ext )) { if( buffer && size > 0 ) { if( format->loadfunc( loadname, buffer, size )) return SoundPack(); // loaded } } } if( !sound.loadformats || sound.loadformats->ext == NULL ) MsgDev( D_NOTE, "FS_LoadSound: soundlib offline\n" ); else if( filename[0] != '#' ) MsgDev( D_WARN, "FS_LoadSound: couldn't load \"%s\"\n", loadname ); return NULL; }