load_form.h File Reference


Detailed Description

quick load of values from georges sheet (using a fast load with compacted file)

Id
load_form.h,v 1.31 2003/11/04 09:25:09 distrib Exp

Definition in file load_form.h.

#include "nel/misc/types_nl.h"
#include <map>
#include <string>
#include <vector>
#include "nel/misc/path.h"
#include "nel/misc/file.h"
#include "nel/misc/sheet_id.h"
#include "nel/georges/u_form_loader.h"
#include "nel/georges/u_form.h"

Go to the source code of this file.

Functions

template<class T> void loadForm (const std::vector< std::string > &sheetFilters, const std::string &packedFilename, std::map< std::string, T > &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)
template<class T> void loadForm (const std::string &sheetFilter, const std::string &packedFilename, std::map< std::string, T > &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)
template<class T> void loadForm (const std::vector< std::string > &sheetFilters, const std::string &packedFilename, std::map< NLMISC::CSheetId, T > &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)
template<class T> void loadForm (const std::string &sheetFilter, const std::string &packedFilename, std::map< NLMISC::CSheetId, T > &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)

Variables

const uint32 PACKED_SHEET_HEADER = 'PKSH'
 Dictionnaley entry for dependency information.

const uint32 PACKED_SHEET_VERSION = 5
const uint32 PACKED_SHEET_VERSION_COMPATIBLE = 0


Function Documentation

template<class T>
void loadForm const std::vector< std::string > &  sheetFilters,
const std::string &  packedFilename,
std::map< std::string, T > &  container,
bool  updatePackedSheet = true,
bool  errorIfPackedSheetNotGood = true
 

This function is used to load values from georges sheet in a quick way.

Parameters:
sheetFilter a vector of string to filter the sheet in the case you need more than one filter
packedFilename the name of the file that this function will generate (extension must be "packed_sheets")
container the map that will be filled by this function

Definition at line 522 of file load_form.h.

References NLMISC::COFile::close(), NLMISC::CIFile::close(), NLGEORGES::UFormLoader::createLoader(), NLMISC::CPath::getFileList(), NLMISC::CFile::getFileModificationDate(), NLMISC::CFile::getFilename(), NLMISC::CTime::getLocalTime(), NLMISC::COFile::getPos(), NLGEORGES::UFormLoader::loadForm(), NLMISC::CPath::lookup(), nlassert, nldebug, nlerror, nlinfo, NLMISC::COFile::open(), NLMISC::CIFile::open(), PACKED_SHEET_HEADER, PACKED_SHEET_VERSION, PACKED_SHEET_VERSION_COMPATIBLE, NLGEORGES::UFormLoader::releaseLoader(), res, NLMISC::COFile::seek(), NLMISC::IStream::serial(), NLMISC::CIFile::serialBuffer(), NLMISC::IStream::serialCheck(), NLMISC::IStream::serialCont(), NLMISC::IStream::serialVersion(), NLMISC::CIFile::setCacheFileOnOpen(), sint, sint32, NLMISC::TTime, uint, and uint32.

Referenced by loadForm().

