X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=radiant%2Feclass_doom3.cpp;h=247c160bb3e3c7185938c1f2952bbbee4cac41bb;hb=9dfae1c9b270ee369c6362903a9205b30751b95f;hp=620cc276808309c33c868327dfb7e8e78aa30c62;hpb=62d99f889c0e98be65f779d3983109c84ce58cec;p=xonotic%2Fnetradiant.git diff --git a/radiant/eclass_doom3.cpp b/radiant/eclass_doom3.cpp index 620cc276..247c160b 100644 --- a/radiant/eclass_doom3.cpp +++ b/radiant/eclass_doom3.cpp @@ -39,776 +39,784 @@ #include "moduleobservers.h" #include "stringio.h" -class RawString -{ -const char* m_value; +class RawString { + const char *m_value; public: -RawString( const char* value ) : m_value( value ){ -} -const char* c_str() const { - return m_value; -} + RawString(const char *value) : m_value(value) + { + } + + const char *c_str() const + { + return m_value; + } }; -inline bool operator<( const RawString& self, const RawString& other ){ - return string_less_nocase( self.c_str(), other.c_str() ); +inline bool operator<(const RawString &self, const RawString &other) +{ + return string_less_nocase(self.c_str(), other.c_str()); } -typedef std::map EntityClasses; +typedef std::map EntityClasses; EntityClasses g_EntityClassDoom3_classes; EntityClass *g_EntityClassDoom3_bad = 0; -void EntityClassDoom3_clear(){ - for ( EntityClasses::iterator i = g_EntityClassDoom3_classes.begin(); i != g_EntityClassDoom3_classes.end(); ++i ) - { - ( *i ).second->free( ( *i ).second ); - } - g_EntityClassDoom3_classes.clear(); +void EntityClassDoom3_clear() +{ + for (EntityClasses::iterator i = g_EntityClassDoom3_classes.begin(); i != g_EntityClassDoom3_classes.end(); ++i) { + (*i).second->free((*i).second); + } + g_EntityClassDoom3_classes.clear(); } // entityClass will be inserted only if another of the same name does not already exist. // if entityClass was inserted, the same object is returned, otherwise the already-existing object is returned. -EntityClass* EntityClassDoom3_insertUnique( EntityClass* entityClass ){ - return ( *g_EntityClassDoom3_classes.insert( EntityClasses::value_type( entityClass->name(), entityClass ) ).first ).second; +EntityClass *EntityClassDoom3_insertUnique(EntityClass *entityClass) +{ + return (*g_EntityClassDoom3_classes.insert( + EntityClasses::value_type(entityClass->name(), entityClass)).first).second; } -void EntityClassDoom3_forEach( EntityClassVisitor& visitor ){ - for ( EntityClasses::iterator i = g_EntityClassDoom3_classes.begin(); i != g_EntityClassDoom3_classes.end(); ++i ) - { - visitor.visit( ( *i ).second ); - } +void EntityClassDoom3_forEach(EntityClassVisitor &visitor) +{ + for (EntityClasses::iterator i = g_EntityClassDoom3_classes.begin(); i != g_EntityClassDoom3_classes.end(); ++i) { + visitor.visit((*i).second); + } } -inline void printParseError( const char* message ){ - globalErrorStream() << message; +inline void printParseError(const char *message) +{ + globalErrorStream() << message; } -#define PARSE_RETURN_FALSE_IF_FAIL( expression ) if ( !( expression ) ) { printParseError( FILE_LINE "\nparse failed: " # expression "\n" ); return false; } else +#define PARSE_RETURN_FALSE_IF_FAIL(expression) do { if (!( expression)) { printParseError(FILE_LINE "\nparse failed: " #expression "\n"); return false; } } while (0) -bool EntityClassDoom3_parseToken( Tokeniser& tokeniser ){ - const char* token = tokeniser.getToken(); - PARSE_RETURN_FALSE_IF_FAIL( token != 0 ); - return true; +bool EntityClassDoom3_parseToken(Tokeniser &tokeniser) +{ + const char *token = tokeniser.getToken(); + PARSE_RETURN_FALSE_IF_FAIL(token != 0); + return true; } -bool EntityClassDoom3_parseToken( Tokeniser& tokeniser, const char* string ){ - const char* token = tokeniser.getToken(); - PARSE_RETURN_FALSE_IF_FAIL( token != 0 ); - return string_equal( token, string ); +bool EntityClassDoom3_parseToken(Tokeniser &tokeniser, const char *string) +{ + const char *token = tokeniser.getToken(); + PARSE_RETURN_FALSE_IF_FAIL(token != 0); + return string_equal(token, string); } -bool EntityClassDoom3_parseString( Tokeniser& tokeniser, const char*& s ){ - const char* token = tokeniser.getToken(); - PARSE_RETURN_FALSE_IF_FAIL( token != 0 ); - s = token; - return true; +bool EntityClassDoom3_parseString(Tokeniser &tokeniser, const char *&s) +{ + const char *token = tokeniser.getToken(); + PARSE_RETURN_FALSE_IF_FAIL(token != 0); + s = token; + return true; } -bool EntityClassDoom3_parseString( Tokeniser& tokeniser, CopiedString& s ){ - const char* token = tokeniser.getToken(); - PARSE_RETURN_FALSE_IF_FAIL( token != 0 ); - s = token; - return true; +bool EntityClassDoom3_parseString(Tokeniser &tokeniser, CopiedString &s) +{ + const char *token = tokeniser.getToken(); + PARSE_RETURN_FALSE_IF_FAIL(token != 0); + s = token; + return true; } -bool EntityClassDoom3_parseString( Tokeniser& tokeniser, StringOutputStream& s ){ - const char* token = tokeniser.getToken(); - PARSE_RETURN_FALSE_IF_FAIL( token != 0 ); - s << token; - return true; +bool EntityClassDoom3_parseString(Tokeniser &tokeniser, StringOutputStream &s) +{ + const char *token = tokeniser.getToken(); + PARSE_RETURN_FALSE_IF_FAIL(token != 0); + s << token; + return true; } -bool EntityClassDoom3_parseUnknown( Tokeniser& tokeniser ){ - //const char* name = - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser ) ); +bool EntityClassDoom3_parseUnknown(Tokeniser &tokeniser) +{ + //const char* name = + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser)); - //globalOutputStream() << "parsing unknown block " << makeQuoted(name) << "\n"; + //globalOutputStream() << "parsing unknown block " << makeQuoted(name) << "\n"; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser, "{" ) ); - tokeniser.nextLine(); + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser, "{")); + tokeniser.nextLine(); - std::size_t depth = 1; - for (;; ) - { - const char* token; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, token ) ); - if ( string_equal( token, "}" ) ) { - if ( --depth == 0 ) { - tokeniser.nextLine(); - break; - } - } - else if ( string_equal( token, "{" ) ) { - ++depth; - } - tokeniser.nextLine(); - } - return true; + std::size_t depth = 1; + for (;;) { + const char *token; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, token)); + if (string_equal(token, "}")) { + if (--depth == 0) { + tokeniser.nextLine(); + break; + } + } else if (string_equal(token, "{")) { + ++depth; + } + tokeniser.nextLine(); + } + return true; } -class Model -{ +class Model { public: -bool m_resolved; -CopiedString m_mesh; -CopiedString m_skin; -CopiedString m_parent; -typedef std::map Anims; -Anims m_anims; -Model() : m_resolved( false ){ -} + bool m_resolved; + CopiedString m_mesh; + CopiedString m_skin; + CopiedString m_parent; + typedef std::map Anims; + Anims m_anims; + + Model() : m_resolved(false) + { + } }; typedef std::map Models; Models g_models; -void Model_resolveInheritance( const char* name, Model& model ){ - if ( model.m_resolved == false ) { - model.m_resolved = true; - - if ( !string_empty( model.m_parent.c_str() ) ) { - Models::iterator i = g_models.find( model.m_parent ); - if ( i == g_models.end() ) { - globalErrorStream() << "model " << name << " inherits unknown model " << model.m_parent.c_str() << "\n"; - } - else - { - Model_resolveInheritance( ( *i ).first.c_str(), ( *i ).second ); - model.m_mesh = ( *i ).second.m_mesh; - model.m_skin = ( *i ).second.m_skin; - } - } - } -} - -bool EntityClassDoom3_parseModel( Tokeniser& tokeniser ){ - const char* name; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, name ) ); - - Model& model = g_models[name]; - - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser, "{" ) ); - tokeniser.nextLine(); - - for (;; ) - { - const char* parameter; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, parameter ) ); - if ( string_equal( parameter, "}" ) ) { - tokeniser.nextLine(); - break; - } - else if ( string_equal( parameter, "inherit" ) ) { - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, model.m_parent ) ); - tokeniser.nextLine(); - } - else if ( string_equal( parameter, "remove" ) ) { - //const char* remove = - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser ) ); - tokeniser.nextLine(); - } - else if ( string_equal( parameter, "mesh" ) ) { - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, model.m_mesh ) ); - tokeniser.nextLine(); - } - else if ( string_equal( parameter, "skin" ) ) { - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, model.m_skin ) ); - tokeniser.nextLine(); - } - else if ( string_equal( parameter, "offset" ) ) { - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser, "(" ) ); - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser ) ); - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser ) ); - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser ) ); - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser, ")" ) ); - tokeniser.nextLine(); - } - else if ( string_equal( parameter, "channel" ) ) { - //const char* channelName = - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser ) ); - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser, "(" ) ); - for (;; ) - { - const char* end; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, end ) ); - if ( string_equal( end, ")" ) ) { - tokeniser.nextLine(); - break; - } - } - } - else if ( string_equal( parameter, "anim" ) ) { - CopiedString animName; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, animName ) ); - const char* animFile; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, animFile ) ); - model.m_anims.insert( Model::Anims::value_type( animName, animFile ) ); - - const char* token; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, token ) ); - - while ( string_equal( token, "," ) ) - { - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, animFile ) ); - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, token ) ); - } - - if ( string_equal( token, "{" ) ) { - for (;; ) - { - const char* end; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, end ) ); - if ( string_equal( end, "}" ) ) { - tokeniser.nextLine(); - break; - } - tokeniser.nextLine(); - } - } - else - { - tokeniser.ungetToken(); - } - } - else - { - globalErrorStream() << "unknown model parameter: " << makeQuoted( parameter ) << "\n"; - return false; - } - tokeniser.nextLine(); - } - return true; -} - -inline bool char_isSpaceOrTab( char c ){ - return c == ' ' || c == '\t'; -} - -inline bool char_isNotSpaceOrTab( char c ){ - return !char_isSpaceOrTab( c ); +void Model_resolveInheritance(const char *name, Model &model) +{ + if (model.m_resolved == false) { + model.m_resolved = true; + + if (!string_empty(model.m_parent.c_str())) { + Models::iterator i = g_models.find(model.m_parent); + if (i == g_models.end()) { + globalErrorStream() << "model " << name << " inherits unknown model " << model.m_parent.c_str() << "\n"; + } else { + Model_resolveInheritance((*i).first.c_str(), (*i).second); + model.m_mesh = (*i).second.m_mesh; + model.m_skin = (*i).second.m_skin; + } + } + } +} + +bool EntityClassDoom3_parseModel(Tokeniser &tokeniser) +{ + const char *name; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, name)); + + Model &model = g_models[name]; + + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser, "{")); + tokeniser.nextLine(); + + for (;;) { + const char *parameter; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, parameter)); + if (string_equal(parameter, "}")) { + tokeniser.nextLine(); + break; + } else if (string_equal(parameter, "inherit")) { + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, model.m_parent)); + tokeniser.nextLine(); + } else if (string_equal(parameter, "remove")) { + //const char* remove = + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser)); + tokeniser.nextLine(); + } else if (string_equal(parameter, "mesh")) { + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, model.m_mesh)); + tokeniser.nextLine(); + } else if (string_equal(parameter, "skin")) { + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, model.m_skin)); + tokeniser.nextLine(); + } else if (string_equal(parameter, "offset")) { + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser, "(")); + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser)); + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser)); + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser)); + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser, ")")); + tokeniser.nextLine(); + } else if (string_equal(parameter, "channel")) { + //const char* channelName = + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser)); + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser, "(")); + for (;;) { + const char *end; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, end)); + if (string_equal(end, ")")) { + tokeniser.nextLine(); + break; + } + } + } else if (string_equal(parameter, "anim")) { + CopiedString animName; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, animName)); + const char *animFile; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, animFile)); + model.m_anims.insert(Model::Anims::value_type(animName, animFile)); + + const char *token; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, token)); + + while (string_equal(token, ",")) { + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, animFile)); + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, token)); + } + + if (string_equal(token, "{")) { + for (;;) { + const char *end; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, end)); + if (string_equal(end, "}")) { + tokeniser.nextLine(); + break; + } + tokeniser.nextLine(); + } + } else { + tokeniser.ungetToken(); + } + } else { + globalErrorStream() << "unknown model parameter: " << makeQuoted(parameter) << "\n"; + return false; + } + tokeniser.nextLine(); + } + return true; +} + +inline bool char_isSpaceOrTab(char c) +{ + return c == ' ' || c == '\t'; } -template -inline const char* string_find_if( const char* string, Predicate predicate ){ - for (; *string != 0; ++string ) - { - if ( predicate( *string ) ) { - return string; - } - } - return string; -} - -inline const char* string_findFirstSpaceOrTab( const char* string ){ - return string_find_if( string, char_isSpaceOrTab ); -} - -inline const char* string_findFirstNonSpaceOrTab( const char* string ){ - return string_find_if( string, char_isNotSpaceOrTab ); -} - - -static bool EntityClass_parse( EntityClass& entityClass, Tokeniser& tokeniser ){ - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, entityClass.m_name ) ); - - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser, "{" ) ); - tokeniser.nextLine(); - - StringOutputStream usage( 256 ); - StringOutputStream description( 256 ); - CopiedString* currentDescription = 0; - StringOutputStream* currentString = 0; - - for (;; ) - { - const char* key; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, key ) ); - - const char* last = string_findFirstSpaceOrTab( key ); - CopiedString first( StringRange( key, last ) ); - - if ( !string_empty( last ) ) { - last = string_findFirstNonSpaceOrTab( last ); - } - - if ( currentString != 0 && string_equal( key, "\\" ) ) { - tokeniser.nextLine(); - *currentString << " "; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, *currentString ) ); - continue; - } - - if ( currentDescription != 0 ) { - *currentDescription = description.c_str(); - description.clear(); - currentDescription = 0; - } - currentString = 0; - - if ( string_equal( key, "}" ) ) { - tokeniser.nextLine(); - break; - } - else if ( string_equal( key, "model" ) ) { - const char* token; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, token ) ); - entityClass.fixedsize = true; - StringOutputStream buffer( 256 ); - buffer << PathCleaned( token ); - entityClass.m_modelpath = buffer.c_str(); - } - else if ( string_equal( key, "editor_color" ) ) { - const char* value; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, value ) ); - if ( !string_empty( value ) ) { - entityClass.colorSpecified = true; - bool success = string_parse_vector3( value, entityClass.color ); - ASSERT_MESSAGE( success, "editor_color: parse error" ); - } - } - else if ( string_equal( key, "editor_ragdoll" ) ) { - //bool ragdoll = atoi(tokeniser.getToken()) != 0; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser ) ); - } - else if ( string_equal( key, "editor_mins" ) ) { - entityClass.sizeSpecified = true; - const char* value; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, value ) ); - if ( !string_empty( value ) && !string_equal( value, "?" ) ) { - entityClass.fixedsize = true; - bool success = string_parse_vector3( value, entityClass.mins ); - ASSERT_MESSAGE( success, "editor_mins: parse error" ); - } - } - else if ( string_equal( key, "editor_maxs" ) ) { - entityClass.sizeSpecified = true; - const char* value; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, value ) ); - if ( !string_empty( value ) && !string_equal( value, "?" ) ) { - entityClass.fixedsize = true; - bool success = string_parse_vector3( value, entityClass.maxs ); - ASSERT_MESSAGE( success, "editor_maxs: parse error" ); - } - } - else if ( string_equal( key, "editor_usage" ) ) { - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, usage ) ); - currentString = &usage; - } - else if ( string_equal_n( key, "editor_usage", 12 ) ) { - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, usage ) ); - currentString = &usage; - } - else if ( string_equal( key, "editor_rotatable" ) - || string_equal( key, "editor_showangle" ) - || string_equal( key, "editor_showangles" ) // typo? in prey movables.def - || string_equal( key, "editor_mover" ) - || string_equal( key, "editor_model" ) - || string_equal( key, "editor_material" ) - || string_equal( key, "editor_combatnode" ) - || ( !string_empty( last ) && string_equal( first.c_str(), "editor_gui" ) ) - || string_equal_n( key, "editor_copy", 11 ) ) { - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser ) ); - } - else if ( !string_empty( last ) && ( string_equal( first.c_str(), "editor_var" ) || string_equal( first.c_str(), "editor_string" ) ) ) { - EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, last ).second; - attribute.m_type = "string"; - currentDescription = &attribute.m_description; - currentString = &description; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, description ) ); - } - else if ( !string_empty( last ) && string_equal( first.c_str(), "editor_float" ) ) { - EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, last ).second; - attribute.m_type = "string"; - currentDescription = &attribute.m_description; - currentString = &description; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, description ) ); - } - else if ( !string_empty( last ) && string_equal( first.c_str(), "editor_snd" ) ) { - EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, last ).second; - attribute.m_type = "sound"; - currentDescription = &attribute.m_description; - currentString = &description; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, description ) ); - } - else if ( !string_empty( last ) && string_equal( first.c_str(), "editor_bool" ) ) { - EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, last ).second; - attribute.m_type = "boolean"; - currentDescription = &attribute.m_description; - currentString = &description; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, description ) ); - } - else if ( !string_empty( last ) && string_equal( first.c_str(), "editor_int" ) ) { - EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, last ).second; - attribute.m_type = "integer"; - currentDescription = &attribute.m_description; - currentString = &description; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, description ) ); - } - else if ( !string_empty( last ) && string_equal( first.c_str(), "editor_model" ) ) { - EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, last ).second; - attribute.m_type = "model"; - currentDescription = &attribute.m_description; - currentString = &description; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, description ) ); - } - else if ( !string_empty( last ) && string_equal( first.c_str(), "editor_color" ) ) { - EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, last ).second; - attribute.m_type = "color"; - currentDescription = &attribute.m_description; - currentString = &description; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, description ) ); - } - else if ( !string_empty( last ) && ( string_equal( first.c_str(), "editor_material" ) || string_equal( first.c_str(), "editor_mat" ) ) ) { - EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, last ).second; - attribute.m_type = "shader"; - currentDescription = &attribute.m_description; - currentString = &description; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, description ) ); - } - else if ( string_equal( key, "inherit" ) ) { - entityClass.inheritanceResolved = false; - ASSERT_MESSAGE( entityClass.m_parent.empty(), "only one 'inherit' supported per entityDef" ); - const char* token; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, token ) ); - entityClass.m_parent.push_back( token ); - } - // begin quake4-specific keys - else if ( string_equal( key, "editor_targetonsel" ) ) { - //const char* value = - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser ) ); - } - else if ( string_equal( key, "editor_menu" ) ) { - //const char* value = - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser ) ); - } - else if ( string_equal( key, "editor_ignore" ) ) { - //const char* value = - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser ) ); - } - // end quake4-specific keys - // begin ignore prey (unknown/unused?) entity keys - else if ( string_equal( key, "editor_light" ) - || string_equal( key, "editor_def def_debrisspawner" ) - || string_equal( key, "editor_def def_drop" ) - || string_equal( key, "editor_def def_guihand" ) - || string_equal( key, "editor_def def_mine" ) ) { - //const char* value = - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser ) ); - } - // end ignore prey entity keys - else - { - CopiedString tmp( key ); - ASSERT_MESSAGE( !string_equal_n( key, "editor_", 7 ), "unsupported editor key: " << makeQuoted( key ) ); - EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, key ).second; - attribute.m_type = "string"; - const char* value; - PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, value ) ); - if ( string_equal( value, "}" ) ) { // hack for quake4 powerups.def bug - globalErrorStream() << "entityDef " << makeQuoted( entityClass.m_name.c_str() ) << " key " << makeQuoted( tmp.c_str() ) << " has no value\n"; - break; - } - else - { - attribute.m_value = value; - } - } - tokeniser.nextLine(); - } - - entityClass.m_comments = usage.c_str(); - - if ( string_equal( entityClass.m_name.c_str(), "light" ) ) { - { - EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, "light_radius" ).second; - attribute.m_type = "vector3"; - attribute.m_value = "300 300 300"; - } - { - EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, "light_center" ).second; - attribute.m_type = "vector3"; - } - { - EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, "noshadows" ).second; - attribute.m_type = "boolean"; - attribute.m_value = "0"; - } - { - EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, "nospecular" ).second; - attribute.m_type = "boolean"; - attribute.m_value = "0"; - } - { - EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, "nodiffuse" ).second; - attribute.m_type = "boolean"; - attribute.m_value = "0"; - } - { - EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, "falloff" ).second; - attribute.m_type = "real"; - } - } - - return true; -} - -bool EntityClassDoom3_parseEntityDef( Tokeniser& tokeniser ){ - EntityClass* entityClass = Eclass_Alloc(); - entityClass->free = &Eclass_Free; - - if ( !EntityClass_parse( *entityClass, tokeniser ) ) { - eclass_capture_state( entityClass ); // finish constructing the entity so that it can be destroyed cleanly. - entityClass->free( entityClass ); - return false; - } - - EntityClass* inserted = EntityClassDoom3_insertUnique( entityClass ); - if ( inserted != entityClass ) { - globalErrorStream() << "entityDef " << entityClass->name() << " is already defined, second definition ignored\n"; - eclass_capture_state( entityClass ); // finish constructing the entity so that it can be destroyed cleanly. - entityClass->free( entityClass ); - } - return true; -} - -bool EntityClassDoom3_parseBlock( Tokeniser& tokeniser, const char* blockType ){ - if ( string_equal( blockType, "entityDef" ) ) { - return EntityClassDoom3_parseEntityDef( tokeniser ); - } - else if ( string_equal( blockType, "model" ) ) { - return EntityClassDoom3_parseModel( tokeniser ); - } - else - { - return EntityClassDoom3_parseUnknown( tokeniser ); - } -} - -bool EntityClassDoom3_parse( TextInputStream& inputStream, const char* filename ){ - Tokeniser& tokeniser = GlobalScriptLibrary().m_pfnNewScriptTokeniser( inputStream ); - - tokeniser.nextLine(); - - for (;; ) - { - const char* blockType = tokeniser.getToken(); - if ( blockType == 0 ) { - return true; - } - CopiedString tmp( blockType ); - if ( !EntityClassDoom3_parseBlock( tokeniser, tmp.c_str() ) ) { - globalErrorStream() << GlobalFileSystem().findFile( filename ) << filename << ":" << (unsigned int)tokeniser.getLine() << ": " << tmp.c_str() << " parse failed, skipping rest of file\n"; - return false; - } - } - - tokeniser.release(); -} - - -void EntityClassDoom3_loadFile( const char* filename ){ - globalOutputStream() << "parsing entity classes from " << makeQuoted( filename ) << "\n"; - - StringOutputStream fullname( 256 ); - fullname << "def/" << filename; - - ArchiveTextFile* file = GlobalFileSystem().openTextFile( fullname.c_str() ); - if ( file != 0 ) { - EntityClassDoom3_parse( file->getInputStream(), fullname.c_str() ); - file->release(); - } -} - -EntityClass* EntityClassDoom3_findOrInsert( const char *name, bool has_brushes ){ - ASSERT_NOTNULL( name ); - - if ( string_empty( name ) ) { - return g_EntityClassDoom3_bad; - } - - EntityClasses::iterator i = g_EntityClassDoom3_classes.find( name ); - if ( i != g_EntityClassDoom3_classes.end() - //&& string_equal((*i).first, name) - ) { - return ( *i ).second; - } - - EntityClass* e = EntityClass_Create_Default( name, has_brushes ); - EntityClass* inserted = EntityClassDoom3_insertUnique( e ); - ASSERT_MESSAGE( inserted == e, "" ); - return inserted; -} - -const ListAttributeType* EntityClassDoom3_findListType( const char* name ){ - return 0; -} - - -void EntityClass_resolveInheritance( EntityClass* derivedClass ){ - if ( derivedClass->inheritanceResolved == false ) { - derivedClass->inheritanceResolved = true; - EntityClasses::iterator i = g_EntityClassDoom3_classes.find( derivedClass->m_parent.front().c_str() ); - if ( i == g_EntityClassDoom3_classes.end() ) { - globalErrorStream() << "failed to find entityDef " << makeQuoted( derivedClass->m_parent.front().c_str() ) << " inherited by " << makeQuoted( derivedClass->m_name.c_str() ) << "\n"; - } - else - { - EntityClass* parentClass = ( *i ).second; - EntityClass_resolveInheritance( parentClass ); - if ( !derivedClass->colorSpecified ) { - derivedClass->colorSpecified = parentClass->colorSpecified; - derivedClass->color = parentClass->color; - } - if ( !derivedClass->sizeSpecified ) { - derivedClass->sizeSpecified = parentClass->sizeSpecified; - derivedClass->mins = parentClass->mins; - derivedClass->maxs = parentClass->maxs; - derivedClass->fixedsize = parentClass->fixedsize; - } - - for ( EntityClassAttributes::iterator j = parentClass->m_attributes.begin(); j != parentClass->m_attributes.end(); ++j ) - { - EntityClass_insertAttribute( *derivedClass, ( *j ).first.c_str(), ( *j ).second ); - } - } - } -} - -class EntityClassDoom3 : public ModuleObserver -{ -std::size_t m_unrealised; -ModuleObservers m_observers; -public: -EntityClassDoom3() : m_unrealised( 2 ){ -} -void realise(){ - if ( --m_unrealised == 0 ) { - globalOutputStream() << "searching vfs directory " << makeQuoted( "def" ) << " for *.def\n"; - GlobalFileSystem().forEachFile( "def/", "def", FreeCaller1() ); - - { - for ( Models::iterator i = g_models.begin(); i != g_models.end(); ++i ) - { - Model_resolveInheritance( ( *i ).first.c_str(), ( *i ).second ); - } - } - { - for ( EntityClasses::iterator i = g_EntityClassDoom3_classes.begin(); i != g_EntityClassDoom3_classes.end(); ++i ) - { - EntityClass_resolveInheritance( ( *i ).second ); - if ( !string_empty( ( *i ).second->m_modelpath.c_str() ) ) { - Models::iterator j = g_models.find( ( *i ).second->m_modelpath ); - if ( j != g_models.end() ) { - ( *i ).second->m_modelpath = ( *j ).second.m_mesh; - ( *i ).second->m_skin = ( *j ).second.m_skin; - } - } - eclass_capture_state( ( *i ).second ); - - StringOutputStream usage( 256 ); - - usage << "-------- NOTES --------\n"; - - if ( !string_empty( ( *i ).second->m_comments.c_str() ) ) { - usage << ( *i ).second->m_comments.c_str() << "\n"; - } - - usage << "\n-------- KEYS --------\n"; - - for ( EntityClassAttributes::iterator j = ( *i ).second->m_attributes.begin(); j != ( *i ).second->m_attributes.end(); ++j ) - { - const char* name = EntityClassAttributePair_getName( *j ); - const char* description = EntityClassAttributePair_getDescription( *j ); - if ( !string_equal( name, description ) ) { - usage << EntityClassAttributePair_getName( *j ) << " : " << EntityClassAttributePair_getDescription( *j ) << "\n"; - } - } - - ( *i ).second->m_comments = usage.c_str(); - } - } - - m_observers.realise(); - } -} -void unrealise(){ - if ( ++m_unrealised == 1 ) { - m_observers.unrealise(); - EntityClassDoom3_clear(); - } -} -void attach( ModuleObserver& observer ){ - m_observers.attach( observer ); -} -void detach( ModuleObserver& observer ){ - m_observers.detach( observer ); +inline bool char_isNotSpaceOrTab(char c) +{ + return !char_isSpaceOrTab(c); } -}; -EntityClassDoom3 g_EntityClassDoom3; +template +inline const char *string_find_if(const char *string, Predicate predicate) +{ + for (; *string != 0; ++string) { + if (predicate(*string)) { + return string; + } + } + return string; +} -void EntityClassDoom3_attach( ModuleObserver& observer ){ - g_EntityClassDoom3.attach( observer ); +inline const char *string_findFirstSpaceOrTab(const char *string) +{ + return string_find_if(string, char_isSpaceOrTab); } -void EntityClassDoom3_detach( ModuleObserver& observer ){ - g_EntityClassDoom3.detach( observer ); + +inline const char *string_findFirstNonSpaceOrTab(const char *string) +{ + return string_find_if(string, char_isNotSpaceOrTab); } -void EntityClassDoom3_realise(){ - g_EntityClassDoom3.realise(); + +static bool EntityClass_parse(EntityClass &entityClass, Tokeniser &tokeniser) +{ + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, entityClass.m_name)); + + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser, "{")); + tokeniser.nextLine(); + + StringOutputStream usage(256); + StringOutputStream description(256); + CopiedString *currentDescription = 0; + StringOutputStream *currentString = 0; + + for (;;) { + const char *key; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, key)); + + const char *last = string_findFirstSpaceOrTab(key); + CopiedString first(StringRange(key, last)); + + if (!string_empty(last)) { + last = string_findFirstNonSpaceOrTab(last); + } + + if (currentString != 0 && string_equal(key, "\\")) { + tokeniser.nextLine(); + *currentString << " "; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, *currentString)); + continue; + } + + if (currentDescription != 0) { + *currentDescription = description.c_str(); + description.clear(); + currentDescription = 0; + } + currentString = 0; + + if (string_equal(key, "}")) { + tokeniser.nextLine(); + break; + } else if (string_equal(key, "model")) { + const char *token; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, token)); + entityClass.fixedsize = true; + StringOutputStream buffer(256); + buffer << PathCleaned(token); + entityClass.m_modelpath = buffer.c_str(); + } else if (string_equal(key, "editor_color")) { + const char *value; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, value)); + if (!string_empty(value)) { + entityClass.colorSpecified = true; + bool success = string_parse_vector3(value, entityClass.color); + ASSERT_MESSAGE(success, "editor_color: parse error"); + } + } else if (string_equal(key, "editor_ragdoll")) { + //bool ragdoll = atoi(tokeniser.getToken()) != 0; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser)); + } else if (string_equal(key, "editor_mins")) { + entityClass.sizeSpecified = true; + const char *value; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, value)); + if (!string_empty(value) && !string_equal(value, "?")) { + entityClass.fixedsize = true; + bool success = string_parse_vector3(value, entityClass.mins); + ASSERT_MESSAGE(success, "editor_mins: parse error"); + } + } else if (string_equal(key, "editor_maxs")) { + entityClass.sizeSpecified = true; + const char *value; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, value)); + if (!string_empty(value) && !string_equal(value, "?")) { + entityClass.fixedsize = true; + bool success = string_parse_vector3(value, entityClass.maxs); + ASSERT_MESSAGE(success, "editor_maxs: parse error"); + } + } else if (string_equal(key, "editor_usage")) { + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, usage)); + currentString = &usage; + } else if (string_equal_n(key, "editor_usage", 12)) { + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, usage)); + currentString = &usage; + } else if (string_equal(key, "editor_rotatable") + || string_equal(key, "editor_showangle") + || string_equal(key, "editor_showangles") // typo? in prey movables.def + || string_equal(key, "editor_mover") + || string_equal(key, "editor_model") + || string_equal(key, "editor_material") + || string_equal(key, "editor_combatnode") + || (!string_empty(last) && string_equal(first.c_str(), "editor_gui")) + || string_equal_n(key, "editor_copy", 11)) { + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser)); + } else if (!string_empty(last) && + (string_equal(first.c_str(), "editor_var") || string_equal(first.c_str(), "editor_string"))) { + EntityClassAttribute &attribute = EntityClass_insertAttribute(entityClass, last).second; + attribute.m_type = "string"; + currentDescription = &attribute.m_description; + currentString = &description; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description)); + } else if (!string_empty(last) && string_equal(first.c_str(), "editor_float")) { + EntityClassAttribute &attribute = EntityClass_insertAttribute(entityClass, last).second; + attribute.m_type = "string"; + currentDescription = &attribute.m_description; + currentString = &description; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description)); + } else if (!string_empty(last) && string_equal(first.c_str(), "editor_snd")) { + EntityClassAttribute &attribute = EntityClass_insertAttribute(entityClass, last).second; + attribute.m_type = "sound"; + currentDescription = &attribute.m_description; + currentString = &description; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description)); + } else if (!string_empty(last) && string_equal(first.c_str(), "editor_bool")) { + EntityClassAttribute &attribute = EntityClass_insertAttribute(entityClass, last).second; + attribute.m_type = "boolean"; + currentDescription = &attribute.m_description; + currentString = &description; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description)); + } else if (!string_empty(last) && string_equal(first.c_str(), "editor_int")) { + EntityClassAttribute &attribute = EntityClass_insertAttribute(entityClass, last).second; + attribute.m_type = "integer"; + currentDescription = &attribute.m_description; + currentString = &description; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description)); + } else if (!string_empty(last) && string_equal(first.c_str(), "editor_model")) { + EntityClassAttribute &attribute = EntityClass_insertAttribute(entityClass, last).second; + attribute.m_type = "model"; + currentDescription = &attribute.m_description; + currentString = &description; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description)); + } else if (!string_empty(last) && string_equal(first.c_str(), "editor_color")) { + EntityClassAttribute &attribute = EntityClass_insertAttribute(entityClass, last).second; + attribute.m_type = "color"; + currentDescription = &attribute.m_description; + currentString = &description; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description)); + } else if (!string_empty(last) && + (string_equal(first.c_str(), "editor_material") || string_equal(first.c_str(), "editor_mat"))) { + EntityClassAttribute &attribute = EntityClass_insertAttribute(entityClass, last).second; + attribute.m_type = "shader"; + currentDescription = &attribute.m_description; + currentString = &description; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description)); + } else if (string_equal(key, "inherit")) { + entityClass.inheritanceResolved = false; + ASSERT_MESSAGE(entityClass.m_parent.empty(), "only one 'inherit' supported per entityDef"); + const char *token; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, token)); + entityClass.m_parent.push_back(token); + } + // begin quake4-specific keys + else if (string_equal(key, "editor_targetonsel")) { + //const char* value = + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser)); + } else if (string_equal(key, "editor_menu")) { + //const char* value = + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser)); + } else if (string_equal(key, "editor_ignore")) { + //const char* value = + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser)); + } + // end quake4-specific keys + // begin ignore prey (unknown/unused?) entity keys + else if (string_equal(key, "editor_light") + || string_equal(key, "editor_def def_debrisspawner") + || string_equal(key, "editor_def def_drop") + || string_equal(key, "editor_def def_guihand") + || string_equal(key, "editor_def def_mine")) { + //const char* value = + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser)); + } + // end ignore prey entity keys + else { + CopiedString tmp(key); + if (string_equal_n(key, "editor_", 7)) { + globalErrorStream() << "unsupported editor key " << makeQuoted(key); + } + EntityClassAttribute &attribute = EntityClass_insertAttribute(entityClass, key).second; + attribute.m_type = "string"; + const char *value; + PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, value)); + if (string_equal(value, "}")) { // hack for quake4 powerups.def bug + globalErrorStream() << "entityDef " << makeQuoted(entityClass.m_name.c_str()) << " key " + << makeQuoted(tmp.c_str()) << " has no value\n"; + break; + } else { + attribute.m_value = value; + } + } + tokeniser.nextLine(); + } + + entityClass.m_comments = usage.c_str(); + + if (string_equal(entityClass.m_name.c_str(), "light")) { + { + EntityClassAttribute &attribute = EntityClass_insertAttribute(entityClass, "light_radius").second; + attribute.m_type = "vector3"; + attribute.m_value = "300 300 300"; + } + { + EntityClassAttribute &attribute = EntityClass_insertAttribute(entityClass, "light_center").second; + attribute.m_type = "vector3"; + } + { + EntityClassAttribute &attribute = EntityClass_insertAttribute(entityClass, "noshadows").second; + attribute.m_type = "boolean"; + attribute.m_value = "0"; + } + { + EntityClassAttribute &attribute = EntityClass_insertAttribute(entityClass, "nospecular").second; + attribute.m_type = "boolean"; + attribute.m_value = "0"; + } + { + EntityClassAttribute &attribute = EntityClass_insertAttribute(entityClass, "nodiffuse").second; + attribute.m_type = "boolean"; + attribute.m_value = "0"; + } + { + EntityClassAttribute &attribute = EntityClass_insertAttribute(entityClass, "falloff").second; + attribute.m_type = "real"; + } + } + + return true; +} + +bool EntityClassDoom3_parseEntityDef(Tokeniser &tokeniser) +{ + EntityClass *entityClass = Eclass_Alloc(); + entityClass->free = &Eclass_Free; + + if (!EntityClass_parse(*entityClass, tokeniser)) { + eclass_capture_state(entityClass); // finish constructing the entity so that it can be destroyed cleanly. + entityClass->free(entityClass); + return false; + } + + EntityClass *inserted = EntityClassDoom3_insertUnique(entityClass); + if (inserted != entityClass) { + globalErrorStream() << "entityDef " << entityClass->name() + << " is already defined, second definition ignored\n"; + eclass_capture_state(entityClass); // finish constructing the entity so that it can be destroyed cleanly. + entityClass->free(entityClass); + } + return true; +} + +bool EntityClassDoom3_parseBlock(Tokeniser &tokeniser, const char *blockType) +{ + if (string_equal(blockType, "entityDef")) { + return EntityClassDoom3_parseEntityDef(tokeniser); + } else if (string_equal(blockType, "model")) { + return EntityClassDoom3_parseModel(tokeniser); + } else { + return EntityClassDoom3_parseUnknown(tokeniser); + } } -void EntityClassDoom3_unrealise(){ - g_EntityClassDoom3.unrealise(); + +bool EntityClassDoom3_parse(TextInputStream &inputStream, const char *filename) +{ + Tokeniser &tokeniser = GlobalScriptLibrary().m_pfnNewScriptTokeniser(inputStream); + + tokeniser.nextLine(); + + for (;;) { + const char *blockType = tokeniser.getToken(); + if (blockType == 0) { + return true; + } + CopiedString tmp(blockType); + if (!EntityClassDoom3_parseBlock(tokeniser, tmp.c_str())) { + globalErrorStream() << GlobalFileSystem().findFile(filename) << filename << ":" + << (unsigned int) tokeniser.getLine() << ": " << tmp.c_str() + << " parse failed, skipping rest of file\n"; + return false; + } + } + + tokeniser.release(); } -void EntityClassDoom3_construct(){ - GlobalFileSystem().attach( g_EntityClassDoom3 ); - // start by creating the default unknown eclass - g_EntityClassDoom3_bad = EClass_Create( "UNKNOWN_CLASS", Vector3( 0.0f, 0.5f, 0.0f ), "" ); +void EntityClassDoom3_loadFile(const char *filename) +{ + globalOutputStream() << "parsing entity classes from " << makeQuoted(filename) << "\n"; - EntityClassDoom3_realise(); + StringOutputStream fullname(256); + fullname << "def/" << filename; + + ArchiveTextFile *file = GlobalFileSystem().openTextFile(fullname.c_str()); + if (file != 0) { + EntityClassDoom3_parse(file->getInputStream(), fullname.c_str()); + file->release(); + } } -void EntityClassDoom3_destroy(){ - EntityClassDoom3_unrealise(); +EntityClass *EntityClassDoom3_findOrInsert(const char *name, bool has_brushes) +{ + ASSERT_NOTNULL(name); + + if (string_empty(name)) { + return g_EntityClassDoom3_bad; + } - g_EntityClassDoom3_bad->free( g_EntityClassDoom3_bad ); + EntityClasses::iterator i = g_EntityClassDoom3_classes.find(name); + if (i != g_EntityClassDoom3_classes.end() + //&& string_equal((*i).first, name) + ) { + return (*i).second; + } - GlobalFileSystem().detach( g_EntityClassDoom3 ); + EntityClass *e = EntityClass_Create_Default(name, has_brushes); + EntityClass *inserted = EntityClassDoom3_insertUnique(e); + ASSERT_MESSAGE(inserted == e, ""); + return inserted; } -class EntityClassDoom3Dependencies : public GlobalFileSystemModuleRef, public GlobalShaderCacheModuleRef +const ListAttributeType *EntityClassDoom3_findListType(const char *name) { -}; + return 0; +} + -class EntityClassDoom3API +void EntityClass_resolveInheritance(EntityClass *derivedClass) { -EntityClassManager m_eclassmanager; + if (derivedClass->inheritanceResolved == false) { + derivedClass->inheritanceResolved = true; + EntityClasses::iterator i = g_EntityClassDoom3_classes.find(derivedClass->m_parent.front().c_str()); + if (i == g_EntityClassDoom3_classes.end()) { + globalErrorStream() << "failed to find entityDef " << makeQuoted(derivedClass->m_parent.front().c_str()) + << " inherited by " << makeQuoted(derivedClass->m_name.c_str()) << "\n"; + } else { + EntityClass *parentClass = (*i).second; + EntityClass_resolveInheritance(parentClass); + if (!derivedClass->colorSpecified) { + derivedClass->colorSpecified = parentClass->colorSpecified; + derivedClass->color = parentClass->color; + } + if (!derivedClass->sizeSpecified) { + derivedClass->sizeSpecified = parentClass->sizeSpecified; + derivedClass->mins = parentClass->mins; + derivedClass->maxs = parentClass->maxs; + derivedClass->fixedsize = parentClass->fixedsize; + } + + for (EntityClassAttributes::iterator j = parentClass->m_attributes.begin(); + j != parentClass->m_attributes.end(); ++j) { + EntityClass_insertAttribute(*derivedClass, (*j).first.c_str(), (*j).second); + } + } + } +} + +class EntityClassDoom3 : public ModuleObserver { + std::size_t m_unrealised; + ModuleObservers m_observers; public: -typedef EntityClassManager Type; -STRING_CONSTANT( Name, "doom3" ); + EntityClassDoom3() : m_unrealised(2) + { + } + + void realise() + { + if (--m_unrealised == 0) { + globalOutputStream() << "searching vfs directory " << makeQuoted("def") << " for *.def\n"; + GlobalFileSystem().forEachFile("def/", "def", makeCallbackF(EntityClassDoom3_loadFile)); + + { + for (Models::iterator i = g_models.begin(); i != g_models.end(); ++i) { + Model_resolveInheritance((*i).first.c_str(), (*i).second); + } + } + { + for (EntityClasses::iterator i = g_EntityClassDoom3_classes.begin(); + i != g_EntityClassDoom3_classes.end(); ++i) { + EntityClass_resolveInheritance((*i).second); + if (!string_empty((*i).second->m_modelpath.c_str())) { + Models::iterator j = g_models.find((*i).second->m_modelpath); + if (j != g_models.end()) { + (*i).second->m_modelpath = (*j).second.m_mesh; + (*i).second->m_skin = (*j).second.m_skin; + } + } + eclass_capture_state((*i).second); + + StringOutputStream usage(256); + + usage << "-------- NOTES --------\n"; + + if (!string_empty((*i).second->m_comments.c_str())) { + usage << (*i).second->m_comments.c_str() << "\n"; + } + + usage << "\n-------- KEYS --------\n"; + + for (EntityClassAttributes::iterator j = (*i).second->m_attributes.begin(); + j != (*i).second->m_attributes.end(); ++j) { + const char *name = EntityClassAttributePair_getName(*j); + const char *description = EntityClassAttributePair_getDescription(*j); + if (!string_equal(name, description)) { + usage << EntityClassAttributePair_getName(*j) << " : " + << EntityClassAttributePair_getDescription(*j) << "\n"; + } + } + + (*i).second->m_comments = usage.c_str(); + } + } + + m_observers.realise(); + } + } + + void unrealise() + { + if (++m_unrealised == 1) { + m_observers.unrealise(); + EntityClassDoom3_clear(); + } + } + + void attach(ModuleObserver &observer) + { + m_observers.attach(observer); + } + + void detach(ModuleObserver &observer) + { + m_observers.detach(observer); + } +}; -EntityClassDoom3API(){ - EntityClassDoom3_construct(); +EntityClassDoom3 g_EntityClassDoom3; - m_eclassmanager.findOrInsert = &EntityClassDoom3_findOrInsert; - m_eclassmanager.findListType = &EntityClassDoom3_findListType; - m_eclassmanager.forEach = &EntityClassDoom3_forEach; - m_eclassmanager.attach = &EntityClassDoom3_attach; - m_eclassmanager.detach = &EntityClassDoom3_detach; - m_eclassmanager.realise = &EntityClassDoom3_realise; - m_eclassmanager.unrealise = &EntityClassDoom3_unrealise; +void EntityClassDoom3_attach(ModuleObserver &observer) +{ + g_EntityClassDoom3.attach(observer); } -~EntityClassDoom3API(){ - EntityClassDoom3_destroy(); + +void EntityClassDoom3_detach(ModuleObserver &observer) +{ + g_EntityClassDoom3.detach(observer); } -EntityClassManager* getTable(){ - return &m_eclassmanager; + +void EntityClassDoom3_realise() +{ + g_EntityClassDoom3.realise(); } + +void EntityClassDoom3_unrealise() +{ + g_EntityClassDoom3.unrealise(); +} + +void EntityClassDoom3_construct() +{ + GlobalFileSystem().attach(g_EntityClassDoom3); + + // start by creating the default unknown eclass + g_EntityClassDoom3_bad = EClass_Create("UNKNOWN_CLASS", Vector3(0.0f, 0.5f, 0.0f), ""); + + EntityClassDoom3_realise(); +} + +void EntityClassDoom3_destroy() +{ + EntityClassDoom3_unrealise(); + + g_EntityClassDoom3_bad->free(g_EntityClassDoom3_bad); + + GlobalFileSystem().detach(g_EntityClassDoom3); +} + +class EntityClassDoom3Dependencies : public GlobalFileSystemModuleRef, public GlobalShaderCacheModuleRef { +}; + +class EntityClassDoom3API { + EntityClassManager m_eclassmanager; +public: + typedef EntityClassManager Type; + + STRING_CONSTANT(Name, "doom3"); + + EntityClassDoom3API() + { + EntityClassDoom3_construct(); + + m_eclassmanager.findOrInsert = &EntityClassDoom3_findOrInsert; + m_eclassmanager.findListType = &EntityClassDoom3_findListType; + m_eclassmanager.forEach = &EntityClassDoom3_forEach; + m_eclassmanager.attach = &EntityClassDoom3_attach; + m_eclassmanager.detach = &EntityClassDoom3_detach; + m_eclassmanager.realise = &EntityClassDoom3_realise; + m_eclassmanager.unrealise = &EntityClassDoom3_unrealise; + } + + ~EntityClassDoom3API() + { + EntityClassDoom3_destroy(); + } + + EntityClassManager *getTable() + { + return &m_eclassmanager; + } }; #include "modulesystem/singletonmodule.h" @@ -816,4 +824,4 @@ EntityClassManager* getTable(){ typedef SingletonModule EntityClassDoom3Module; typedef Static StaticEntityClassDoom3Module; -StaticRegisterModule staticRegisterEntityClassDoom3( StaticEntityClassDoom3Module::instance() ); +StaticRegisterModule staticRegisterEntityClassDoom3(StaticEntityClassDoom3Module::instance());