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 "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
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
00548
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 }