load_form.h

Go to the documentation of this file.
00001 
00005 /* Copyright, 2001 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NEL.
00008  * NEVRAX NEL is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NEL is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
00022  */
00023 
00024 #ifndef NL_LOAD_FORM_H
00025 #define NL_LOAD_FORM_H
00026 
00027 #include "nel/misc/types_nl.h"
00028 
00029 #include <map>
00030 #include <string>
00031 #include <vector>
00032 
00033 #include "nel/misc/path.h"
00034 #include "nel/misc/file.h"
00035 #include "nel/misc/sheet_id.h"
00036 #include "nel/misc/algo.h"
00037 
00038 #include "u_form_loader.h"
00039 #include "u_form.h"
00040 
00105 
00106 /*
00107 struct TLoadFormDicoEntry
00108 {
00109     std::string     Filename;
00110     uint32          ModificationDate;
00111 
00112     void serial(NLMISC::IStream &s)
00113     {
00114         s.serial(Filename);
00115         s.serial(ModificationDate);
00116     }
00117 };
00118 */
00119 const uint32        PACKED_SHEET_HEADER = 'PKSH';
00120 const uint32        PACKED_SHEET_VERSION = 5;
00121 // This Version may be used if you want to use the serialVersion() system in loadForm()
00122 const uint32        PACKED_SHEET_VERSION_COMPATIBLE = 0;
00123 
00124 // ***************************************************************************
00130 template <class T>
00131 void loadForm (const std::vector<std::string> &sheetFilters, const std::string &packedFilename, std::map<NLMISC::CSheetId, T> &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)
00132 {
00133     std::vector<std::string>                        dictionnary;
00134     std::map<std::string, uint>                     dictionnaryIndex;
00135     std::map<NLMISC::CSheetId, std::vector<uint32> >    dependencies;
00136     std::vector<uint32>                             dependencyDates;
00137 
00138     // check the extension (i know that file like "foo.packed_sheetsbar" will be accepted but this check is enough...)
00139     nlassert (packedFilename.find (".packed_sheets") != std::string::npos);
00140 
00141     std::string packedFilenamePath = NLMISC::CPath::lookup(NLMISC::CFile::getFilename(packedFilename), false, false);
00142     if (packedFilenamePath.empty())
00143     {
00144         packedFilenamePath = packedFilename;
00145     }
00146 
00147     // make sure the CSheetId singleton has been properly initialised
00148     NLMISC::CSheetId::init(updatePackedSheet);
00149 
00150     // load the packed sheet if exists
00151     try
00152     {
00153         NLMISC::CIFile ifile;
00154         ifile.setCacheFileOnOpen(true);
00155         if (!ifile.open (packedFilenamePath))
00156         {
00157             throw   NLMISC::Exception("can't open PackedSheet %s", packedFilenamePath.c_str());
00158         }
00159         // an exception will be launch if the file is not the good version or if the file is not found
00160 
00161         nlinfo ("loadForm(): Loading packed file '%s'", packedFilename.c_str());
00162 
00163         // read the header
00164         ifile.serialCheck(PACKED_SHEET_HEADER);
00165         ifile.serialCheck(PACKED_SHEET_VERSION);
00166         ifile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);
00167 
00168         // Read depend block size
00169         uint32  dependBlockSize;
00170         ifile.serial(dependBlockSize);
00171 
00172         // Read the dependencies only if update packed sheet
00173         if(updatePackedSheet)
00174         {
00175             // read the dictionnary
00176             {
00177                 ifile.serialCont(dictionnary);
00178             }
00179             // read the dependency data
00180             {
00181                 uint32 depSize;
00182                 ifile.serial(depSize);
00183                 for (uint i=0; i<depSize; ++i)
00184                 {
00185                     NLMISC::CSheetId sheetId;
00186 
00187                     // Avoid copy, use []
00188                     ifile.serial(sheetId);
00189                     ifile.serialCont(dependencies[sheetId]);
00190                 }
00191             }
00192         }
00193         // else dummy read one big block => no heavy reallocation / free
00194         else if(dependBlockSize>0)
00195         {
00196             std::vector<uint8>  bigBlock;
00197             bigBlock.resize(dependBlockSize);
00198             ifile.serialBuffer(&bigBlock[0], dependBlockSize);
00199         }
00200 
00201         // read the packed sheet data
00202         uint32  nbEntries;
00203         uint32  ver;
00204         ifile.serial (nbEntries);
00205         ifile.serial (ver);
00206         if(ver != T::getVersion ())
00207             throw NLMISC::Exception("The packed sheet version in stream is different of the code");
00208         ifile.serialCont (container);
00209         ifile.close ();
00210     }
00211     catch (NLMISC::Exception &e)
00212     {
00213         // clear the container because it can contains partially loaded sheet so we must clean it before continue
00214         container.clear ();
00215         if (!updatePackedSheet)
00216         {
00217             if (errorIfPackedSheetNotGood)
00218                 nlerror ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what());
00219             else
00220                 nlinfo ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what());
00221 
00222             return;
00223         }
00224         else
00225         {
00226             nlinfo ("loadForm(): Exception during reading the packed file, I'll reconstruct it (%s)", e.what());
00227         }
00228     }
00229 
00230     // if we don't want to update packed sheet, we have nothing more to do
00231     if (!updatePackedSheet)
00232     {
00233         nlinfo ("Don't update the packed sheet with real sheet");
00234         return;
00235     }
00236 
00237     // retreive the date of all dependency file
00238     {
00239         for (uint i=0; i<dictionnary.size(); ++i)
00240         {
00241             std::string p = NLMISC::CPath::lookup (dictionnary[i], false, false);
00242             if (!p.empty())
00243             {
00244                 uint32 d = NLMISC::CFile::getFileModificationDate(p);
00245                 dependencyDates.push_back(d);
00246             }
00247             else
00248             {
00249                 // file not found !
00250                 // write a future date to invalidate any file dependent on it
00251                 nldebug("Can't find dependent file %s !", dictionnary[i].c_str());
00252                 dependencyDates.push_back(0xffffffff);
00253             }
00254         }
00255     }
00256 
00257     // build a vector of the sheetFilters sheet ids (ie: "item")
00258     std::vector<NLMISC::CSheetId> sheetIds;
00259     std::vector<std::string> filenames;
00260     for (uint i = 0; i < sheetFilters.size(); i++)
00261         NLMISC::CSheetId::buildIdVector(sheetIds, filenames, sheetFilters[i]);
00262 
00263     // if there's no file, nothing to do
00264     if (sheetIds.empty())
00265         return;
00266 
00267     // set up the current sheet in container to remove sheet that are in the container and not in the directory anymore
00268     std::map<NLMISC::CSheetId, bool> sheetToRemove;
00269     for (typename std::map<NLMISC::CSheetId, T>::iterator it = container.begin(); it != container.end(); it++)
00270     {
00271         sheetToRemove.insert (std::make_pair((*it).first, true));
00272     }
00273 
00274     // check if we need to create a new .pitems or just read it
00275     uint32 packedFiledate = NLMISC::CFile::getFileModificationDate(packedFilenamePath);
00276 
00277     bool containerChanged = false;
00278 
00279     NLGEORGES::UFormLoader *formLoader = NULL;
00280 
00281     std::vector<uint> NeededToRecompute;
00282 
00283     for (uint k = 0; k < filenames.size(); k++)
00284     {
00285         std::string p = NLMISC::CPath::lookup (filenames[k], false, false);
00286         if (p.empty()) continue;
00287         uint32 d = NLMISC::CFile::getFileModificationDate(p);
00288 
00289         // no need to remove this sheet
00290         sheetToRemove[sheetIds[k]] = false;
00291 
00292         if( d > packedFiledate || container.find (sheetIds[k]) == container.end())
00293         {
00294             NeededToRecompute.push_back(k);
00295         }
00296         else
00297         {
00298             // check the date of each parent
00299             nlassert(dependencies.find(sheetIds[k]) != dependencies.end());
00300             std::vector<uint32> &depends = dependencies[sheetIds[k]];
00301 
00302             for (uint i=0; i<depends.size(); ++i)
00303             {
00304                 if (dependencyDates[depends[i]] > packedFiledate)
00305                 {
00306                     nldebug("Dependency on %s for %s not up to date !",
00307                         dictionnary[depends[i]].c_str(), sheetIds[k].toString().c_str());
00308                     NeededToRecompute.push_back(k);
00309                     break;
00310                 }
00311             }
00312         }
00313     }
00314 
00315     nlinfo ("%d sheets checked, %d need to be recomputed", filenames.size(), NeededToRecompute.size());
00316 
00317     NLMISC::TTime last = NLMISC::CTime::getLocalTime ();
00318     NLMISC::TTime start = NLMISC::CTime::getLocalTime ();
00319 
00320     NLMISC::CSmartPtr<NLGEORGES::UForm> form;
00321     std::vector<NLMISC::CSmartPtr<NLGEORGES::UForm> >   cacheFormList;
00322 
00323     for (uint j = 0; j < NeededToRecompute.size(); j++)
00324     {
00325         if(NLMISC::CTime::getLocalTime () > last + 5000)
00326         {
00327             last = NLMISC::CTime::getLocalTime ();
00328             if(j>0)
00329                 nlinfo ("%.0f%% completed (%d/%d), %d seconds remaining", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(last-start)/j/1000);
00330         }
00331 
00332         // create the georges loader if necessary
00333         if (formLoader == NULL)
00334         {
00335             NLMISC::WarningLog->addNegativeFilter("CFormLoader: Can't open the form file");
00336             formLoader = NLGEORGES::UFormLoader::createLoader ();
00337         }
00338 
00339         //  cache used to retain information (to optimize time).
00340         if (form)
00341             cacheFormList.push_back (form);
00342 
00343         // Load the form with given sheet id
00344         form = formLoader->loadForm (sheetIds[NeededToRecompute[j]].toString().c_str ());
00345         if (form)
00346         {
00347             // build the dependency data
00348             {
00349                 std::vector<uint32>     depends;
00350                 std::set<std::string>   dependFiles;
00351                 form->getDependencies (dependFiles);
00352                 nlassert(dependFiles.find(sheetIds[NeededToRecompute[j]].toString()) != dependFiles.end());
00353                 // remove the sheet itself from the container
00354                 dependFiles.erase(sheetIds[NeededToRecompute[j]].toString());
00355 
00356                 std::set<std::string>::iterator first(dependFiles.begin()), last(dependFiles.end());
00357                 for (; first != last; ++first)
00358                 {
00359                     const   std::string filename = NLMISC::CFile::getFilename(*first);
00360                     std::map<std::string,uint>::iterator    findDicIt=dictionnaryIndex.find(filename);
00361 
00362                     if  (findDicIt!=dictionnaryIndex.end())
00363                     {
00364                         depends.push_back(findDicIt->second);
00365                         continue;
00366                     }
00367 
00368                     std::string p = NLMISC::CPath::lookup (*first, false, false);
00369                     if  (!p.empty())
00370                     {
00371                         uint dicIndex;
00372                         // add a new dictionnary entry
00373                         dicIndex = dictionnary.size();
00374                         dictionnaryIndex.insert(std::make_pair(filename, dictionnary.size()));
00375                         dictionnary.push_back(filename);
00376 
00377                         // add the dependecy index
00378                         depends.push_back(dicIndex);
00379                     }
00380                 }
00381                 // store the dependency list with the sheet ID
00382                 dependencies[sheetIds[NeededToRecompute[j]]] = depends;
00383             }
00384 
00385             // add the new creature, it could be already loaded by the packed sheets but will be overwritten with the new one
00386             typedef typename std::map<NLMISC::CSheetId, T>::iterator TType1;
00387             typedef typename std::pair<TType1, bool> TType2;
00388             TType2 res = container.insert(std::make_pair(sheetIds[NeededToRecompute[j]],T()));
00389 
00390             (*res.first).second.readGeorges (form, sheetIds[NeededToRecompute[j]]);
00391             containerChanged = true;
00392         }
00393     }
00394 
00395     if(NeededToRecompute.size() > 0)
00396         nlinfo ("%d seconds to recompute %d sheets", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size());
00397 
00398     // free the georges loader if necessary
00399     if (formLoader != NULL)
00400     {
00401         NLGEORGES::UFormLoader::releaseLoader (formLoader);
00402         NLMISC::WarningLog->removeFilter ("CFormLoader: Can't open the form file");
00403     }
00404 
00405     // we have now to remove sheets that are in the container and not exist anymore in the sheet directories
00406     for (std::map<NLMISC::CSheetId, bool>::iterator it2 = sheetToRemove.begin(); it2 != sheetToRemove.end(); it2++)
00407     {
00408         if((*it2).second)
00409         {
00410             nlinfo ("the sheet '%s' is not in the directory, remove it from container", (*it2).first.toString().c_str());
00411             container.find((*it2).first)->second.removed();
00412             container.erase((*it2).first);
00413             containerChanged = true;
00414             dependencies.erase((*it2).first);
00415         }
00416     }
00417 
00418     // now, save the new container in the packedfile
00419     try
00420     {
00421         if(containerChanged)
00422         {
00423             NLMISC::COFile ofile;
00424             ofile.open(packedFilenamePath);
00425 
00426             // write the header.
00427             ofile.serialCheck(PACKED_SHEET_HEADER);
00428             ofile.serialCheck(PACKED_SHEET_VERSION);
00429             ofile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);
00430 
00431             // Write a dummy block size for now
00432             sint32  posBlockSize= ofile.getPos();
00433             uint32  dependBlockSize= 0;
00434             ofile.serial(dependBlockSize);
00435 
00436             // write the dictionnary
00437             ofile.serialCont(dictionnary);
00438 
00439             // write the dependencies data
00440             uint32 depSize = dependencies.size();
00441             ofile.serial(depSize);
00442             std::map<NLMISC::CSheetId, std::vector<uint32> >::iterator first(dependencies.begin()), last(dependencies.end());
00443             for (; first != last; ++first)
00444             {
00445                 NLMISC::CSheetId si = first->first;
00446                 ofile.serial(si);
00447                 ofile.serialCont(first->second);
00448             }
00449 
00450             // Then get the dictionary + dependencies size, and write it back to posBlockSize
00451             sint32  endBlockSize= ofile.getPos();
00452             dependBlockSize= (endBlockSize - posBlockSize) - 4;
00453             ofile.seek(posBlockSize, NLMISC::IStream::begin);
00454             ofile.serial(dependBlockSize);
00455             ofile.seek(endBlockSize, NLMISC::IStream::begin);
00456 
00457             // write the sheet data
00458             uint32 nbEntries = sheetIds.size();
00459             uint32 ver = T::getVersion ();
00460             ofile.serial (nbEntries);
00461             ofile.serial (ver);
00462             ofile.serialCont(container);
00463             ofile.close ();
00464         }
00465     }
00466     catch (NLMISC::Exception &e)
00467     {
00468         nlinfo ("loadForm(): Exception during saving the packed file, it will be recreated next launch (%s)", e.what());
00469     }
00470 
00471     // housekeeping
00472     sheetIds.clear ();
00473     filenames.clear ();
00474 }
00475 
00476 // ***************************************************************************
00482 template <class T>
00483 void loadForm (const std::string &sheetFilter, const std::string &packedFilename, std::map<NLMISC::CSheetId, T> &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)
00484 {
00485     std::vector<std::string> vs;
00486     vs.push_back(sheetFilter);
00487     loadForm(vs, packedFilename, container, updatePackedSheet, errorIfPackedSheetNotGood);
00488 }
00489 
00490 
00491 // ***************************************************************************
00492 // variant with smart pointers, maintain with function above
00493 template <class T>
00494 void loadForm2(const std::vector<std::string> &sheetFilters, const std::string &packedFilename, std::map<NLMISC::CSheetId, NLMISC::CSmartPtr<T> > &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)
00495 {
00496     std::vector<std::string>                        dictionnary;
00497     std::map<std::string, uint>                     dictionnaryIndex;
00498     std::map<NLMISC::CSheetId, std::vector<uint32> >    dependencies;
00499     std::vector<uint32>                             dependencyDates;
00500 
00501     // check the extension (i know that file like "foo.packed_sheetsbar" will be accepted but this check is enough...)
00502     nlassert (packedFilename.find (".packed_sheets") != std::string::npos);
00503 
00504     std::string packedFilenamePath = NLMISC::CPath::lookup(NLMISC::CFile::getFilename(packedFilename), false, false);
00505     if (packedFilenamePath.empty())
00506     {
00507         packedFilenamePath = packedFilename;
00508     }
00509 
00510     // make sure the CSheetId singleton has been properly initialised
00511     NLMISC::CSheetId::init(updatePackedSheet);
00512 
00513     // load the packed sheet if exists
00514     try
00515     {
00516         NLMISC::CIFile ifile;
00517         ifile.setCacheFileOnOpen(true);
00518         if (!ifile.open (packedFilenamePath))
00519         {
00520             throw   NLMISC::Exception("can't open PackedSheet %s", packedFilenamePath.c_str());
00521         }
00522         // an exception will be launch if the file is not the good version or if the file is not found
00523 
00524         nlinfo ("loadForm(): Loading packed file '%s'", packedFilename.c_str());
00525 
00526         // read the header
00527         ifile.serialCheck(PACKED_SHEET_HEADER);
00528         ifile.serialCheck(PACKED_SHEET_VERSION);
00529         sint    loadFormVersion= ifile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);
00530 
00531         // Read depend block size
00532         uint32  dependBlockSize;
00533         ifile.serial(dependBlockSize);
00534 
00535         // Read the dependencies only if update packed sheet
00536         if(updatePackedSheet)
00537         {
00538             // read the dictionnary
00539             {
00540                 ifile.serialCont(dictionnary);
00541             }
00542             // read the dependency data
00543             {
00544                 uint32 depSize;
00545                 ifile.serial(depSize);
00546                 for (uint i=0; i<depSize; ++i)
00547                 {
00548                     NLMISC::CSheetId sheetId;
00549 
00550                     // Avoid copy, use []
00551                     ifile.serial(sheetId);
00552                     ifile.serialCont(dependencies[sheetId]);
00553                 }
00554             }
00555         }
00556         // else dummy read one big block => no heavy reallocation / free
00557         else if(dependBlockSize>0)
00558         {
00559             std::vector<uint8>  bigBlock;
00560             bigBlock.resize(dependBlockSize);
00561             ifile.serialBuffer(&bigBlock[0], dependBlockSize);
00562         }
00563 
00564         // read the packed sheet data
00565         uint32  nbEntries;
00566         uint32  ver;
00567         ifile.serial (nbEntries);
00568         ifile.serial (ver);
00569         if(ver != T::getVersion ())
00570             throw NLMISC::Exception("The packed sheet version in stream is different of the code");
00571         ifile.serialPtrCont (container);
00572         ifile.close ();
00573     }
00574     catch (NLMISC::Exception &e)
00575     {
00576         // clear the container because it can contains partially loaded sheet so we must clean it before continue
00577         container.clear ();
00578         if (!updatePackedSheet)
00579         {
00580             if (errorIfPackedSheetNotGood)
00581                 nlerror ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what());
00582             else
00583                 nlinfo ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what());
00584 
00585             return;
00586         }
00587         else
00588         {
00589             nlinfo ("loadForm(): Exception during reading the packed file, I'll reconstruct it (%s)", e.what());
00590         }
00591     }
00592 
00593     // if we don't want to update packed sheet, we have nothing more to do
00594     if (!updatePackedSheet)
00595     {
00596         nlinfo ("Don't update the packed sheet with real sheet");
00597         return;
00598     }
00599 
00600     // retreive the date of all dependency file
00601     {
00602         for (uint i=0; i<dictionnary.size(); ++i)
00603         {
00604             std::string p = NLMISC::CPath::lookup (dictionnary[i], false, false);
00605             if (!p.empty())
00606             {
00607                 uint32 d = NLMISC::CFile::getFileModificationDate(p);
00608                 dependencyDates.push_back(d);
00609             }
00610             else
00611             {
00612                 // file not found !
00613                 // write a future date to invalidate any file dependent on it
00614                 nldebug("Can't find dependent file %s !", dictionnary[i].c_str());
00615                 dependencyDates.push_back(0xffffffff);
00616             }
00617         }
00618     }
00619 
00620     // build a vector of the sheetFilters sheet ids (ie: "item")
00621     std::vector<NLMISC::CSheetId> sheetIds;
00622     std::vector<std::string> filenames;
00623     for (uint i = 0; i < sheetFilters.size(); i++)
00624         NLMISC::CSheetId::buildIdVector(sheetIds, filenames, sheetFilters[i]);
00625 
00626     // if there's no file, nothing to do
00627     if (sheetIds.empty())
00628         return;
00629 
00630     // set up the current sheet in container to remove sheets that are in the container and not in the directory anymore
00631     std::map<NLMISC::CSheetId, bool> sheetToRemove;
00632     for (typename std::map<NLMISC::CSheetId, NLMISC::CSmartPtr<T> >::iterator it = container.begin(); it != container.end(); it++)
00633     {
00634         sheetToRemove.insert (std::make_pair((*it).first, true));
00635     }
00636 
00637     // check if we need to create a new .pitems or just read it
00638     uint32 packedFiledate = NLMISC::CFile::getFileModificationDate(packedFilenamePath);
00639 
00640     bool containerChanged = false;
00641 
00642     NLGEORGES::UFormLoader *formLoader = NULL;
00643 
00644     std::vector<uint> NeededToRecompute;
00645 
00646     for (uint k = 0; k < filenames.size(); k++)
00647     {
00648         std::string p = NLMISC::CPath::lookup (filenames[k], false, false);
00649         if (p.empty()) continue;
00650         uint32 d = NLMISC::CFile::getFileModificationDate(p);
00651 
00652         // no need to remove this sheet
00653         sheetToRemove[sheetIds[k]] = false;
00654 
00655         if( d > packedFiledate || container.find (sheetIds[k]) == container.end())
00656         {
00657             NeededToRecompute.push_back(k);
00658         }
00659         else
00660         {
00661             // check the date of each parent
00662             nlassert(dependencies.find(sheetIds[k]) != dependencies.end());
00663             std::vector<uint32> &depends = dependencies[sheetIds[k]];
00664 
00665             for (uint i=0; i<depends.size(); ++i)
00666             {
00667                 if (dependencyDates[depends[i]] > packedFiledate)
00668                 {
00669                     nldebug("Dependency on %s for %s not up to date !",
00670                         dictionnary[depends[i]].c_str(), sheetIds[k].toString().c_str());
00671                     NeededToRecompute.push_back(k);
00672                     break;
00673                 }
00674             }
00675         }
00676     }
00677 
00678     nlinfo ("%d sheets checked, %d need to be recomputed", filenames.size(), NeededToRecompute.size());
00679 
00680     NLMISC::TTime last = NLMISC::CTime::getLocalTime ();
00681     NLMISC::TTime start = NLMISC::CTime::getLocalTime ();
00682 
00683     NLMISC::CSmartPtr<NLGEORGES::UForm> form;
00684     std::vector<NLMISC::CSmartPtr<NLGEORGES::UForm> >   cacheFormList;
00685 
00686     for (uint j = 0; j < NeededToRecompute.size(); j++)
00687     {
00688         if(NLMISC::CTime::getLocalTime () > last + 5000)
00689         {
00690             last = NLMISC::CTime::getLocalTime ();
00691             if(j>0)
00692                 nlinfo ("%.0f%% completed (%d/%d), %d seconds remaining", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(last-start)/j/1000);
00693         }
00694 
00695         // create the georges loader if necessary
00696         if (formLoader == NULL)
00697         {
00698             NLMISC::WarningLog->addNegativeFilter("CFormLoader: Can't open the form file");
00699             formLoader = NLGEORGES::UFormLoader::createLoader ();
00700         }
00701 
00702         //  cache used to retain information (to optimize time).
00703         if (form)
00704             cacheFormList.push_back (form);
00705 
00706         // Load the form with given sheet id
00707         form = formLoader->loadForm (sheetIds[NeededToRecompute[j]].toString().c_str ());
00708         if (form)
00709         {
00710             // build the dependency data
00711             {
00712                 std::vector<uint32>     depends;
00713                 std::set<std::string>   dependFiles;
00714                 form->getDependencies (dependFiles);
00715                 nlassert(dependFiles.find(sheetIds[NeededToRecompute[j]].toString()) != dependFiles.end());
00716                 // remove the sheet itself from the container
00717                 dependFiles.erase(sheetIds[NeededToRecompute[j]].toString());
00718 
00719                 std::set<std::string>::iterator first(dependFiles.begin()), last(dependFiles.end());
00720                 for (; first != last; ++first)
00721                 {
00722                     const   std::string filename = NLMISC::CFile::getFilename(*first);
00723                     std::map<std::string,uint>::iterator    findDicIt=dictionnaryIndex.find(filename);
00724 
00725                     if  (findDicIt!=dictionnaryIndex.end())
00726                     {
00727                         depends.push_back(findDicIt->second);
00728                         continue;
00729                     }
00730 
00731                     std::string p = NLMISC::CPath::lookup (*first, false, false);
00732                     if  (!p.empty())
00733                     {
00734                         uint dicIndex;
00735                         // add a new dictionnary entry
00736                         dicIndex = dictionnary.size();
00737                         dictionnaryIndex.insert(std::make_pair(filename, dictionnary.size()));
00738                         dictionnary.push_back(filename);
00739 
00740                         // add the dependency index
00741                         depends.push_back(dicIndex);
00742                     }
00743                 }
00744                 // store the dependency list with the sheet ID
00745                 dependencies[sheetIds[NeededToRecompute[j]]] = depends;
00746             }
00747 
00748             // add the new creature, it could be already loaded by the packed sheets but will be overwritten with the new one
00749             typedef typename std::map<NLMISC::CSheetId, NLMISC::CSmartPtr<T> >::iterator TType1;
00750             typedef typename std::pair<TType1, bool> TType2;
00751             TType2 res = container.insert(std::make_pair(sheetIds[NeededToRecompute[j]], NLMISC::CSmartPtr<T>(new T())));
00752 
00753             (*res.first).second->readGeorges (form, sheetIds[NeededToRecompute[j]]);
00754             containerChanged = true;
00755         }
00756     }
00757 
00758     if(NeededToRecompute.size() > 0)
00759         nlinfo ("%d seconds to recompute %d sheets", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size());
00760 
00761     // free the georges loader if necessary
00762     if (formLoader != NULL)
00763     {
00764         NLGEORGES::UFormLoader::releaseLoader (formLoader);
00765         NLMISC::WarningLog->removeFilter ("CFormLoader: Can't open the form file");
00766     }
00767 
00768     // we have now to remove sheets that are in the container and not exist anymore in the sheet directories
00769     for (std::map<NLMISC::CSheetId, bool>::iterator it2 = sheetToRemove.begin(); it2 != sheetToRemove.end(); it2++)
00770     {
00771         if((*it2).second)
00772         {
00773             nlinfo ("the sheet '%s' is not in the directory, remove it from container", (*it2).first.toString().c_str());
00774             container.find((*it2).first)->second->removed();
00775             container.erase((*it2).first);
00776             containerChanged = true;
00777             dependencies.erase((*it2).first);
00778         }
00779     }
00780 
00781     // now, save the new container in the packedfile
00782     try
00783     {
00784         if(containerChanged)
00785         {
00786             NLMISC::COFile ofile;
00787             ofile.open(packedFilenamePath);
00788 
00789             // write the header.
00790             ofile.serialCheck(PACKED_SHEET_HEADER);
00791             ofile.serialCheck(PACKED_SHEET_VERSION);
00792             ofile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);
00793 
00794             // Write a dummy block size for now
00795             sint32  posBlockSize= ofile.getPos();
00796             uint32  dependBlockSize= 0;
00797             ofile.serial(dependBlockSize);
00798 
00799             // write the dictionnary
00800             ofile.serialCont(dictionnary);
00801 
00802             // write the dependencies data
00803             uint32 depSize = dependencies.size();
00804             ofile.serial(depSize);
00805             std::map<NLMISC::CSheetId, std::vector<uint32> >::iterator first(dependencies.begin()), last(dependencies.end());
00806             for (; first != last; ++first)
00807             {
00808                 NLMISC::CSheetId si = first->first;
00809                 ofile.serial(si);
00810                 ofile.serialCont(first->second);
00811             }
00812 
00813             // Then get the dicionary + dependencies size, and write it back to posBlockSize
00814             sint32  endBlockSize= ofile.getPos();
00815             dependBlockSize= (endBlockSize - posBlockSize) - 4;
00816             ofile.seek(posBlockSize, NLMISC::IStream::begin);
00817             ofile.serial(dependBlockSize);
00818             ofile.seek(endBlockSize, NLMISC::IStream::begin);
00819 
00820             // write the sheet data
00821             uint32 nbEntries = sheetIds.size();
00822             uint32 ver = T::getVersion ();
00823             ofile.serial (nbEntries);
00824             ofile.serial (ver);
00825             ofile.serialPtrCont(container);
00826             ofile.close ();
00827         }
00828     }
00829     catch (NLMISC::Exception &e)
00830     {
00831         nlinfo ("loadForm(): Exception during saving the packed file, it will be recreated next launch (%s)", e.what());
00832     }
00833 
00834     // housekeeping
00835     sheetIds.clear ();
00836     filenames.clear ();
00837 }
00838 
00839 // ***************************************************************************
00840 // variant with smart pointers, maintain with function above
00841 template <class T>
00842 void loadForm2(const std::string &sheetFilter, const std::string &packedFilename, std::map<NLMISC::CSheetId, T> &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)
00843 {
00844     std::vector<std::string> vs;
00845     vs.push_back(sheetFilter);
00846     loadForm2(vs, packedFilename, container, updatePackedSheet, errorIfPackedSheetNotGood);
00847 }
00848 
00849 
00850 
00851 // ***************************************************************************
00857 template <class T>
00858 void loadForm (const std::vector<std::string> &sheetFilters, const std::string &packedFilename, std::map<std::string, T> &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)
00859 {
00860     std::vector<std::string>                        dictionnary;
00861     std::map<std::string, uint>                     dictionnaryIndex;
00862     std::map<std::string, std::vector<uint32> >     dependencies;
00863     std::vector<uint32>                             dependencyDates;
00864 
00865     // check the extension (i know that file like "foo.packed_sheetsbar" will be accepted but this check is enough...)
00866     nlassert (packedFilename.find (".packed_sheets") != std::string::npos);
00867 
00868     std::string packedFilenamePath = NLMISC::CPath::lookup(packedFilename, false, false);
00869     if (packedFilenamePath.empty())
00870     {
00871         packedFilenamePath = packedFilename;
00872     }
00873 
00874     // make sure the CSheetId singleton has been properly initialised
00875 //  NLMISC::CSheetId::init(updatePackedSheet);
00876 
00877     // load the packed sheet if exists
00878     try
00879     {
00880         NLMISC::CIFile ifile;
00881         ifile.setCacheFileOnOpen(true);
00882         ifile.open (packedFilenamePath);
00883         // an exception will be launch if the file is not the good version or if the file is not found
00884 
00885         nlinfo ("loadForm(): Loading packed file '%s'", packedFilename.c_str());
00886 
00887         // read the header
00888         ifile.serialCheck(PACKED_SHEET_HEADER);
00889         ifile.serialCheck(PACKED_SHEET_VERSION);
00890         ifile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);
00891 
00892         // Read depend block size
00893         uint32  dependBlockSize;
00894         ifile.serial(dependBlockSize);
00895 
00896         // Read the dependencies only if update packed sheet
00897         if(updatePackedSheet)
00898         {
00899             // read the dictionnary
00900             {
00901                 ifile.serialCont(dictionnary);
00902             }
00903             // read the dependency data
00904             {
00905                 uint32 depSize;
00906                 ifile.serial(depSize);
00907                 for (uint i=0; i<depSize; ++i)
00908                 {
00909                     std::string sheetName;
00910 
00911                     // Avoid copy, use []
00912                     ifile.serial(sheetName);
00913                     ifile.serialCont(dependencies[sheetName]);
00914                 }
00915             }
00916         }
00917         // else dummy read one big block => no heavy reallocation / free
00918         else if(dependBlockSize>0)
00919         {
00920             std::vector<uint8>  bigBlock;
00921             bigBlock.resize(dependBlockSize);
00922             ifile.serialBuffer(&bigBlock[0], dependBlockSize);
00923         }
00924 
00925         // read the packed sheet data
00926         uint32  nbEntries;
00927         uint32  ver;
00928         ifile.serial (nbEntries);
00929         ifile.serial (ver);
00930         if(ver != T::getVersion ())
00931             throw NLMISC::Exception("The packed sheet version in stream is different of the code");
00932         ifile.serialCont (container);
00933         ifile.close ();
00934     }
00935     catch (NLMISC::Exception &e)
00936     {
00937         // clear the container because it can contains partially loaded sheet so we must clean it before continue
00938         container.clear ();
00939         if (!updatePackedSheet)
00940         {
00941             if (errorIfPackedSheetNotGood)
00942                 nlerror ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what());
00943             else
00944                 nlinfo ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what());
00945 
00946             return;
00947         }
00948         else
00949         {
00950             nlinfo ("loadForm(): Exception during reading the packed file, I'll reconstruct it (%s)", e.what());
00951         }
00952     }
00953 
00954     // if we don't want to update packed sheet, we have nothing more to do
00955     if (!updatePackedSheet)
00956     {
00957         nlinfo ("Don't update the packed sheet with real sheet");
00958         return;
00959     }
00960 
00961     // retreive the date of all dependency file
00962     {
00963         for (uint i=0; i<dictionnary.size(); ++i)
00964         {
00965             std::string p = NLMISC::CPath::lookup (dictionnary[i], false, false);
00966             if (!p.empty())
00967             {
00968                 uint32 d = NLMISC::CFile::getFileModificationDate(p);
00969                 dependencyDates.push_back(d);
00970             }
00971             else
00972             {
00973                 // file not found !
00974                 // write a future date to invalidate any file dependent on it
00975                 nldebug("Can't find dependent file %s !", dictionnary[i].c_str());
00976                 dependencyDates.push_back(0xffffffff);
00977             }
00978         }
00979     }
00980 
00981     // build a vector of the sheetFilters sheet ids (ie: "item")
00982     std::vector<std::string> sheetNames;
00983     {
00984         std::vector<std::string>::const_iterator first(sheetFilters.begin()), last(sheetFilters.end());
00985         for (; first != last; ++first)
00986             NLMISC::CPath::getFileList(*first, sheetNames);
00987 
00988     }
00989 
00990     // if there's no file, nothing to do
00991     if (sheetNames.empty())
00992         return;
00993 
00994     // set up the current sheet in container to remove sheet that are in the container and not in the directory anymore
00995     std::map<std::string, bool> sheetToRemove;
00996     {
00997         typename std::map<std::string, T>::iterator first(container.begin()), last(container.end());
00998         for(; first != last; ++first)
00999             sheetToRemove.insert (make_pair(first->first, true));
01000     }
01001 
01002     // check if we need to create a new .pitems or just read it
01003     uint32 packedFiledate = NLMISC::CFile::getFileModificationDate(packedFilenamePath);
01004 
01005     bool containerChanged = false;
01006 
01007     NLGEORGES::UFormLoader *formLoader = NULL;
01008 
01009     std::vector<uint> NeededToRecompute;
01010 
01011     for (uint k = 0; k < sheetNames.size(); k++)
01012     {
01013         std::string p = NLMISC::CPath::lookup (sheetNames[k], false, false);
01014         if (p.empty())
01015         {
01016             continue;
01017         }
01018         uint32 d = NLMISC::CFile::getFileModificationDate(p);
01019 
01020         // no need to remove this sheet
01021         sheetToRemove[sheetNames[k]] = false;
01022 
01023         if( d > packedFiledate || container.find (sheetNames[k]) == container.end())
01024         {
01025             NeededToRecompute.push_back(k);
01026         }
01027         else
01028         {
01029             // check the date of each parent
01030             nlassert(dependencies.find(sheetNames[k]) != dependencies.end());
01031             std::vector<uint32> &depends = dependencies[sheetNames[k]];
01032 
01033             for (uint i=0; i<depends.size(); ++i)
01034             {
01035                 if (dependencyDates[depends[i]] > packedFiledate)
01036                 {
01037                     nldebug("Dependancy on %s for %s not up to date !",
01038                         dictionnary[depends[i]].c_str(), sheetNames[k].c_str());
01039                     NeededToRecompute.push_back(k);
01040                     break;
01041                 }
01042             }
01043         }
01044     }
01045 
01046     nlinfo ("%d sheets checked, %d need to be recomputed", sheetNames.size(), NeededToRecompute.size());
01047 
01048     NLMISC::TTime lastTime = NLMISC::CTime::getLocalTime ();
01049     NLMISC::TTime start = NLMISC::CTime::getLocalTime ();
01050 
01051     NLMISC::CSmartPtr<NLGEORGES::UForm> form;
01052 
01053     for (uint j = 0; j < NeededToRecompute.size(); j++)
01054     {
01055         if(NLMISC::CTime::getLocalTime () > lastTime + 5000)
01056         {
01057             lastTime = NLMISC::CTime::getLocalTime ();
01058             if(j>0)
01059                 nlinfo ("%.0f%% completed (%d/%d), %d seconds remaining", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(lastTime-start)/j/1000);
01060         }
01061 
01062         // create the georges loader if necessary
01063         if (formLoader == NULL)
01064         {
01065             NLMISC::WarningLog->addNegativeFilter("CFormLoader: Can't open the form file");
01066             formLoader = NLGEORGES::UFormLoader::createLoader ();
01067         }
01068 
01069         // Load the form with given sheet id
01070         form = formLoader->loadForm (sheetNames[NeededToRecompute[j]].c_str ());
01071         if (form)
01072         {
01073             // build the dependency data
01074             {
01075                 std::vector<uint32>     depends;
01076                 std::set<std::string>   dependFiles;
01077                 form->getDependencies (dependFiles);
01078                 nlassert(dependFiles.find(sheetNames[NeededToRecompute[j]]) != dependFiles.end());
01079                 // remove the sheet itself from the container
01080                 dependFiles.erase(sheetNames[NeededToRecompute[j]]);
01081 
01082                 std::set<std::string>::iterator first(dependFiles.begin()), last(dependFiles.end());
01083                 for (; first != last; ++first)
01084                 {
01085                     std::string p = NLMISC::CPath::lookup (*first, false, false);
01086                     if (!p.empty())
01087                     {
01088 //                      uint32 date = NLMISC::CFile::getFileModificationDate(p);
01089 
01090                         uint dicIndex;
01091                         std::string filename = NLMISC::CFile::getFilename(p);
01092 
01093                         if (dictionnaryIndex.find(filename) == dictionnaryIndex.end())
01094                         {
01095                             // add a new dictionnary entry
01096                             dicIndex = dictionnary.size();
01097                             dictionnaryIndex.insert(std::make_pair(filename, dictionnary.size()));
01098                             dictionnary.push_back(filename);
01099                         }
01100                         else
01101                         {
01102                             dicIndex = dictionnaryIndex.find(filename)->second;
01103                         }
01104 
01105                         // add the dependecy index
01106                         depends.push_back(dicIndex);
01107                     }
01108                 }
01109                 // store the dependency list with the sheet ID
01110                 dependencies[sheetNames[NeededToRecompute[j]]] = depends;
01111             }
01112 
01113             // add the new creature, it could be already loaded by the packed sheets but will be overwritten with the new one
01114             typedef typename std::map<std::string, T>::iterator TType1;
01115             typedef typename std::pair<TType1, bool> TType2;
01116             TType2 res = container.insert(std::make_pair(sheetNames[NeededToRecompute[j]],T()));
01117 
01118             (*res.first).second.readGeorges (form, sheetNames[NeededToRecompute[j]]);
01119             containerChanged = true;
01120         }
01121     }
01122 
01123     nlinfo ("%d seconds to recompute %d sheets", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size());
01124 
01125     // free the georges loader if necessary
01126     if (formLoader != NULL)
01127     {
01128         NLGEORGES::UFormLoader::releaseLoader (formLoader);
01129         NLMISC::WarningLog->removeFilter ("CFormLoader: Can't open the form file");
01130     }
01131 
01132     // we have now to remove sheet that are in the container and not exist anymore in the sheet directories
01133     for (std::map<std::string, bool>::iterator it2 = sheetToRemove.begin(); it2 != sheetToRemove.end(); it2++)
01134     {
01135         if(it2->second)
01136         {
01137             // inform the contained object that it is no more needed.
01138             container.find(it2->first)->second.removed();
01139             container.erase(it2->first);
01140             containerChanged = true;
01141             dependencies.erase((*it2).first);
01142         }
01143     }
01144 
01145     // now, save the new container in the packedfile
01146     try
01147     {
01148         if(containerChanged)
01149         {
01150             NLMISC::COFile ofile;
01151             ofile.open(packedFilenamePath);
01152 
01153             // write the header.
01154             ofile.serialCheck(PACKED_SHEET_HEADER);
01155             ofile.serialCheck(PACKED_SHEET_VERSION);
01156             ofile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);
01157 
01158             // Write a dummy block size for now
01159             sint32  posBlockSize= ofile.getPos();
01160             uint32  dependBlockSize= 0;
01161             ofile.serial(dependBlockSize);
01162 
01163             // write the dictionnary
01164             ofile.serialCont(dictionnary);
01165 
01166             // write the dependencies data
01167             uint32 depSize = dependencies.size();
01168             ofile.serial(depSize);
01169             std::map<std::string, std::vector<uint32> >::iterator first(dependencies.begin()), last(dependencies.end());
01170             for (; first != last; ++first)
01171             {
01172                 std::string  sheetName = first->first;
01173                 ofile.serial(sheetName);
01174                 ofile.serialCont(first->second);
01175             }
01176 
01177             // Then get the dicionary + dependencies size, and write it back to posBlockSize
01178             sint32  endBlockSize= ofile.getPos();
01179             dependBlockSize= (endBlockSize - posBlockSize) - 4;
01180             ofile.seek(posBlockSize, NLMISC::IStream::begin);
01181             ofile.serial(dependBlockSize);
01182             ofile.seek(endBlockSize, NLMISC::IStream::begin);
01183 
01184             // write the sheet data
01185             uint32 nbEntries = sheetNames.size();
01186             uint32 ver = T::getVersion ();
01187             ofile.serial (nbEntries);
01188             ofile.serial (ver);
01189             ofile.serialCont(container);
01190             ofile.close ();
01191         }
01192     }
01193     catch (NLMISC::Exception &e)
01194     {
01195         nlinfo ("loadForm(): Exception during saving the packed file, it will be recreated next launch (%s)", e.what());
01196     }
01197 
01198     // housekeeping
01199     sheetNames.clear ();
01200 }
01201 
01202 // ***************************************************************************
01208 template <class T>
01209 void loadForm (const std::string &sheetFilter, const std::string &packedFilename, std::map<std::string, T> &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)
01210 {
01211     std::vector<std::string> vs;
01212     vs.push_back(sheetFilter);
01213     loadForm(vs, packedFilename, container, updatePackedSheet, errorIfPackedSheetNotGood);
01214 }
01215 
01216 // ***************************************************************************
01217 template <class T>
01218 void loadFormNoPackedSheet (const std::string &sheetFilter, std::map<NLMISC::CSheetId, T> &container, const std::string &wildcardFilter)
01219 {
01220     std::vector<std::string> vs;
01221     vs.push_back(sheetFilter);
01222     loadFormNoPackedSheet(vs, container, wildcardFilter);
01223 }
01224 
01225 // ***************************************************************************
01226 // variant with smart pointers, maintain with function above
01227 template <class T>
01228 void loadFormNoPackedSheet2 (const std::string &sheetFilter, std::map<NLMISC::CSheetId, T> &container, const std::string &wildcardFilter)
01229 {
01230     std::vector<std::string> vs;
01231     vs.push_back(sheetFilter);
01232     loadFormNoPackedSheet2(vs, container, wildcardFilter);
01233 }
01234 
01235 // ***************************************************************************
01242 template <class T>
01243 void loadFormNoPackedSheet (const std::vector<std::string> &sheetFilters, std::map<NLMISC::CSheetId, T> &container, const std::string &wildcardFilter)
01244 {
01245     // make sure the CSheetId singleton has been properly initialised
01246     NLMISC::CSheetId::init(false);
01247 
01248     // build a vector of the sheetFilters sheet ids (ie: "item")
01249     std::vector<NLMISC::CSheetId> sheetIds;
01250     std::vector<std::string> filenames;
01251     for (uint i = 0; i < sheetFilters.size(); i++)
01252         NLMISC::CSheetId::buildIdVector(sheetIds, filenames, sheetFilters[i]);
01253 
01254 
01255     // if there s no file, nothing to do
01256     if (sheetIds.empty())
01257         return;
01258 
01259 
01260     // compute sheets that needs to be recomputed
01261     std::vector<uint> NeededToRecompute;
01262     for (uint k = 0; k < filenames.size(); k++)
01263     {
01264         std::string p = NLMISC::CPath::lookup (filenames[k], false, false);
01265         if (p.empty()) continue;
01266         // check if wildcardok
01267         if(!wildcardFilter.empty() && !NLMISC::testWildCard(p,wildcardFilter)) continue;
01268 
01269         NeededToRecompute.push_back(k);
01270     }
01271     nlinfo ("%d sheets checked, %d need to be recomputed", filenames.size(), NeededToRecompute.size());
01272 
01273 
01274     NLMISC::TTime last = NLMISC::CTime::getLocalTime ();
01275     NLMISC::TTime start = NLMISC::CTime::getLocalTime ();
01276     NLGEORGES::UFormLoader *formLoader = NULL;
01277     NLMISC::CSmartPtr<NLGEORGES::UForm> form;
01278     std::vector<NLMISC::CSmartPtr<NLGEORGES::UForm> >   cacheFormList;
01279 
01280     // For all sheets need to recompute
01281     for (uint j = 0; j < NeededToRecompute.size(); j++)
01282     {
01283         if(NLMISC::CTime::getLocalTime () > last + 5000)
01284         {
01285             last = NLMISC::CTime::getLocalTime ();
01286             if(j>0)
01287                 nlinfo ("%.0f%% completed (%d/%d), %d seconds remaining", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(last-start)/j/1000);
01288         }
01289 
01290         // create the georges loader if necessary
01291         if (formLoader == NULL)
01292         {
01293             NLMISC::WarningLog->addNegativeFilter("CFormLoader: Can't open the form file");
01294             formLoader = NLGEORGES::UFormLoader::createLoader ();
01295         }
01296 
01297         //  cache used to retain information (to optimize time).
01298         if (form)
01299             cacheFormList.push_back (form);
01300 
01301         // Load the form with given sheet id
01302         form = formLoader->loadForm (sheetIds[NeededToRecompute[j]].toString().c_str ());
01303         if (form)
01304         {
01305             // add the new creature, it could be already loaded by the packed sheets but will be overwritten with the new one
01306             typedef typename std::map<NLMISC::CSheetId, T>::iterator TType1;
01307             typedef typename std::pair<TType1, bool> TType2;
01308             TType2 res = container.insert(std::make_pair(sheetIds[NeededToRecompute[j]],T()));
01309 
01310             (*res.first).second.readGeorges (form, sheetIds[NeededToRecompute[j]]);
01311         }
01312     }
01313 
01314     if(NeededToRecompute.size() > 0)
01315         nlinfo ("%d seconds to recompute %d sheets", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size());
01316 
01317     // free the georges loader if necessary
01318     if (formLoader != NULL)
01319     {
01320         NLGEORGES::UFormLoader::releaseLoader (formLoader);
01321         NLMISC::WarningLog->removeFilter ("CFormLoader: Can't open the form file");
01322     }
01323 
01324     // housekeeping
01325     sheetIds.clear ();
01326     filenames.clear ();
01327 }
01328 
01329 // ***************************************************************************
01330 // variant with smart pointers, maintain with function above
01331 template <class T>
01332 void loadFormNoPackedSheet2 (const std::vector<std::string> &sheetFilters, std::map<NLMISC::CSheetId, NLMISC::CSmartPtr<T> > &container, const std::string &wildcardFilter)
01333 {
01334     // make sure the CSheetId singleton has been properly initialised
01335     NLMISC::CSheetId::init(false);
01336 
01337     // build a vector of the sheetFilters sheet ids (ie: "item")
01338     std::vector<NLMISC::CSheetId> sheetIds;
01339     std::vector<std::string> filenames;
01340     for (uint i = 0; i < sheetFilters.size(); i++)
01341         NLMISC::CSheetId::buildIdVector(sheetIds, filenames, sheetFilters[i]);
01342 
01343 
01344     // if there's no file, nothing to do
01345     if (sheetIds.empty())
01346         return;
01347 
01348 
01349     // compute sheets that needs to be recomputed
01350     std::vector<uint> NeededToRecompute;
01351     for (uint k = 0; k < filenames.size(); k++)
01352     {
01353         std::string p = NLMISC::CPath::lookup (filenames[k], false, false);
01354         if (p.empty()) continue;
01355         // check if wildcardok
01356         if(!wildcardFilter.empty() && !NLMISC::testWildCard(p,wildcardFilter)) continue;
01357 
01358         NeededToRecompute.push_back(k);
01359     }
01360     nlinfo ("%d sheets checked, %d need to be recomputed", filenames.size(), NeededToRecompute.size());
01361 
01362 
01363     NLMISC::TTime last = NLMISC::CTime::getLocalTime ();
01364     NLMISC::TTime start = NLMISC::CTime::getLocalTime ();
01365     NLGEORGES::UFormLoader *formLoader = NULL;
01366     NLMISC::CSmartPtr<NLGEORGES::UForm> form;
01367     std::vector<NLMISC::CSmartPtr<NLGEORGES::UForm> >   cacheFormList;
01368 
01369     // For all sheets need to recompute
01370     for (uint j = 0; j < NeededToRecompute.size(); j++)
01371     {
01372         if(NLMISC::CTime::getLocalTime () > last + 5000)
01373         {
01374             last = NLMISC::CTime::getLocalTime ();
01375             if(j>0)
01376                 nlinfo ("%.0f%% completed (%d/%d), %d seconds remaining", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(last-start)/j/1000);
01377         }
01378 
01379         // create the georges loader if necessary
01380         if (formLoader == NULL)
01381         {
01382             NLMISC::WarningLog->addNegativeFilter("CFormLoader: Can't open the form file");
01383             formLoader = NLGEORGES::UFormLoader::createLoader ();
01384         }
01385 
01386         //  cache used to retain information (to optimize time).
01387         if (form)
01388             cacheFormList.push_back (form);
01389 
01390         // Load the form with given sheet id
01391         form = formLoader->loadForm (sheetIds[NeededToRecompute[j]].toString().c_str ());
01392         if (form)
01393         {
01394             // add the new creature, it could be already loaded by the packed sheets but will be overwritten with the new one
01395             typedef typename std::map<NLMISC::CSheetId, NLMISC::CSmartPtr<T> >::iterator TType1;
01396             typedef typename std::pair<TType1, bool> TType2;
01397             TType2 res = container.insert(std::make_pair(sheetIds[NeededToRecompute[j]], NLMISC::CSmartPtr<T>(new T())));
01398 
01399             (*res.first).second->readGeorges (form, sheetIds[NeededToRecompute[j]]);
01400         }
01401     }
01402 
01403     if(NeededToRecompute.size() > 0)
01404         nlinfo ("%d seconds to recompute %d sheets", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size());
01405 
01406     // free the georges loader if necessary
01407     if (formLoader != NULL)
01408     {
01409         NLGEORGES::UFormLoader::releaseLoader (formLoader);
01410         NLMISC::WarningLog->removeFilter ("CFormLoader: Can't open the form file");
01411     }
01412 
01413     // housekeeping
01414     sheetIds.clear ();
01415     filenames.clear ();
01416 }
01417 
01418 #endif // NL_LOAD_FORM_H
01419 
01420 /* End of load_form.h */

Generated on Thu Jan 7 08:26:22 2010 for NeL by  doxygen 1.6.1