khanat-opennel-code/code/ryzom/tools/stats_scan/character_scan_job.cpp
2010-05-08 15:37:08 +02:00

283 lines
8 KiB
C++

// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//-------------------------------------------------------------------------------------------------
// includes
//-------------------------------------------------------------------------------------------------
#include "nel/misc/variable.h"
#include "nel/misc/path.h"
#include "game_share/persistent_data.h"
#include "character_scan_job.h"
#include "character.h"
//-------------------------------------------------------------------------------------------------
// Variables
//-------------------------------------------------------------------------------------------------
extern NLMISC::CVariable<std::string> OutputDirectory;
//-------------------------------------------------------------------------------------------------
// methods CCharacterScanJob
//-------------------------------------------------------------------------------------------------
CCharacterScanJob::CCharacterScanJob()
{
// start by initialising simple properties
_CharTblFile=NULL;
_NextFile=0;
_State=INIT;
// setup the special reserved table columns 'account' and 'accountSlot'
charTblAddCol("account");
charTblAddCol("accountSlot");
// open the output file for the character table
std::string filename= "char_tbl.csv";
_CharTblFile=fopen(filename.c_str(),"wb");
if (_CharTblFile==NULL)
{
nlwarning("Failed to open output file: %s",filename.c_str());
_State=ERROR;
}
}
CCharacterScanJob::~CCharacterScanJob()
{
if (_State!=ERROR)
_State=CLOSED;
if (_CharTblFile!=NULL)
fclose(_CharTblFile);
// flush the stats maps to their respective output files
for (TCharStatsMap::iterator it=_CharStatsMap.begin();it!=_CharStatsMap.end();++it)
{
// create the output file name and open the file for writing
std::string filename="char_stats_"+(*it).first+".csv";
FILE* f=fopen(filename.c_str(),"wb");
if (f==NULL)
{
nlwarning("Failed to open output file: %s",filename.c_str());
continue;
}
// dump data to the file
for (TCharStatsMapTbl::iterator it2=it->second.begin();it2!=it->second.end();++it2)
{
fprintf(f,"%s,%d,\n",it2->first.c_str(),it2->second);
}
// the writing is finished so close the file
fclose(f);
}
}
void CCharacterScanJob::update()
{
if (_NextFile>=_Files.size())
return;
// load the file into a pdr record
static CPersistentDataRecord pdr;
pdr.clear();
pdr.readFromFile(_Files[_NextFile].c_str());
++_NextFile;
// create a character representation and apply the pdr
CStatsScanCharacter c;
c.apply(pdr);
// iterate over the info extractors executing their core code
for (uint32 i=0;i<_InfoExtractors.size();++i)
{
_InfoExtractors[i]->execute(this,&c);
}
// flush the info collected by the info extractors to the output file
charTblFlushRow(123,456);
}
bool CCharacterScanJob::charTblAddCol(const std::string& name)
{
nlassert(_State==INIT);
// make sure the col doesn't already exist in the table
for (uint32 i=0;i<_TblCols.size();++i)
{
nlassert(_TblCols[i]!=name);
}
// add the colt ot he table
_TblCols.push_back(name);
return true;
}
bool CCharacterScanJob::addInfoExtractor(ICharInfoExtractor* infoExtractor)
{
// make sure this info extractor doesn't already exist
for (uint32 i=0;i<_InfoExtractors.size();++i)
{
if(_InfoExtractors[i]->toString()== infoExtractor->toString())
{
nlwarning("Attempt to add info extractor to the same job more than once: %s",infoExtractor->toString().c_str());
return false;
}
}
// append the new info extractor to the buffer
_InfoExtractors.push_back(infoExtractor);
return true;
}
bool CCharacterScanJob::addFilter(ICharFilter* filter)
{
// make sure this info extractor doesn't already exist
for (uint32 i=0;i<_Filters.size();++i)
{
if(_Filters[i]->toString()== filter->toString())
{
nlwarning("Attempt to add filter to the same job more than once: %s",filter->toString().c_str());
return false;
}
}
// append the new info extractor to the buffer
_Filters.push_back(filter);
return true;
}
bool CCharacterScanJob::addFiles(const CFileDescriptionContainer& fdc)
{
for (uint32 i=0;i<fdc.size();++i)
{
// generate a normalised a full file name with expanded path
std::string fullFileName= NLMISC::CPath::getFullPath(NLMISC::CFile::getPath(fdc[i].FileName))+NLMISC::CFile::getFilename(fdc[i].FileName);
// make sure the full file name doesn't already exist in the _Files vector
uint32 j;
for (j=0;j<_Files.size();++j)
{
if (fullFileName==_Files[j])
break;
}
if (j<_Files.size())
continue;
// add the full file name to the _Files vector
_Files.push_back(fullFileName);
}
return true;
}
bool CCharacterScanJob::setOutputPath(const std::string& path)
{
nlinfo("Setting output path to: %s",path.c_str());
_OutputPath= NLMISC::CPath::getFullPath(OutputDirectory)+path;
bool result= NLMISC::CFile::createDirectoryTree(_OutputPath);
if (result==false)
{
nlwarning("Failed to create directory tree: %s",path.c_str());
return false;
}
return true;
}
void CCharacterScanJob::charTblFlushRow(uint32 account,uint32 slot)
{
// setup the stuff for the ne
charTblSetEntry("account",NLMISC::toString(account));
charTblSetEntry("accountSlot",NLMISC::toString(slot));
nlassert(_State==WORK);
// build the row text from the _CurrentRowEntries entries and erase the entries as we go
std::string rowTxt;
for (uint32 i=0;i<_TblCols.size();++i)
{
if (!rowTxt.empty())
rowTxt+=',';
rowTxt+=_CurrentRowEntries[_TblCols[i]];
_CurrentRowEntries.erase(_TblCols[i]);
}
// get rid of any excess entries (spew warnings to compain about the problem)
while (!_CurrentRowEntries.empty())
{
nlwarning("Character Tbl entry found for unknown column: %s: %s",(*_CurrentRowEntries.begin()).first.c_str(),(*_CurrentRowEntries.begin()).second.c_str());
_CurrentRowEntries.erase(_CurrentRowEntries.begin());
}
// add the row text to the output file
fprintf(_CharTblFile,"%s\n",rowTxt.c_str());
fflush(_CharTblFile);
}
void CCharacterScanJob::charTblSetEntry(const std::string& colName,const std::string& value)
{
nlassert(_State==WORK);
// ensure we don't already have a value for this col
nlassert(_CurrentRowEntries.find(colName)==_CurrentRowEntries.end());
// det the value for the col
_CurrentRowEntries[colName]= value;
}
void CCharacterScanJob::freqTblAddEntry(const std::string& tblName, const std::string& key)
{
nlassert(_State==WORK);
// if the key doesn't exist in the given freq tbl then init the value to 1 else increment
if(_CharStatsMap[tblName].find(key)==_CharStatsMap[tblName].end())
_CharStatsMap[tblName][key]=1;
else
++_CharStatsMap[tblName][key];
}
bool CCharacterScanJob::finished()
{
return _NextFile>= _Files.size();
}
std::string CCharacterScanJob::getShortStatus()
{
return NLMISC::toString("CharacterFiles %d/%d",_NextFile,_Files.size());
}
std::string CCharacterScanJob::getStatus()
{
return getShortStatus();
}
void CCharacterScanJob::display(NLMISC::CLog* log)
{
log->displayNL("%s",getStatus().c_str());
for (uint32 i=0;i<_InfoExtractors.size();++i)
{
log->displayNL("- %s",_InfoExtractors[i]->toString().c_str());
}
}