X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;ds=sidebyside;f=radiant%2Feclass_def.cpp;h=8637b4800c186e1ff3c23d260fe904779ca4fc7f;hb=32dc1da26645b97a5823ff22175000542225c6dd;hp=6c22dbf4c6cdf91b70974e011c41f5e9fcc6bdb4;hpb=80378101101ca1762bbf5638a9e3566893096d8a;p=xonotic%2Fnetradiant.git diff --git a/radiant/eclass_def.cpp b/radiant/eclass_def.cpp index 6c22dbf4..8637b480 100644 --- a/radiant/eclass_def.cpp +++ b/radiant/eclass_def.cpp @@ -1,306 +1,389 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include "cmdlib.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 "eclass_def.h" - -/*! \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; - -CSynapseBuiltinClientDef eclass_def; - -// forward declare, I'm cheap -void Eclass_ScanFile (char *filename); - -const char* EClass_GetExtension() -{ - return "def"; -} - -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); - - 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; - - return true; - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -#include "version.h" - -const char* CSynapseBuiltinClientDef::GetInfo() -{ - return "Builtin .def module built " __DATE__ " " RADIANT_VERSION; -} - -// ------------------------------------------------------------------------------------------------ - -qboolean eclass_found; -char *debugname; - -void setSpecialLoad(eclass_t *e, const char* pWhat, char*& p) -{ - // Hydra: removed some amazingly bad cstring usage, whoever wrote that - // needs to be taken out and shot. - - char *pText = NULL; - char *where = NULL; - - p = NULL; // incase we don't find what we're looking for. - where = strstr(e->comments,pWhat); - if (!where) - return; - - pText = where + strlen(pWhat); - if (*pText == '\"') - pText++; - - 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 - } - else - p = strdup(pText); -} - -eclass_t *Eclass_InitFromText (char *text) -{ - char *t; - int len; - int r, i; - char parms[256], *p; - eclass_t *e; - char color[128]; - - e = (eclass_t*)malloc(sizeof(*e)); - memset (e, 0, sizeof(*e)); - - text += strlen("/*QUAKED "); - - // 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; - } - 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; - } - text++; - } - text++; - - // get the size - 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]); - if (r != 6) { - return e; - } - - for (i=0 ; i<2 ; i++) - { - while (*text != ')') - { - if (!*text) { - return e; - } - text++; - } - text++; - } - } - - // 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 ; iflagnames[i], Get_COM_Token()); - } - - // 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 ; icomments[i] = ' '; - else - e->comments[i] = text[i]; -#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); - - // 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; - } - - 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 (strcmpi(e->name, "misc_model") == 0) - { - e->nShowFlags |= ECLASS_MISCMODEL; - } - - - return e; -} - -void Eclass_ScanFile (char *filename) -{ - int size; - char *data; - eclass_t *e; - int i; - char temp[1024]; - - QE_ConvertDOSToUnixName( temp, filename ); - - size = vfsLoadFullPathFile(filename, (void**)&data); - if (size <= 0) - { - Sys_FPrintf (SYS_ERR, "Eclass_ScanFile: %s not found\n", filename); - return; - } - Sys_Printf ("ScanFile: %s\n", temp); - eclass_found = false; - for (i=0 ; i EclassDefModule; +typedef Static StaticEclassDefModule; +StaticRegisterModule staticRegisterEclassDef( StaticEclassDefModule::instance() ); + + +#include "string/string.h" + +#include + + +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; + } + +// skip whitespace +skipwhite: + while ( ( c = *data ) <= ' ' ) + { + if ( c == 0 ) { + com_eof = true; + return 0; // end of file; + } + data++; + } + +// skip // comments + if ( c == '/' && data[1] == '/' ) { + while ( *data && *data != '\n' ) + data++; + goto skipwhite; + } + + +// 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; +} + + +const char *debugname; + +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. + + const char *pText = 0; + const char *where = 0; + + where = strstr( e->comments(),pWhat ); + if ( !where ) { + return; + } + + pText = where + strlen( pWhat ); + if ( *pText == '\"' ) { + pText++; + } + + where = strchr( pText,'\"' ); + if ( where ) { + p = StringRange( pText, where ); + } + else + { + p = pText; + } +} + +#include "eclasslib.h" + +/* + + the classname, color triple, and bounding box are parsed out of comments + A ? size means take the exact brush size. + + / *QUAKED (0 0 0) ? + / *QUAKED (0 0 0) (-8 -8 -8) (8 8 8) + + 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->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 ); + } + + while ( *text != ')' ) + { + if ( !*text ) { + return 0; + } + text++; + } + text++; + + // get the size + text = COM_Parse( text ); + if ( Get_COM_Token()[0] == '(' ) { // parse the size as two vectors + e->fixedsize = true; + 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 0; + } + + for ( int i = 0 ; i < 2 ; i++ ) + { + while ( *text != ')' ) + { + if ( !*text ) { + return 0; + } + text++; + } + text++; + } + } + + char parms[256]; + // get the flags + { + // copy to the first /n + char* p = parms; + while ( *text && *text != '\n' ) + *p++ = *text++; + *p = 0; + text++; + } + + { + // 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() ); + } + } + + e->m_comments = text; + + 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 ( !e->fixedsize ) { + EntityClass_insertAttribute( *e, "angle", EntityClassAttribute( "direction", "Direction", "0" ) ); + } + 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( EntityClassCollector& collector, const char *filename ){ + EntityClass *e; + + TextFileInputStream inputFile( filename ); + if ( inputFile.failed() ) { + globalErrorStream() << "ScanFile: " << filename << " not found\n"; + return; + } + 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 (;; ) + { + 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 + { + 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"; + } + + buffer.clear(); + state = eParseDefault; + } + else + { + buffer.push_back( '*' ); + buffer.push_back( c ); + state = eParseEntityClass; + } + break; + } + } +}