/*** * * Copyright (C) 2002 The Wastes Project, All Rights Reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. * All Rights Reserved. * * Use, distribution, and modification of this source code and/or resulting * object code is restricted to non-commercial enhancements to products from * The Wastes Project. All other use, distribution, or modification is prohibited * without written permission from The Wastes Project. * ***/ // // parsebsp.cpp -> parse bsp entity information client side // some of this code was graciously accepted from DMC_Teleporters.cpp // #include "extdll.h" #include "entity_state.h" #include "pm_defs.h" #include "pm_movevars.h" #include "hud_iface.h" #include "com_model.h" #include "event_api.h" #include "com_weapons.h" #include "event_flags.h" #include "dmc_bspfile.h" #include "cl_util.h" #include "ParseBspEnt.h" #include "ParseBsp.h" #include using namespace std; CParseBsp g_ParseBsp; CParseBsp::CParseBsp() { memset( m_szCurrentLevel, 0, sizeof( m_szCurrentLevel ) ); } int CParseBsp::CheckMap() { if( stricmp( m_szCurrentLevel, gEngfuncs.pfnGetLevelName() ) != 0 ) { strcpy( m_szCurrentLevel, gEngfuncs.pfnGetLevelName() ); // Right now this is kind of a strong approach to read entities // The entire .bsp must be read for each new entity we wish to read. ParseBsp( "worldspawn", new CBspWorldspawn() ); ParseBsp( "env_fog", new CBspEnvFog() ); ParseBsp( "env_particlesystem", new CBspEnvParticleSystem() ); return 1; } return 0; } char *CParseBsp::ParseEntity( char *pBuf, int &error, CBspEntity *pEnt ) { char key[256]; char token[ 1024 ]; int n; while (1) { // Parse key pBuf = gEngfuncs.COM_ParseFile ( pBuf, token ); if ( token[0] == '}' ) break; // Ran out of input buffer? if ( !pBuf ) { error = 1; break; } // Store off the key strcpy ( key, token ); // Fix heynames with trailing spaces n = strlen( key ); while (n && key[n-1] == ' ') { key[n-1] = 0; n--; } // Parse value pBuf = gEngfuncs.COM_ParseFile ( pBuf, token ); // Ran out of buffer? if (!pBuf) { error = 1; break; } // Hit the end instead of a value? if ( token[0] == '}' ) { error = 1; break; } if ( token[0] == '}' && token[1] == '(' ) int k = 0; // Assign k/v pair pEnt->SetKeyValue( key, token ); } // Return what's left in the stream return pBuf; } char *CParseBsp::LoadEntityLump( char *pszFilename ) { FILE *fp; int i; dheader_t header; int size; lump_t *curLump; char *buffer = NULL; fp = fopen( pszFilename, "rb" ); if( !fp ) return NULL; // Read in the .bsp header if ( fread(&header, sizeof(dheader_t), 1, fp) != 1 ) { gEngfuncs.Con_Printf("Dmc_LoadEntityLump: Could not read BSP header for map [%s].\n", pszFilename); fclose(fp); return NULL; } // Check the version i = header.version; if ( i != 29 && i != 30) { fclose(fp); gEngfuncs.Con_Printf("Dmc_LoadEntityLump: Map [%s] has incorrect BSP version (%i should be %i).\n", pszFilename, i, BSPVERSION); return NULL; } // Get entity lump curLump = &header.lumps[ LUMP_ENTITIES ]; // and entity lump size size = curLump->filelen; // Jump to it fseek( fp, curLump->fileofs, SEEK_SET ); // Allocate sufficient memmory buffer = new char[ size + 1 ]; if ( buffer == NULL ) { fclose(fp); gEngfuncs.Con_Printf("Dmc_LoadEntityLump: Couldn't allocate %i bytes\n", size + 1 ); return NULL; } // Read in the entity lump fread( buffer, size, 1, fp ); // Terminate the string buffer[ size ] = '\0'; if ( fp ) { fclose(fp); } return buffer; } void CParseBsp::LumpPass( char *pBuf, char *pszClassname, CBspEntity *pEnt ) { char szToken[ 1024 ]; int error = 0; while( 1 ) { pBuf = gEngfuncs.COM_ParseFile( pBuf, szToken ); if( pBuf == NULL ) break; // Didn't find opening brace? if( szToken[0] != '{' ) { gEngfuncs.Con_Printf( "CParseBsp::ParseBsp: found %s when expecting {\n", szToken[0] ); break; } pBuf = ParseEntity( pBuf, error, pEnt ); if( stricmp( pszClassname, pEnt->szClassname ) == 0 ) pEnt->AddEntity(); if( error ) { gEngfuncs.Con_Printf( "CParseBsp::ParseBsp: error parsing entities\n" ); break; } } delete pEnt; } void CParseBsp::ParseBsp( char *pszClassname, CBspEntity *pEnt ) { char szFilename[256]; char *pBuf; sprintf( szFilename, "%s/%s", gEngfuncs.pfnGetGameDirectory(), m_szCurrentLevel ); pBuf = LoadEntityLump( szFilename ); if( pBuf != NULL ) { LumpPass( pBuf, pszClassname, pEnt ); delete[] pBuf; } }