itemrepository.cpp

Go to the documentation of this file.
00001 
00002 /***************************************************************************
00003                           itemrepository.cpp   -  description
00004                              -------------------
00005     begin                : Thu Jul 28 2001
00006     copyright            : (C) 2001 by Martin Bickel
00007     email                : bickel@asc-hq.org
00008  ***************************************************************************/
00013 /***************************************************************************
00014  *                                                                         *
00015  *   This program is free software; you can redistribute it and/or modify  *
00016  *   it under the terms of the GNU General Public License as published by  *
00017  *   the Free Software Foundation; either version 2 of the License, or     *
00018  *   (at your option) any later version.                                   *
00019  *                                                                         *
00020  ***************************************************************************/
00021 
00022 #include <map>
00023 #include <vector>
00024 #include "typen.h"
00025 #include "itemrepository.h"
00026 #include "textfileparser.h"
00027 #include "sgstream.h"
00028 #include "textfile_evaluation.h"
00029 #include "util/messaginghub.h"
00030 #include "packagemanager.h"
00031 #include "packagerepository.h"
00032 
00033 
00034 SigC::Signal0<void> dataLoaderTicker;
00035 
00036 
00037 const char* cacheFileName = "asc2.cache";
00038 
00039 typedef vector<TextFileDataLoader*> DataLoaders;
00040 DataLoaders dataLoaders;
00041 DataLoaders dataLoadersToDelete;
00042 
00043 
00044 typedef map<ASCString,TextPropertyList> TextFileRepository;
00045 TextFileRepository textFileRepository;
00046 
00047 
00048 void duplicateIDError ( const ASCString& itemtype, int id, const ASCString& file1, const ASCString& name1, const ASCString&  file2, const ASCString& name2 )
00049 {
00050    fatalError ( "Conflicting IDs !\n"
00051                 "These two " + itemtype + "s use both the ID of " + strrr ( id ) + "\n" +
00052                 " " + name1 + " from file " + file1 + "\n" +
00053                 " " + name2 + " from file " + file2 + "\n\n" +
00054                 "This is NOT a bug of ASC, it is conflict between two data files.");
00055 }
00056 
00057 
00058 template<class T> 
00059 void ItemRepository<T>::RegisterID::operator() (int id )
00060 {
00061    typename ObjectMap::iterator i = repository.hash.find ( id );
00062    if ( i != repository.hash.end() && i->second )
00063       duplicateIDError ( repository.typeName, id, object->location, object->name, i->second->location, i->second->name );
00064    repository.hash[ id ] = object;
00065 }
00066 
00067 
00068 
00069 template<class T>
00070 void ItemRepository<T>::add( T* obj )
00071 {
00072    RegisterID reg(*this, obj);
00073    reg( obj->id );
00074 
00075    for_each ( obj->secondaryIDs.begin(), obj->secondaryIDs.end(), reg );
00076 
00077 
00078    container.push_back( obj );
00079 }
00080 
00081 
00082 template<class T>
00083 void ItemRepositoryLoader<T>::readTextFiles( PropertyReadingContainer& prc, const ASCString& fileName, const ASCString& location )
00084 {
00085    T* t = new T;
00086    t->runTextIO ( prc );
00087 
00088    t->filename = fileName;
00089    t->location = location;
00090    t->archive = prc.getArchive();
00091    add ( t );
00092 }
00093 
00094 
00095 template<class T>
00096 void ItemRepositoryLoader<T>::read( tnstream& stream )
00097 {
00098    int version = stream.readInt();
00099    if ( version != 1 )
00100       throw tinvalidversion( stream.getLocation(), 1, version );
00101    int num = stream.readInt();
00102    for ( int i = 0; i< num; ++i ) {
00103       dataLoaderTicker();
00104 
00105       T* t = new T;
00106       t->read( stream );
00107 
00108       t->filename = stream.readString();
00109       t->location = stream.readString();
00110       t->archive = stream.readString();
00111       dataLoaderTicker();
00112 
00113       add ( t );
00114       // add ( T::newFromStream(stream ));
00115    }
00116 }
00117 
00118 
00119 template<class T>
00120 void ItemRepositoryLoader<T>::write( tnstream& stream )
00121 {
00122    stream.writeInt( 1 );
00123    stream.writeInt( ItemRepository<T>::container.size() );
00124    for ( typename ItemRepository<T>::ItemContainerType::iterator i = ItemRepository<T>::container.begin(); i != ItemRepository<T>::container.end(); ++i ) {
00125        (*i)->write( stream );
00126        stream.writeString ( (*i)->filename );
00127        stream.writeString ( (*i)->location );
00128        stream.writeString ( (*i)->archive ); 
00129    }
00130 }
00131 
00132 
00133 template<class T>
00134 void ItemRepository<T>::addIdTranslation( int from, int to )
00135 {
00136     idTranslation[from] = to;
00137 }
00138 
00139 MineTypeRepository  mineTypeRepository;
00140 
00141 
00142 MineTypeRepository::MineTypeRepository() : ItemRepository<MineType>("Mines")
00143 {
00144    add( new MineType( cmantipersonnelmine ) );
00145    add( new MineType( cmantitankmine ) );
00146    add( new MineType( cmmooredmine ) );
00147    add( new MineType( cmfloatmine ) );
00148 }
00149 
00150 
00151 ItemRepositoryLoader<VehicleType>  vehicleTypeRepository( "vehicletype" );
00152 ItemRepositoryLoader<TerrainType>  terrainTypeRepository( "terraintype" );
00153 ItemRepositoryLoader<ObjectType>   objectTypeRepository ( "objecttype" );
00154 ItemRepositoryLoader<BuildingType> buildingTypeRepository ("buildingtype");
00155 ItemRepositoryLoader<Technology>   technologyRepository ( "technology");
00156 
00157 TechAdapterContainer techAdapterContainer;
00158 
00159 namespace {
00160    class Foo {
00161    public:
00162       Foo() { objectTypeRepository.addIdTranslation( 12998, 1 ); };
00163    } foo;
00164 };
00165 
00166 class TechAdapterLoader : public TextFileDataLoader {
00167       void readTextFiles(PropertyReadingContainer& prc, const ASCString& fileName, const ASCString& location ) {
00168            TechAdapter* ta = new TechAdapter;
00169            ta->runTextIO ( prc );
00170 
00171            ta->filename = fileName;
00172            ta->location = location;
00173            techAdapterContainer.push_back ( ta );
00174       };
00175 
00176       void read ( tnstream& stream ){
00177          readPointerContainer( techAdapterContainer, stream );
00178       };
00179 
00180       void write ( tnstream& stream ){
00181          writePointerContainer( techAdapterContainer, stream );
00182       };
00183       ASCString getTypeName() {
00184          return "techadapter";
00185       };
00186 };
00187 
00188 
00189 void  loadalltextfiles ( );
00190 
00191 const int cacheVersion = 33;
00192 
00193 class FileCache {
00194       vector<tfindfile::FileInfo> actualFileInfo;
00195       tnstream* stream;
00196       bool current;
00197       bool checkForModification ();
00198    public:
00199       FileCache( );
00200       bool isCurrent() { return current; };
00201       void load();
00202       void write();
00203 
00204       ~FileCache();
00205 };
00206 
00207 FileCache::FileCache( )
00208           :stream(NULL)
00209 {
00210    tfindfile::FileInfo fi;
00211    {
00212       tfindfile f ( "*.ascdat", tfindfile::AllDirs, tfindfile::OutsideContainer);
00213       while ( f.getnextname( fi ))
00214          actualFileInfo.push_back ( fi );
00215    }
00216    {
00217       tfindfile f ( "*.asctxt", tfindfile::AllDirs, tfindfile::OutsideContainer);
00218       while ( f.getnextname( fi ))
00219          actualFileInfo.push_back ( fi );
00220    }
00221 
00222    if ( exist ( cacheFileName )) {
00223       stream = new tnfilestream ( cacheFileName, tnstream::reading );
00224       int version = stream->readInt();
00225 
00226       if ( version == cacheVersion )
00227          current = checkForModification();
00228       else
00229          current = false;
00230    } else
00231       current = false;
00232 }
00233 
00234 bool FileCache::checkForModification (  )
00235 {
00236    vector<tfindfile::FileInfo> cacheFileInfo;
00237    readClassContainer ( cacheFileInfo, *stream );
00238 
00239    if ( cacheFileInfo.size() != actualFileInfo.size() )
00240       return false;
00241 
00242    for ( vector<tfindfile::FileInfo>::iterator i = actualFileInfo.begin(); i != actualFileInfo.end(); ++i ) {
00243       bool found = false;
00244       for ( vector<tfindfile::FileInfo>::iterator j = cacheFileInfo.begin(); j != cacheFileInfo.end(); ++j )
00245          if ( i->name == j->name ) {
00246             found = true;
00247             if ( i->size != j->size )
00248                return false;
00249 
00250             if ( i->date != j->date )
00251                return false;
00252 
00253             break;
00254          }
00255 
00256       if ( !found)
00257          return false;
00258    }
00259 
00260 
00261    return true;
00262 }
00263 
00264 
00265 void FileCache::load()
00266 {
00267    for ( DataLoaders::iterator i = dataLoaders.begin(); i != dataLoaders.end(); ++i) {
00268       displayLogMessage ( 5, "loading all of " + (*i)->getTypeName() + " from cache ... ");
00269       (*i)->read ( *stream );
00270       (*i)->postChecks();
00271       displayLogMessage ( 5, "completed \n ");
00272    }
00273 }
00274 
00275 
00276 void FileCache::write()
00277 {
00278    if ( stream )
00279       delete stream;
00280 
00281    stream = new tn_file_buf_stream ( cacheFileName, tnstream::writing );
00282 
00283    stream->writeInt ( cacheVersion );
00284    writeClassContainer ( actualFileInfo, *stream );
00285 
00286    for ( DataLoaders::iterator i = dataLoaders.begin(); i != dataLoaders.end(); ++i)
00287       (*i)->write ( *stream );
00288 
00289 }
00290 
00291 
00292 
00293 FileCache::~FileCache()
00294 {
00295    if ( stream ) {
00296       delete stream;
00297       stream = NULL;
00298    }
00299    for ( DataLoaders::iterator i = dataLoadersToDelete.begin(); i != dataLoadersToDelete.end(); ++i)
00300       delete *i;
00301 }
00302 
00303 
00304 
00305 void registerDataLoader( TextFileDataLoader* dataLoader )
00306 {
00307    dataLoaders.push_back ( dataLoader );
00308    dataLoadersToDelete.push_back ( dataLoader );
00309 }
00310 
00311 void registerDataLoader( TextFileDataLoader& dataLoader )
00312 {
00313    dataLoaders.push_back ( &dataLoader );
00314 }
00315 
00316 
00317 void  loadAllData( bool useCache )
00318 {
00319    FileCache cache;
00320 
00321    registerDataLoader( packageRepository );
00322    registerDataLoader( vehicleTypeRepository );
00323    registerDataLoader( terrainTypeRepository );
00324    registerDataLoader( objectTypeRepository );
00325    registerDataLoader( buildingTypeRepository );
00326    registerDataLoader( technologyRepository );
00327    registerDataLoader( new TechAdapterLoader() );
00328    registerDataLoader( new ItemFiltrationSystem::DataLoader() );
00329 
00330 
00331    if ( cache.isCurrent() && useCache ) {
00332       try {
00333          cache.load();
00334       }
00335       catch ( tinvalidversion err ) {
00336          fatalError("the cache seems to have been generated with a newer version of ASC than this one.\nPlease upgrade to that version, or delete " + ASCString(cacheFileName) + " and try again");
00337       }
00338       displayLogMessage ( 4, "loading of cache completed\n");
00339    } else {
00340       MessagingHub::Instance().statusInformation("rebuilding data cache, please be patient");
00341       
00342       loadalltextfiles();
00343 
00344       for ( DataLoaders::iterator dl = dataLoaders.begin(); dl != dataLoaders.end(); ++dl) {
00345          TextPropertyList& tpl = textFileRepository[ (*dl)->getTypeName() ];
00346          for ( TextPropertyList::iterator i = tpl.begin(); i != tpl.end(); i++ ) {
00347             dataLoaderTicker();
00348 
00349             if ( !(*i)->isAbstract() ) {
00350                PropertyReadingContainer pc ( (*dl)->getTypeName(), *i );
00351 
00352                displayLogMessage ( 5, "loading " + (*i)->location );
00353                (*dl)->readTextFiles( pc, (*i)->fileName, (*i)->location );
00354                displayLogMessage ( 5, " done\n");
00355             }
00356          }
00357          (*dl)->postChecks();
00358          displayLogMessage ( 4, "loading all of " + (*dl)->getTypeName() + "  completed\n");
00359 
00360       }
00361 
00362       if ( useCache ) {
00363          try {
00364             cache.write();
00365          }
00366          catch ( tfileerror err ) {
00367             fatalError("error writing cache file");
00368          }
00369       }
00370 
00371       textFileRepository.clear();
00372    }
00373 }
00374 
00375 
00376 
00377 
00378 
00379 void  loadalltextfiles ( )
00380 {
00381    tfindfile ff ( "*.asctxt" );
00382    ASCString c = ff.getnextname();
00383 
00384    while( !c.empty() ) {
00385       dataLoaderTicker();
00386 
00387       tnfilestream s ( c, tnstream::reading );
00388 
00389       displayLogMessage ( 6, "loadalltextfiles :: loading " + s.getLocation() + ", " );
00390 
00391       TextFormatParser tfp ( &s );
00392 
00393       displayLogMessage ( 5, "TFP running... " );
00394 
00395       TextPropertyGroup* tpg = tfp.run();
00396 
00397       textFileRepository[tpg->typeName].push_back ( tpg );
00398 
00399       displayLogMessage ( 5, "done\n" );
00400 
00401       c = ff.getnextname();
00402    }
00403    displayLogMessage ( 4, "loadalltextfiles completed\n");
00404 
00405    displayLogMessage ( 4, "Building inheritance...");
00406 
00407    displayLogMessage ( 10, " Printing all .ASCTXT files after inheritance and aliases have been resolved\n");
00408    for ( TextFileRepository::iterator i = textFileRepository.begin(); i != textFileRepository.end(); i++ ) {
00409       i->second.buildIDs();
00410       for ( TextPropertyList::iterator j = i->second.begin(); j != i->second.end(); j++ ) {
00411           displayLogMessage( 9, "Building inheritance: " + (*j)->location + "\n");
00412           (*j)->buildInheritance( i->second );
00413           if ( MessagingHub::Instance().getVerbosity() >= 10 )
00414              (*j)->print();
00415       }
00416    }
00417    displayLogMessage ( 4, "done\n");
00418 }
00419 
00420 
00421 
00422 
00423 
00424 
00425 
00426 deallocating_vector<ItemFiltrationSystem::ItemFilter*> ItemFiltrationSystem::itemFilters;
00427 
00428 
00429 ItemFiltrationSystem::ItemFilter::ItemFilter( const ASCString& _name, const IntRangeArray& unitsetIDs, bool _active )
00430 {
00431    name = "UnitSet: " + _name;
00432    units = unitsetIDs;
00433    active = _active;
00434 }
00435 
00436 
00437 void ItemFiltrationSystem::ItemFilter::runTextIO ( PropertyContainer& pc )
00438 {
00439     if ( pc.find ( "Buildings"))
00440       pc.addIntRangeArray ( "Buildings", buildings );
00441     if ( pc.find ( "Vehicles"))
00442       pc.addIntRangeArray ( "Vehicles", units );
00443     if ( pc.find ( "Objects"))
00444        pc.addIntRangeArray ( "Objects", objects );
00445     if ( pc.find ( "Terrain"))
00446       pc.addIntRangeArray ( "Terrain", terrain );
00447     if ( pc.find ( "Technologies"))
00448       pc.addIntRangeArray ( "Technologies", technologies );
00449     pc.addBool ( "activated", active, false );
00450     pc.addString ( "name", name );
00451 }
00452 
00453 void ItemFiltrationSystem::ItemFilter::read ( tnstream& stream )
00454 {
00455    int version = stream.readInt();
00456    if ( version > 2 )
00457       throw tinvalidversion( stream.getDeviceName(), 2, version );
00458    readClassContainer ( buildings, stream );
00459    readClassContainer ( objects, stream );
00460    readClassContainer ( units, stream );
00461    readClassContainer ( terrain, stream );
00462    if ( version >= 2 )
00463       readClassContainer ( technologies, stream );
00464 
00465    active = stream.readInt();
00466    name = stream.readString();
00467 }
00468 
00469 void ItemFiltrationSystem::ItemFilter::write ( tnstream& stream )
00470 {
00471    stream.writeInt ( 2 );
00472    writeClassContainer ( buildings, stream );
00473    writeClassContainer ( objects, stream );
00474    writeClassContainer ( units, stream );
00475    writeClassContainer ( terrain, stream );
00476    writeClassContainer ( technologies, stream );
00477    stream.writeInt ( active );
00478    stream.writeString ( name );
00479 }
00480 
00481 
00482 
00483 bool ItemFiltrationSystem::ItemFilter::isContained ( IntRangeArray& arr, int id )
00484 {
00485    for ( IntRangeArray::iterator i = arr.begin(); i != arr.end(); i++ )
00486       if ( id >= i->from && id <= i->to )
00487          return true;
00488    return false;
00489 }
00490 
00491 
00492 
00493 bool ItemFiltrationSystem::ItemFilter::isContained ( ItemFiltrationSystem::Category cat, int id )
00494 {
00495    switch ( cat ) {
00496       case Building: return isContained ( buildings, id );
00497       case Vehicle: return isContained ( units, id );
00498       case Object: return isContained ( objects, id );
00499       case Terrain: return isContained ( terrain, id );
00500       case Technology: return isContained ( technologies, id );
00501    };
00502    return false;
00503 }
00504 
00505 bool ItemFiltrationSystem::isFiltered ( ItemFiltrationSystem::Category cat, int id )
00506 {
00507    for ( vector<ItemFilter*>::iterator i = itemFilters.begin(); i != itemFilters.end(); i++ )
00508       if ( (*i)->isContained ( cat, id ) )
00509          if ( (*i)->isActive() )
00510             return true;
00511 
00512    return false;
00513 }
00514 
00515 
00516 bool ItemFiltrationSystem::isFiltered( const VehicleType* item )
00517 {
00518    return isFiltered( Vehicle, item->id );
00519 }
00520 
00521 bool ItemFiltrationSystem::isFiltered( const BuildingType* item )
00522 {
00523    return isFiltered( Building, item->id );
00524 }
00525 
00526 bool ItemFiltrationSystem::isFiltered( const ObjectType* item )
00527 {
00528    return isFiltered( Object, item->id );
00529 }
00530 
00531 bool ItemFiltrationSystem::isFiltered( const TerrainType* item )
00532 {
00533    return isFiltered( Terrain, item->id );
00534 }
00535 
00536 bool ItemFiltrationSystem::isFiltered( const MineType* item )
00537 {
00538    return false;
00539 }
00540 
00541 
00542 void ItemFiltrationSystem::DataLoader::readTextFiles( PropertyReadingContainer& prc, const ASCString& fileName, const ASCString& location )
00543 {
00544    ItemFilter* itf = new ItemFilter;
00545    itf->runTextIO ( prc );
00546 
00547    // bmtt->filename = (*i)->fileName;
00548    // bmtt->location = (*i)->location;
00549    ItemFiltrationSystem::itemFilters.push_back ( itf );
00550 }
00551 
00552 void ItemFiltrationSystem::DataLoader::read ( tnstream& stream )
00553 {
00554    stream.readInt();
00555    readPointerContainer( ItemFiltrationSystem::itemFilters, stream );
00556 }
00557 
00558 void ItemFiltrationSystem::DataLoader::write ( tnstream& stream )
00559 {
00560    stream.writeInt ( 1 );
00561    writePointerContainer( ItemFiltrationSystem::itemFilters, stream );
00562 }

Generated on Mon May 21 01:26:34 2012 for Advanced Strategic Command by  doxygen 1.5.1