00523 {
00524         std::vector<std::string>                                                dictionnary;
00525         std::map<std::string, uint>                                             dictionnaryIndex;
00526         std::map<std::string, std::vector<uint32> >             dependencies;
00527         std::vector<uint32>                                                             dependencyDates;
00528 
00529         // check the extension (i know that file like "foo.packed_sheetsbar" will be accepted but this check is enough...)
00530         nlassert (packedFilename.find (".packed_sheets") != std::string::npos);
00531 
00532         std::string packedFilenamePath = NLMISC::CPath::lookup(packedFilename, false, false);
00533         if (packedFilenamePath.empty())
00534         {
00535                 packedFilenamePath = packedFilename;
00536         }
00537 
00538         // make sure the CSheetId singleton has been properly initialised
00539 //      NLMISC::CSheetId::init(updatePackedSheet);
00540 
00541         // load the packed sheet if exists
00542         try
00543         {
00544                 NLMISC::CIFile ifile;
00545                 ifile.setCacheFileOnOpen(true);
00546                 ifile.open (packedFilenamePath);
00547                 // an exception will be launch if the file is not the good version or if the file is not found
00548 
00549                 nlinfo ("loadForm(): Loading packed file '%s'", packedFilename.c_str());
00550 
00551                 // read the header
00552                 ifile.serialCheck(PACKED_SHEET_HEADER);
00553                 ifile.serialCheck(PACKED_SHEET_VERSION);
00554                 sint    loadFormVersion= ifile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);
00555                 
00556                 // Read depend block size
00557                 uint32  dependBlockSize;
00558                 ifile.serial(dependBlockSize);
00559                 
00560                 // Read the dependencies only if update packed sheet
00561                 if(updatePackedSheet)           
00562                 {
00563                         // read the dictionnary
00564                         {
00565                                 ifile.serialCont(dictionnary);
00566                         }
00567                         // read the dependency data
00568                         {
00569                                 uint32 depSize;
00570                                 ifile.serial(depSize);
00571                                 for (uint i=0; i<depSize; ++i)
00572                                 {
00573                                         std::string sheetName;
00574 
00575                                         // Avoid copy, use []
00576                                         ifile.serial(sheetName);
00577                                         ifile.serialCont(dependencies[sheetName]);
00578                                 }
00579                         }
00580                 }
00581                 // else dummy read one big block => no heavy reallocation / free
00582                 else if(dependBlockSize>0)
00583                 {
00584                         std::vector<uint8>      bigBlock;
00585                         bigBlock.resize(dependBlockSize);
00586                         ifile.serialBuffer(&bigBlock[0], dependBlockSize);
00587                 }
00588                 
00589                 // read the packed sheet data
00590                 uint32  nbEntries;
00591                 uint32  ver;
00592                 ifile.serial (nbEntries);
00593                 ifile.serial (ver);
00594                 if(ver != T::getVersion ())
00595                         throw Exception("The packed sheet version in stream is different of the code");
00596                 ifile.serialCont (container);
00597                 ifile.close ();
00598         }
00599         catch (NLMISC::Exception &e)
00600         {
00601                 // clear the container because it can contains partially loaded sheet so we must clean it before continue
00602                 container.clear ();
00603                 if (!updatePackedSheet)
00604                 {
00605                         if (errorIfPackedSheetNotGood)
00606                                 nlerror ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what());
00607                         else
00608                                 nlinfo ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what());
00609 
00610                         return;
00611                 }
00612                 else
00613                 {
00614                         nlinfo ("loadForm(): Exception during reading the packed file, I'll reconstruct it (%s)", e.what());
00615                 }
00616         }
00617 
00618         // if we don't want to update packed sheet, we nothing more to do
00619         if (!updatePackedSheet)
00620         {
00621                 nlinfo ("Don't update the packed sheet with real sheet");
00622                 return;
00623         }
00624 
00625         // retreive the date of all dependency file
00626         {
00627                 for (uint i=0; i<dictionnary.size(); ++i)
00628                 {
00629                         std::string p = NLMISC::CPath::lookup (dictionnary[i], false, false);
00630                         if (!p.empty()) 
00631                         {
00632                                 uint32 d = NLMISC::CFile::getFileModificationDate(p);
00633                                 dependencyDates.push_back(d);
00634                         }
00635                         else
00636                         {
00637                                 // file not found !
00638                                 // write a future date to invalidate any file dependent on it
00639                                 nldebug("Can't find dependent file %s !", dictionnary[i].c_str());
00640                                 dependencyDates.push_back(0xffffffff);
00641                         }
00642                 }
00643         }
00644 
00645         // build a vector of the sheetFilters sheet ids (ie: "item")
00646         std::vector<std::string> sheetNames;
00647         {
00648                 std::vector<std::string>::const_iterator first(sheetFilters.begin()), last(sheetFilters.end());
00649                 for (; first != last; ++first)
00650                         NLMISC::CPath::getFileList(*first, sheetNames);
00651 
00652         }
00653 
00654         // if there s no file, nothing to do
00655         if (sheetNames.empty())
00656                 return;
00657 
00658         // set up the current sheet in container to remove sheet that are in the container and not in the directory anymore
00659         std::map<std::string, bool> sheetToRemove;
00660         {
00661                 typename std::map<std::string, T>::iterator first(container.begin()), last(container.end());
00662                 for(; first != last; ++first)
00663                         sheetToRemove.insert (make_pair(first->first, true));
00664         }
00665 
00666         // check if we need to create a new .pitems or just read it
00667         uint32 packedFiledate = NLMISC::CFile::getFileModificationDate(packedFilenamePath);
00668 
00669         bool containerChanged = false;
00670 
00671         NLGEORGES::UFormLoader *formLoader = NULL;
00672 
00673         std::vector<uint> NeededToRecompute;
00674 
00675         for (uint k = 0; k < sheetNames.size(); k++)
00676         {
00677                 std::string p = NLMISC::CPath::lookup (sheetNames[k], false, false);
00678                 if (p.empty()) 
00679                 {
00680                         continue;
00681                 }
00682                 uint32 d = NLMISC::CFile::getFileModificationDate(p);
00683 
00684                 // no need to remove this sheet
00685                 sheetToRemove[sheetNames[k]] = false;
00686 
00687                 if( d > packedFiledate || container.find (sheetNames[k]) == container.end())
00688                 {
00689                         NeededToRecompute.push_back(k);
00690                 }
00691                 else
00692                 {
00693                         // check the date of each parent
00694                         nlassert(dependencies.find(sheetNames[k]) != dependencies.end());
00695                         std::vector<uint32> &depends = dependencies[sheetNames[k]];
00696 
00697                         for (uint i=0; i<depends.size(); ++i)
00698                         {
00699                                 if (dependencyDates[depends[i]] > packedFiledate)
00700                                 {
00701                                         nldebug("Dependancy on %s for %s not up to date !", 
00702                                                 dictionnary[depends[i]].c_str(), sheetNames[k].c_str());
00703                                         NeededToRecompute.push_back(k);
00704                                         break;
00705                                 }
00706                         }
00707                 }
00708         }
00709 
00710         nlinfo ("%d sheets checked, %d need to be recomputed", sheetNames.size(), NeededToRecompute.size());
00711 
00712         NLMISC::TTime lastTime = NLMISC::CTime::getLocalTime ();
00713         NLMISC::TTime start = NLMISC::CTime::getLocalTime ();
00714 
00715         NLMISC::CSmartPtr<NLGEORGES::UForm> form;
00716 
00717         for (uint j = 0; j < NeededToRecompute.size(); j++)
00718         {
00719                 if(NLMISC::CTime::getLocalTime () > lastTime + 5000)
00720                 {
00721                         lastTime = NLMISC::CTime::getLocalTime ();
00722                         if(j>0)
00723                                 nlinfo ("%.0f%% completed (%d/%d), %d seconds remaining", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(lastTime-start)/j/1000);
00724                 }
00725 
00726                 // create the georges loader if necessary
00727                 if (formLoader == NULL)
00728                 {
00729                         NLMISC::WarningLog->addNegativeFilter("CFormLoader: Can't open the form file");
00730                         formLoader = NLGEORGES::UFormLoader::createLoader ();
00731                 }
00732 
00733                 // Load the form with given sheet id
00734                 form = formLoader->loadForm (sheetNames[NeededToRecompute[j]].c_str ());
00735                 if (form)
00736                 {
00737                         // build the dependency data
00738                         {
00739                                 std::vector<uint32>             depends;
00740                                 std::set<std::string>   dependFiles;
00741                                 form->getDependencies (dependFiles);
00742                                 nlassert(dependFiles.find(sheetNames[NeededToRecompute[j]]) != dependFiles.end());
00743                                 // remove the sheet itself from the container
00744                                 dependFiles.erase(sheetNames[NeededToRecompute[j]]);
00745 
00746                                 std::set<std::string>::iterator first(dependFiles.begin()), last(dependFiles.end());
00747                                 for (; first != last; ++first)
00748                                 {
00749                                         std::string p = NLMISC::CPath::lookup (*first, false, false);
00750                                         if (!p.empty())
00751                                         {
00752                                                 uint32 date = NLMISC::CFile::getFileModificationDate(p);
00753 
00754                                                 uint dicIndex;
00755                                                 std::string filename = NLMISC::CFile::getFilename(p);
00756 
00757                                                 if (dictionnaryIndex.find(filename) == dictionnaryIndex.end())
00758                                                 {
00759                                                         // add a new dictionnary entry
00760                                                         dicIndex = dictionnary.size();
00761                                                         dictionnaryIndex.insert(std::make_pair(filename, dictionnary.size()));
00762                                                         dictionnary.push_back(filename);
00763                                                 }
00764                                                 else
00765                                                 {
00766                                                         dicIndex = dictionnaryIndex.find(filename)->second;
00767                                                 }
00768 
00769                                                 // add the dependecy index
00770                                                 depends.push_back(dicIndex);
00771                                         }
00772                                 }
00773                                 // store the dependency list with the sheet ID
00774                                 dependencies[sheetNames[NeededToRecompute[j]]] = depends;
00775                         }
00776                         
00777                         // add the new creature, it could be already loaded by the packed sheets but will be overwrite with the new one
00778                         typedef typename std::map<std::string, T>::iterator TType1;
00779             typedef typename std::pair<TType1, bool> TType2;
00780                         TType2 res = container.insert(std::make_pair(sheetNames[NeededToRecompute[j]],T()));
00781 
00782                         (*res.first).second.readGeorges (form, sheetNames[NeededToRecompute[j]]);
00783                         containerChanged = true;
00784                 }
00785         }
00786 
00787         nlinfo ("%d seconds to recompute %d sheets", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size());
00788 
00789         // free the georges loader if necessary
00790         if (formLoader != NULL)
00791         {
00792                 NLGEORGES::UFormLoader::releaseLoader (formLoader);
00793                 NLMISC::WarningLog->removeFilter ("CFormLoader: Can't open the form file");
00794         }
00795 
00796         // we have now to remove sheet that are in the container and not exist anymore in the sheet directories
00797         for (std::map<std::string, bool>::iterator it2 = sheetToRemove.begin(); it2 != sheetToRemove.end(); it2++)
00798         {
00799                 if(it2->second)
00800                 {
00801                         // informe the contained object that it is no more needed.
00802                         container.find(it2->first)->second.removed();
00803                         container.erase(it2->first);
00804                         containerChanged = true;
00805                         dependencies.erase((*it2).first);
00806                 }
00807         }
00808 
00809         // now, save the new container in the packedfile
00810         try
00811         {
00812                 if(containerChanged)
00813                 {
00814                         NLMISC::COFile ofile;
00815                         ofile.open(packedFilenamePath);
00816 
00817                         // write the header.
00818                         ofile.serialCheck(PACKED_SHEET_HEADER);
00819                         ofile.serialCheck(PACKED_SHEET_VERSION);
00820                         ofile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);
00821                         
00822                         // Write a dummy block size for now
00823                         sint32  posBlockSize= ofile.getPos();
00824                         uint32  dependBlockSize= 0;
00825                         ofile.serial(dependBlockSize);
00826                         
00827                         // write the dictionnary
00828                         ofile.serialCont(dictionnary);
00829 
00830                         // write the dependencies data
00831                         uint32 depSize = dependencies.size();
00832                         ofile.serial(depSize);
00833                         std::map<std::string, std::vector<uint32> >::iterator first(dependencies.begin()), last(dependencies.end());
00834                         for (; first != last; ++first)
00835                         {
00836                                 std::string  sheetName = first->first;
00837                                 ofile.serial(sheetName);
00838                                 ofile.serialCont(first->second);
00839                         }
00840 
00841                         // Then get the dicionary + dependencies size, and write it back to posBlockSize
00842                         sint32  endBlockSize= ofile.getPos();
00843                         dependBlockSize= (endBlockSize - posBlockSize) - 4;
00844                         ofile.seek(posBlockSize, NLMISC::IStream::begin);
00845                         ofile.serial(dependBlockSize);
00846                         ofile.seek(endBlockSize, NLMISC::IStream::begin);
00847                 
00848                         // write the sheet data
00849                         uint32 nbEntries = sheetNames.size();
00850                         uint32 ver = T::getVersion ();
00851                         ofile.serial (nbEntries);
00852                         ofile.serial (ver);
00853                         ofile.serialCont(container);
00854                         ofile.close ();
00855                 }
00856         }
00857         catch (NLMISC::Exception &e)
00858         {
00859                 nlinfo ("loadForm(): Exception during saving the packed file, it will be recreated next launch (%s)", e.what());
00860         }
00861 
00862         // housekeeping
00863         sheetNames.clear ();
00864 }

