X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=radiant%2Feclass_def.cpp;h=8637b4800c186e1ff3c23d260fe904779ca4fc7f;hb=e3af470d9d19e105c9a9c6228931ee2645d09371;hp=0caf630ccd33e14d7e1b598963a6d5a64fb8b69b;hpb=830125fad042fad35dc029b6eb57c8156ad7e176;p=xonotic%2Fnetradiant.git diff --git a/radiant/eclass_def.cpp b/radiant/eclass_def.cpp index 0caf630c..8637b480 100644 --- a/radiant/eclass_def.cpp +++ b/radiant/eclass_def.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 1999-2007 id Software, Inc. and contributors. + Copyright (C) 1999-2006 Id Software, Inc. and contributors. For a list of contributors, see the accompanying CONTRIBUTORS file. This file is part of GtkRadiant. @@ -19,87 +19,150 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "cmdlib.h" +#include "eclass_def.h" -#include "synapse.h" -#define USE_QERTABLE_DEFINE -#include "qerplugin.h" -#define USE_ECLASSMANAGER_DEFINE -#include "ieclass.h" -#define USE_SCRIPLIBTABLE_DEFINE #include "iscriplib.h" - -#define __VFSTABLENAME g_FileSystemTable_def -#define USE_VFSTABLE_DEFINE #include "ifilesystem.h" +#include "iarchive.h" +#include "eclasslib.h" +#include "stream/stringstream.h" +#include "stream/textfilestream.h" +#include "modulesystem/moduleregistry.h" +#include "os/path.h" -#include "eclass_def.h" +const char* EClass_GetExtension(){ + return "def"; +} +void Eclass_ScanFile( EntityClassCollector& collector, const char *filename ); -/*! \file eclass_def.cpp - \brief .def entity description format - implements parsing for .def entity format - this is statically linked into the radiant core as we always need it, but really considered - as an idependant module by the rest of the core. "ECLASS_MAJOR" "def" - */ -_QERScripLibTable g_ScripLibTable; -_EClassManagerTable g_EClassManagerTable; -_QERFuncTable_1 g_FuncTable; -_QERFileSystemTable g_FileSystemTable_def; +#include "modulesystem/singletonmodule.h" -CSynapseBuiltinClientDef eclass_def; +class EntityClassDefDependencies : public GlobalShaderCacheModuleRef, public GlobalScripLibModuleRef +{ +}; -// forward declare, I'm cheap -void Eclass_ScanFile( char *filename ); +class EclassDefAPI +{ +EntityClassScanner m_eclassdef; +public: +typedef EntityClassScanner Type; +STRING_CONSTANT( Name, "def" ); -const char* EClass_GetExtension(){ - return "def"; +EclassDefAPI(){ + m_eclassdef.scanFile = &Eclass_ScanFile; + m_eclassdef.getExtension = &EClass_GetExtension; +} +EntityClassScanner* getTable(){ + return &m_eclassdef; } +}; -void CSynapseBuiltinClientDef::EnumerateInterfaces( CSynapseServer *server ){ - AddAPI( SCRIPLIB_MAJOR, NULL, sizeof( g_ScripLibTable ), SYN_REQUIRE, &g_ScripLibTable ); - AddAPI( RADIANT_MAJOR, NULL, sizeof( g_FuncTable ), SYN_REQUIRE, &g_FuncTable ); - AddAPI( ECLASSMANAGER_MAJOR, NULL, sizeof( g_EClassManagerTable ), SYN_REQUIRE, &g_EClassManagerTable ); - // hardcode the minor for now, we can still add it to the synapse.config at some point - AddAPI( VFS_MAJOR, "pk3", sizeof( g_FileSystemTable_def ), SYN_REQUIRE, &g_FileSystemTable_def ); +typedef SingletonModule EclassDefModule; +typedef Static StaticEclassDefModule; +StaticRegisterModule staticRegisterEclassDef( StaticEclassDefModule::instance() ); - AddAPI( ECLASS_MAJOR, "def", sizeof( _EClassTable ) ); -} -bool CSynapseBuiltinClientDef::RequestAPI( APIDescriptor_t *pAPI ){ - if ( !strcmp( pAPI->major_name, ECLASS_MAJOR ) ) { - _EClassTable* pTable = static_cast<_EClassTable*>( pAPI->mpTable ); - pTable->m_pfnScanFile = &Eclass_ScanFile; - pTable->m_pfnGetExtension = &EClass_GetExtension; +#include "string/string.h" + +#include + - return true; +char com_token[1024]; +bool com_eof; + +/* + ============== + COM_Parse + + Parse a token out of a string + ============== + */ +const char *COM_Parse( const char *data ){ + int c; + int len; + + len = 0; + com_token[0] = 0; + + if ( !data ) { + return 0; } - Syn_Printf( "ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo() ); - return false; -} +// skip whitespace +skipwhite: + while ( ( c = *data ) <= ' ' ) + { + if ( c == 0 ) { + com_eof = true; + return 0; // end of file; + } + data++; + } -#include "version.h" +// skip // comments + if ( c == '/' && data[1] == '/' ) { + while ( *data && *data != '\n' ) + data++; + goto skipwhite; + } -const char* CSynapseBuiltinClientDef::GetInfo(){ - return "Builtin .def module built " __DATE__ " " RADIANT_VERSION; + +// handle quoted strings specially + if ( c == '\"' ) { + data++; + do + { + c = *data++; + if ( c == '\"' ) { + com_token[len] = 0; + return data; + } + com_token[len] = c; + len++; + } while ( 1 ); + } + +// parse single characters + if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) { + com_token[len] = c; + len++; + com_token[len] = 0; + return data + 1; + } + +// parse a regular word + do + { + com_token[len] = c; + data++; + len++; + c = *data; + if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) { + break; + } + } while ( c > 32 ); + + com_token[len] = 0; + return data; +} + +const char* Get_COM_Token(){ + return com_token; } -// ------------------------------------------------------------------------------------------------ -qboolean eclass_found; -char *debugname; +const char *debugname; -void setSpecialLoad( eclass_t *e, const char* pWhat, char*& p ){ +void setSpecialLoad( EntityClass *e, const char* pWhat, CopiedString& p ){ // Hydra: removed some amazingly bad cstring usage, whoever wrote that // needs to be taken out and shot. - char *pText = NULL; - char *where = NULL; + const char *pText = 0; + const char *where = 0; - p = NULL; // incase we don't find what we're looking for. - where = strstr( e->comments,pWhat ); + where = strstr( e->comments(),pWhat ); if ( !where ) { return; } @@ -111,48 +174,52 @@ void setSpecialLoad( eclass_t *e, const char* pWhat, char*& p ){ where = strchr( pText,'\"' ); if ( where ) { - int len = ( where - pText ); - p = new char[len + 1]; - strncpy( p,pText,len ); - p[len] = 0; // just to make sure, as most implementations of strncpy don't null terminate + p = StringRange( pText, where ); } - else{ - p = strdup( pText ); + else + { + p = pText; } } -eclass_t *Eclass_InitFromText( char *text ){ - char *t; - int len; - int r, i; - char parms[256], *p; - eclass_t *e; - char color[128]; +#include "eclasslib.h" + +/* + + the classname, color triple, and bounding box are parsed out of comments + A ? size means take the exact brush size. - e = (eclass_t*)malloc( sizeof( *e ) ); - memset( e, 0, sizeof( *e ) ); + / *QUAKED (0 0 0) ? + / *QUAKED (0 0 0) (-8 -8 -8) (8 8 8) - text += strlen( "/*QUAKED " ); + Flag names can follow the size description: + + / *QUAKED func_door (0 .5 .8) ? START_OPEN STONE_SOUND DOOR_DONT_LINK GOLD_KEY SILVER_KEY + + */ + +EntityClass *Eclass_InitFromText( const char *text ){ + EntityClass* e = Eclass_Alloc(); + e->free = &Eclass_Free; // grab the name text = COM_Parse( text ); - e->name = (char*)malloc( strlen( Get_COM_Token() ) + 1 ); - strcpy( e->name, Get_COM_Token() ); - debugname = e->name; - - // grab the color, reformat as texture name - r = sscanf( text," (%f %f %f)", &e->color[0], &e->color[1], &e->color[2] ); - if ( r != 3 ) { - return e; + e->m_name = Get_COM_Token(); + debugname = e->name(); + + { + // grab the color, reformat as texture name + int r = sscanf( text," (%f %f %f)", &e->color[0], &e->color[1], &e->color[2] ); + if ( r != 3 ) { + return e; + } + eclass_capture_state( e ); } - sprintf( color, "(%f %f %f)", e->color[0], e->color[1], e->color[2] ); - //strcpy (e->texdef.name, color); - e->texdef.SetName( color ); while ( *text != ')' ) { if ( !*text ) { - return e; + return 0; } text++; } @@ -162,18 +229,18 @@ eclass_t *Eclass_InitFromText( char *text ){ text = COM_Parse( text ); if ( Get_COM_Token()[0] == '(' ) { // parse the size as two vectors e->fixedsize = true; - r = sscanf( text,"%f %f %f) (%f %f %f)", &e->mins[0], &e->mins[1], &e->mins[2], - &e->maxs[0], &e->maxs[1], &e->maxs[2] ); + int r = sscanf( text,"%f %f %f) (%f %f %f)", &e->mins[0], &e->mins[1], &e->mins[2], + &e->maxs[0], &e->maxs[1], &e->maxs[2] ); if ( r != 6 ) { - return e; + return 0; } - for ( i = 0 ; i < 2 ; i++ ) + for ( int i = 0 ; i < 2 ; i++ ) { while ( *text != ')' ) { if ( !*text ) { - return e; + return 0; } text++; } @@ -181,119 +248,142 @@ eclass_t *Eclass_InitFromText( char *text ){ } } + char parms[256]; // get the flags - - // copy to the first /n - p = parms; - while ( *text && *text != '\n' ) - *p++ = *text++; - *p = 0; - text++; - - // any remaining words are parm flags - p = parms; - for ( i = 0 ; i < MAX_FLAGS ; i++ ) { - p = COM_Parse( p ); - if ( !p ) { - break; - } - strcpy( e->flagnames[i], Get_COM_Token() ); + // copy to the first /n + char* p = parms; + while ( *text && *text != '\n' ) + *p++ = *text++; + *p = 0; + text++; } - // find the length until close comment - for ( t = text ; t[0] && !( t[0] == '*' && t[1] == '/' ) ; t++ ) - ; - - // copy the comment block out - len = t - text; - e->comments = (char*)malloc( len + 1 ); - memcpy( e->comments, text, len ); -#ifdef _WIN32 - // the win32 Gtk widgets are expecting text stuff to be in unix format (that is CR only instead of DOS's CR/LF) - // we convert on the fly by replacing the LF with a ' ' (yeah I'm cheap) - for ( i = 0 ; i < len ; i++ ) - if ( text[i] == '\r' ) { - e->comments[i] = ' '; - } - else{ - e->comments[i] = text[i]; + { + // any remaining words are parm flags + const char* p = parms; + for ( std::size_t i = 0 ; i < MAX_FLAGS ; i++ ) + { + p = COM_Parse( p ); + if ( !p ) { + break; + } + strcpy( e->flagnames[i], Get_COM_Token() ); } -#endif - e->comments[len] = 0; - - setSpecialLoad( e, "model=", e->modelpath ); - setSpecialLoad( e, "skin=", e->skinpath ); - char *pFrame = NULL; - setSpecialLoad( e, "frame=", pFrame ); - if ( pFrame != NULL ) { - e->nFrame = atoi( pFrame ); - delete pFrame; //Hydra - Fixed memory leak! } - if ( !e->skinpath ) { - setSpecialLoad( e, "texture=", e->skinpath ); - } + e->m_comments = text; - // setup show flags - e->nShowFlags = 0; - if ( strcmpi( e->name, "light" ) == 0 || strcmpi( e->name, "dlight" ) == 0 || strcmpi( e->name, "lightjunior" ) == 0 ) { - e->nShowFlags |= ECLASS_LIGHT; - } + setSpecialLoad( e, "model=", e->m_modelpath ); + StringOutputStream buffer( string_length( e->m_modelpath.c_str() ) ); + buffer << PathCleaned( e->m_modelpath.c_str() ); + e->m_modelpath = buffer.c_str(); - if ( ( strnicmp( e->name, "info_player", strlen( "info_player" ) ) == 0 ) - || ( strnicmp( e->name, "path_corner", strlen( "path_corner" ) ) == 0 ) - || ( strnicmp( e->name, "team_ctf", strlen( "team_ctf" ) ) == 0 ) - || ( strnicmp( e->name, "misc_teleporter_dest", strlen( "misc_teleporter_dest" ) ) == 0 ) - ) { - e->nShowFlags |= ECLASS_ANGLE; - } - if ( strcmpi( e->name, "path" ) == 0 ) { - e->nShowFlags |= ECLASS_PATH; + if ( !e->fixedsize ) { + EntityClass_insertAttribute( *e, "angle", EntityClassAttribute( "direction", "Direction", "0" ) ); } - if ( strcmpi( e->name, "misc_model" ) == 0 ) { - e->nShowFlags |= ECLASS_MISCMODEL; + else + { + EntityClass_insertAttribute( *e, "angle", EntityClassAttribute( "angle", "Yaw Angle", "0" ) ); } - + EntityClass_insertAttribute( *e, "model", EntityClassAttribute( "model", "Model" ) ); + EntityClass_insertAttribute( *e, "noise", EntityClassAttribute( "sound", "Sound" ) ); return e; } -void Eclass_ScanFile( char *filename ){ - int size; - char *data; - eclass_t *e; - int i; - char temp[1024]; - - QE_ConvertDOSToUnixName( temp, filename ); +void Eclass_ScanFile( EntityClassCollector& collector, const char *filename ){ + EntityClass *e; - size = vfsLoadFullPathFile( filename, (void**)&data ); - if ( size <= 0 ) { - Sys_FPrintf( SYS_ERR, "Eclass_ScanFile: %s not found\n", filename ); + TextFileInputStream inputFile( filename ); + if ( inputFile.failed() ) { + globalErrorStream() << "ScanFile: " << filename << " not found\n"; return; } - Sys_Printf( "ScanFile: %s\n", temp ); - eclass_found = false; - for ( i = 0 ; i < size ; i++ ) + globalOutputStream() << "ScanFile: " << filename << "\n"; + + enum EParserState + { + eParseDefault, + eParseSolidus, + eParseComment, + eParseQuakeED, + eParseEntityClass, + eParseEntityClassEnd, + } state = eParseDefault; + const char* quakeEd = "QUAKED"; + const char* p = 0; + StringBuffer buffer; + SingleCharacterInputStream bufferedInput( inputFile ); + for (;; ) { - if ( !strncmp( data + i, "/*QUAKED",8 ) ) { - e = Eclass_InitFromText( data + i ); - if ( e ) { - Eclass_InsertAlphabetized( e ); + char c; + if ( !bufferedInput.readChar( c ) ) { + break; + } + + switch ( state ) + { + case eParseDefault: + if ( c == '/' ) { + state = eParseSolidus; + } + break; + case eParseSolidus: + if ( c == '/' ) { + state = eParseComment; + } + else if ( c == '*' ) { + p = quakeEd; + state = eParseQuakeED; + } + break; + case eParseComment: + if ( c == '\n' ) { + state = eParseDefault; + } + break; + case eParseQuakeED: + if ( c == *p ) { + if ( *( ++p ) == '\0' ) { + state = eParseEntityClass; + } + } + else + { + state = eParseDefault; + } + break; + case eParseEntityClass: + if ( c == '*' ) { + state = eParseEntityClassEnd; } - else{ - Sys_FPrintf( SYS_ERR, "Error parsing: %s in %s\n",debugname, filename ); + else + { + buffer.push_back( c ); } + break; + case eParseEntityClassEnd: + if ( c == '/' ) { + e = Eclass_InitFromText( buffer.c_str() ); + state = eParseDefault; + if ( e ) { + collector.insert( e ); + } + else{ + globalErrorStream() << "Error parsing: " << debugname << " in " << filename << "\n"; + } - // single ? - *Get_Eclass_E() = e; - Set_Eclass_Found( true ); - if ( Get_Parsing_Single() ) { - break; + buffer.clear(); + state = eParseDefault; + } + else + { + buffer.push_back( '*' ); + buffer.push_back( c ); + state = eParseEntityClass; } + break; } } - - g_free( data ); }