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