template<class T>
void loadForm const std::string &  sheetFilter,
const std::string &  packedFilename,
std::map< std::string, T > &  container,
bool  updatePackedSheet = true,
bool  errorIfPackedSheetNotGood = true
 

This function is used to load values from georges sheet in a quick way.

Parameters:
sheetFilter a string to filter the sheet (ie: ".item")
packedFilename the name of the file that this function will generate (extension must be "packed_sheets")
container the map that will be filled by this function

Definition at line 508 of file load_form.h.

References loadForm().

00509 {
00510         std::vector<std::string> vs;
00511         vs.push_back(sheetFilter);
00512         loadForm(vs, packedFilename, container, updatePackedSheet, errorIfPackedSheetNotGood);
00513 }

template<class T>
void loadForm const std::vector< std::string > &  sheetFilters,
const std::string &  packedFilename,
std::map< NLMISC::CSheetId, T > &  container,
bool  updatePackedSheet = true,
bool  errorIfPackedSheetNotGood = true
 

This function is used to load values from georges sheet in a quick way.

Parameters:
sheetFilter a vector of string to filter the sheet in the case you need more than one filter
packedFilename the name of the file that this function will generate (extension must be "packed_sheets")
container the map that will be filled by this function

Definition at line 145 of file load_form.h.

References NLMISC::CSheetId::buildIdVector(), NLMISC::COFile::close(), NLMISC::CIFile::close(), NLGEORGES::UFormLoader::createLoader(), NLMISC::CFile::getFileModificationDate(), NLMISC::CFile::getFilename(), NLMISC::CTime::getLocalTime(), NLMISC::COFile::getPos(), NLMISC::CSheetId::init(), NLGEORGES::UFormLoader::loadForm(), NLMISC::CPath::lookup(), nlassert, nldebug, nlerror, nlinfo, NLMISC::COFile::open(), NLMISC::CIFile::open(), PACKED_SHEET_HEADER, PACKED_SHEET_VERSION, PACKED_SHEET_VERSION_COMPATIBLE, NLGEORGES::UFormLoader::releaseLoader(), res, NLMISC::COFile::seek(), NLMISC::IStream::serial(), NLMISC::CIFile::serialBuffer(), NLMISC::IStream::serialCheck(), NLMISC::IStream::serialCont(), NLMISC::IStream::serialVersion(), NLMISC::CIFile::setCacheFileOnOpen(), sint, sint32, NLMISC::TTime, uint, and uint32.

00146 {
00147         std::vector<std::string>                                                dictionnary;
00148         std::map<std::string, uint>                                             dictionnaryIndex;
00149         std::map<NLMISC::CSheetId, std::vector<uint32> >        dependencies;
00150         std::vector<uint32>                                                             dependencyDates;
00151 
00152         // check the extension (i know that file like "foo.packed_sheetsbar" will be accepted but this check is enough...)
00153         nlassert (packedFilename.find (".packed_sheets") != std::string::npos);
00154 
00155         std::string packedFilenamePath = NLMISC::CPath::lookup(NLMISC::CFile::getFilename(packedFilename), false, false);
00156         if (packedFilenamePath.empty())
00157         {
00158                 packedFilenamePath = packedFilename;
00159         }
00160 
00161         // make sure the CSheetId singleton has been properly initialised
00162         NLMISC::CSheetId::init(updatePackedSheet);
00163 
00164         // load the packed sheet if exists
00165         try
00166         {
00167                 NLMISC::CIFile ifile;
00168                 ifile.setCacheFileOnOpen(true);
00169                 if (!ifile.open (packedFilenamePath))
00170                 {
00171                         throw   NLMISC::Exception("can't open PackedSheet %s", packedFilenamePath.c_str());
00172                 }
00173                 // an exception will be launch if the file is not the good version or if the file is not found
00174 
00175                 nlinfo ("loadForm(): Loading packed file '%s'", packedFilename.c_str());
00176 
00177                 // read the header
00178                 ifile.serialCheck(PACKED_SHEET_HEADER);
00179                 ifile.serialCheck(PACKED_SHEET_VERSION);
00180                 sint    loadFormVersion= ifile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);
00181 
00182                 // Read depend block size
00183                 uint32  dependBlockSize;
00184                 ifile.serial(dependBlockSize);
00185 
00186                 // Read the dependencies only if update packed sheet
00187                 if(updatePackedSheet)
00188                 {
00189                         // read the dictionnary
00190                         {
00191                                 ifile.serialCont(dictionnary);
00192                         }
00193                         // read the dependency data
00194                         {
00195                                 uint32 depSize;
00196                                 ifile.serial(depSize);
00197                                 for (uint i=0; i<depSize; ++i)
00198                                 {
00199                                         NLMISC::CSheetId sheetId;
00200 
00201                                         // Avoid copy, use []
00202                                         ifile.serial(sheetId);
00203                                         ifile.serialCont(dependencies[sheetId]);
00204                                 }
00205                         }
00206                 }
00207                 // else dummy read one big block => no heavy reallocation / free
00208                 else if(dependBlockSize>0)
00209                 {
00210                         std::vector<uint8>      bigBlock;
00211                         bigBlock.resize(dependBlockSize);
00212                         ifile.serialBuffer(&bigBlock[0], dependBlockSize);
00213                 }
00214                                 
00215                 // read the packed sheet data
00216                 uint32  nbEntries;
00217                 uint32  ver;
00218                 ifile.serial (nbEntries);
00219                 ifile.serial (ver);
00220                 if(ver != T::getVersion ())
00221                         throw NLMISC::Exception("The packed sheet version in stream is different of the code");
00222                 ifile.serialCont (container);
00223                 ifile.close ();
00224         }
00225         catch (NLMISC::Exception &e)
00226         {
00227                 // clear the container because it can contains partially loaded sheet so we must clean it before continue
00228                 container.clear ();
00229                 if (!updatePackedSheet)
00230                 {
00231                         if (errorIfPackedSheetNotGood)
00232                                 nlerror ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what());
00233                         else
00234                                 nlinfo ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what());
00235 
00236                         return;
00237                 }
00238                 else
00239                 {
00240                         nlinfo ("loadForm(): Exception during reading the packed file, I'll reconstruct it (%s)", e.what());
00241                 }
00242         }
00243 
00244         // if we don't want to update packed sheet, we nothing more to do
00245         if (!updatePackedSheet)
00246         {
00247                 nlinfo ("Don't update the packed sheet with real sheet");
00248                 return;
00249         }
00250 
00251         // retreive the date of all dependency file
00252         {
00253                 for (uint i=0; i<dictionnary.size(); ++i)
00254                 {
00255                         std::string p = NLMISC::CPath::lookup (dictionnary[i], false, false);
00256                         if (!p.empty()) 
00257                         {
00258                                 uint32 d = NLMISC::CFile::getFileModificationDate(p);
00259                                 dependencyDates.push_back(d);
00260                         }
00261                         else
00262                         {
00263                                 // file not found !
00264                                 // write a future date to invalidate any file dependent on it
00265                                 nldebug("Can't find dependent file %s !", dictionnary[i].c_str());
00266                                 dependencyDates.push_back(0xffffffff);
00267                         }
00268                 }
00269         }
00270 
00271         // build a vector of the sheetFilters sheet ids (ie: "item")
00272         std::vector<NLMISC::CSheetId> sheetIds;
00273         std::vector<std::string> filenames;
00274         for (uint i = 0; i < sheetFilters.size(); i++)
00275                 NLMISC::CSheetId::buildIdVector(sheetIds, filenames, sheetFilters[i]);
00276 
00277         // if there s no file, nothing to do
00278         if (sheetIds.empty())
00279                 return;
00280 
00281         // set up the current sheet in container to remove sheet that are in the container and not in the directory anymore
00282         std::map<NLMISC::CSheetId, bool> sheetToRemove;
00283         for (typename std::map<NLMISC::CSheetId, T>::iterator it = container.begin(); it != container.end(); it++)
00284         {
00285                 sheetToRemove.insert (std::make_pair((*it).first, true));
00286         }
00287 
00288         // check if we need to create a new .pitems or just read it
00289         uint32 packedFiledate = NLMISC::CFile::getFileModificationDate(packedFilenamePath);
00290 
00291         bool containerChanged = false;
00292 
00293         NLGEORGES::UFormLoader *formLoader = NULL;
00294 
00295         std::vector<uint> NeededToRecompute;
00296 
00297         for (uint k = 0; k < filenames.size(); k++)
00298         {
00299                 std::string p = NLMISC::CPath::lookup (filenames[k], false, false);
00300                 if (p.empty()) continue;
00301                 uint32 d = NLMISC::CFile::getFileModificationDate(p);
00302 
00303                 // no need to remove this sheet
00304                 sheetToRemove[sheetIds[k]] = false;
00305 
00306                 if( d > packedFiledate || container.find (sheetIds[k]) == container.end())
00307                 {
00308                         NeededToRecompute.push_back(k);
00309                 }
00310                 else
00311                 {
00312                         // check the date of each parent
00313                         nlassert(dependencies.find(sheetIds[k]) != dependencies.end());
00314                         std::vector<uint32> &depends = dependencies[sheetIds[k]];
00315 
00316                         for (uint i=0; i<depends.size(); ++i)
00317                         {
00318                                 if (dependencyDates[depends[i]] > packedFiledate)
00319                                 {
00320                                         nldebug("Dependancy on %s for %s not up to date !", 
00321                                                 dictionnary[depends[i]].c_str(), sheetIds[k].toString().c_str());
00322                                         NeededToRecompute.push_back(k);
00323                                         break;
00324                                 }
00325                         }
00326                 }
00327         }
00328 
00329         nlinfo ("%d sheets checked, %d need to be recomputed", filenames.size(), NeededToRecompute.size());
00330 
00331         NLMISC::TTime last = NLMISC::CTime::getLocalTime ();
00332         NLMISC::TTime start = NLMISC::CTime::getLocalTime ();
00333 
00334         NLMISC::CSmartPtr<NLGEORGES::UForm> form;
00335         std::vector<NLMISC::CSmartPtr<NLGEORGES::UForm> >       cacheFormList;
00336         
00337         for (uint j = 0; j < NeededToRecompute.size(); j++)
00338         {
00339                 if(NLMISC::CTime::getLocalTime () > last + 5000)
00340                 {
00341                         last = NLMISC::CTime::getLocalTime ();
00342                         if(j>0)
00343                                 nlinfo ("%.0f%% completed (%d/%d), %d seconds remaining", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(last-start)/j/1000);
00344                 }
00345 
00346                 // create the georges loader if necessary
00347                 if (formLoader == NULL)
00348                 {
00349                         NLMISC::WarningLog->addNegativeFilter("CFormLoader: Can't open the form file");
00350                         formLoader = NLGEORGES::UFormLoader::createLoader ();
00351                 }
00352 
00353                 //      cache used to retain information (to optimize time).
00354                 if (form)
00355                         cacheFormList.push_back (form);
00356                 
00357                 // Load the form with given sheet id
00358                 form = formLoader->loadForm (sheetIds[NeededToRecompute[j]].toString().c_str ());
00359                 if (form)
00360                 {
00361                         // build the dependency data
00362                         {
00363                                 std::vector<uint32>             depends;
00364                                 std::set<std::string>   dependFiles;
00365                                 form->getDependencies (dependFiles);
00366                                 nlassert(dependFiles.find(sheetIds[NeededToRecompute[j]].toString()) != dependFiles.end());
00367                                 // remove the sheet itself from the container
00368                                 dependFiles.erase(sheetIds[NeededToRecompute[j]].toString());
00369 
00370                                 std::set<std::string>::iterator first(dependFiles.begin()), last(dependFiles.end());
00371                                 for (; first != last; ++first)
00372                                 {
00373                                         const   std::string filename = NLMISC::CFile::getFilename(*first);
00374                                         std::map<std::string,uint>::iterator    findDicIt=dictionnaryIndex.find(filename);
00375 
00376                                         if      (findDicIt!=dictionnaryIndex.end())
00377                                         {
00378                                                 depends.push_back(findDicIt->second);
00379                                                 continue;
00380                                         }
00381 
00382                                         std::string p = NLMISC::CPath::lookup (*first, false, false);
00383                                         if      (!p.empty())
00384                                         {
00385 //                                              uint32 date = NLMISC::CFile::getFileModificationDate(p);
00386 
00387                                                 uint dicIndex;
00388 //                                              std::string filename = NLMISC::CFile::getFilename(p);
00389 
00390 //                                              if (dictionnaryIndex.find(filename) == dictionnaryIndex.end())
00391 //                                              {
00392                                                         // add a new dictionnary entry
00393                                                         dicIndex = dictionnary.size();
00394                                                         dictionnaryIndex.insert(std::make_pair(filename, dictionnary.size()));
00395                                                         dictionnary.push_back(filename);
00396 //                                              }
00397 //                                              else
00398 //                                              {
00399 //                                                      dicIndex = dictionnaryIndex.find(filename)->second;
00400 //                                              }
00401 
00402                                                 // add the dependecy index
00403                                                 depends.push_back(dicIndex);
00404                                         }
00405                                 }
00406                                 // store the dependency list with the sheet ID
00407                                 dependencies[sheetIds[NeededToRecompute[j]]] = depends;
00408                         }
00409 
00410                         // add the new creature, it could be already loaded by the packed sheets but will be overwrite with the new one
00411                         typedef typename std::map<NLMISC::CSheetId, T>::iterator TType1;
00412             typedef typename std::pair<TType1, bool> TType2;
00413                         TType2 res = container.insert(std::make_pair(sheetIds[NeededToRecompute[j]],T()));
00414 
00415                         (*res.first).second.readGeorges (form, sheetIds[NeededToRecompute[j]]);
00416                         containerChanged = true;
00417                 }
00418         }
00419 
00420         if(NeededToRecompute.size() > 0)
00421                 nlinfo ("%d seconds to recompute %d sheets", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size());
00422 
00423         // free the georges loader if necessary
00424         if (formLoader != NULL)
00425         {
00426                 NLGEORGES::UFormLoader::releaseLoader (formLoader);
00427                 NLMISC::WarningLog->removeFilter ("CFormLoader: Can't open the form file");
00428         }
00429 
00430         // we have now to remove sheet that are in the container and not exist anymore in the sheet directories
00431         for (std::map<NLMISC::CSheetId, bool>::iterator it2 = sheetToRemove.begin(); it2 != sheetToRemove.end(); it2++)
00432         {
00433                 if((*it2).second)
00434                 {
00435                         nlinfo ("the sheet '%s' is not in the directory, remove it from container", (*it2).first.toString().c_str());
00436                         container.find((*it2).first)->second.removed();
00437                         container.erase((*it2).first);
00438                         containerChanged = true;
00439                         dependencies.erase((*it2).first);
00440                 }
00441         }
00442 
00443         // now, save the new container in the packedfile
00444         try
00445         {
00446                 if(containerChanged)
00447                 {
00448                         NLMISC::COFile ofile;
00449                         ofile.open(packedFilenamePath);
00450 
00451                         // write the header.
00452                         ofile.serialCheck(PACKED_SHEET_HEADER);
00453                         ofile.serialCheck(PACKED_SHEET_VERSION);
00454                         ofile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);
00455                         
00456                         // Write a dummy block size for now
00457                         sint32  posBlockSize= ofile.getPos();
00458                         uint32  dependBlockSize= 0;
00459                         ofile.serial(dependBlockSize);
00460                         
00461                         // write the dictionnary
00462                         ofile.serialCont(dictionnary);
00463 
00464                         // write the dependencies data
00465                         uint32 depSize = dependencies.size();
00466                         ofile.serial(depSize);
00467                         std::map<NLMISC::CSheetId, std::vector<uint32> >::iterator first(dependencies.begin()), last(dependencies.end());
00468                         for (; first != last; ++first)
00469                         {
00470                                 NLMISC::CSheetId si = first->first;
00471                                 ofile.serial(si);
00472                                 ofile.serialCont(first->second);
00473                         }
00474 
00475                         // Then get the dicionary + dependencies size, and write it back to posBlockSize
00476                         sint32  endBlockSize= ofile.getPos();
00477                         dependBlockSize= (endBlockSize - posBlockSize) - 4;
00478                         ofile.seek(posBlockSize, NLMISC::IStream::begin);
00479                         ofile.serial(dependBlockSize);
00480                         ofile.seek(endBlockSize, NLMISC::IStream::begin);
00481                         
00482                         // write the sheet data
00483                         uint32 nbEntries = sheetIds.size();
00484                         uint32 ver = T::getVersion ();
00485                         ofile.serial (nbEntries);
00486                         ofile.serial (ver);
00487                         ofile.serialCont(container);
00488                         ofile.close ();
00489                 }
00490         }
00491         catch (NLMISC::Exception &e)
00492         {
00493                 nlinfo ("loadForm(): Exception during saving the packed file, it will be recreated next launch (%s)", e.what());
00494         }
00495 
00496         // housekeeping
00497         sheetIds.clear ();
00498         filenames.clear ();
00499 }

template<class T>
void loadForm const std::string &  sheetFilter,
const std::string &  packedFilename,
std::map< NLMISC::CSheetId, T > &  container,
bool  updatePackedSheet = true,
bool  errorIfPackedSheetNotGood = true
 

This function is used to load values from georges sheet in a quick way.

Parameters:
sheetFilter a string to filter the sheet (ie: ".item")
packedFilename the name of the file that this function will generate (extension must be "packed_sheets")
container the map that will be filled by this function

Definition at line 132 of file load_form.h.

References loadForm().

00133 {
00134         std::vector<std::string> vs;
00135         vs.push_back(sheetFilter);
00136         loadForm(vs, packedFilename, container, updatePackedSheet, errorIfPackedSheetNotGood);
00137 }


Variable Documentation

const uint32 PACKED_SHEET_HEADER = 'PKSH'
 

Dictionnaley entry for dependency information.

This function is used to load values from georges sheet in a quick way. The first time it loads the sheet and parse it with the readGeorges function provided by the user to read the value he wants. It'll generate a packed file that contains this values (using serialCont). The next launch, the function will only load the packed file and if some sheet have changed, it'll automatically regenerate the packed file.

To use the loadForm(), you first have to create a class that will contains values for one sheet. This class must also implements 2 functions (readGeorges() and serial()) and 1 static functions (getVersion())

Extension file name for the packedFilename must be ".packed_sheets"

Classical use (copy/paste this in your code):

For each sheet in the packed sheet, an instance of this class is created and stored into an stl container. This class must be default and copy constructable. class CContainerEntry { public: CContainerEntry () : WalkSpeed(1.3f), RunSpeed(6.0f) {}

float WalkSpeed, RunSpeed;

load the values using the george sheet void readGeorges (const NLMISC::CSmartPtr<NLGEORGES::UForm> &form, const NLMISC::CSheetId &sheetId) { the form was found so read the true values from George form->getRootNode ().getValueByName (WalkSpeed, "Basics.MovementSpeeds.WalkSpeed"); form->getRootNode ().getValueByName (RunSpeed, "Basics.MovementSpeeds.RunSpeed"); }

load/save the values using the serial system void serial (NLMISC::IStream &s) { s.serial (WalkSpeed, RunSpeed); }

Event to implement any action when the sheet is no longeur existent. This method is call when a sheet have been read from the packed sheet and the associated sheet file no more exist in the directories. void removed() { any action that is needed if the sheet no more exist. }

return the version of this class, increments this value when the content hof this class changed static uint getVersion () { return 1; } };

this structure is fill by the loadForm() function and will contain all you need std::map<NLMISC::CSheetId,CContainerEntry> Container;

void init () { load the values using the george sheet or packed file and fill the container loadForm(".creature", "test.packed_sheets", Container); }

Now you can access the Container (using the CSheedId) to know the WalkSpeed and RunSpeed of all creatures.

Definition at line 120 of file load_form.h.

Referenced by loadForm().

const uint32 PACKED_SHEET_VERSION = 5
 

Definition at line 121 of file load_form.h.

Referenced by loadForm().

const uint32 PACKED_SHEET_VERSION_COMPATIBLE = 0
 

Definition at line 123 of file load_form.h.

Referenced by loadForm().


Generated on Tue Mar 16 06:42:53 2004 for NeL by doxygen 1.3.6