khanat-opennel-code/code/ryzom/server/src/general_utilities_service/merge_commands.cpp
2010-05-06 02:08:41 +02:00

264 lines
9.4 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
//-----------------------------------------------------------------------------
//nel
#include "nel/misc/command.h"
#include "nel/misc/variable.h"
// game share
#include "game_share/utils.h"
#include "game_share/file_description_container.h"
#include "game_share/singleton_registry.h"
#include "game_share/persistent_data.h"
//-----------------------------------------------------------------------------
// Namespaces
//-----------------------------------------------------------------------------
using namespace std;
//-----------------------------------------------------------------------------
// Variables
//-----------------------------------------------------------------------------
//NLMISC::CVariable<string> Bla("ShardMerge", "Bla", "Directory containing event tools", string("./events/tools/"), 0, true);
//-----------------------------------------------------------------------------
// CContestCtrlScript Commands
//-----------------------------------------------------------------------------
NLMISC_CATEGORISED_COMMAND(ShardMerge,mergeGuildIdFix,"set the guild ids in the pdr records from the values in their file names","<filespec>")
{
if (args.size()!=1)
return false;
CFileDescriptionContainer fdc;
fdc.addFileSpec(args[0]);
for (uint32 i=0;i<fdc.size();++i)
{
uint32 id= NLMISC::CSString(NLMISC::CFile::getFilenameWithoutExtension(fdc[i].FileName)).splitFrom('_').atoui();
nlinfo("Setting id for guild: %s to: %d",fdc[i].FileName.c_str(),id);
// read the file
static CPersistentDataRecord pdr;
pdr.clear();
pdr.readFromFile(fdc[i].FileName.c_str());
// convert to XML
NLMISC::CSString inputString;
pdr.toXML(inputString);
NLMISC::CSString resultString;
resultString+= inputString.splitTo("<Id type=\"UINT32\" value=\"");
resultString+= "<Id type=\"UINT32\" value=\"";
resultString+= NLMISC::toString("%u",id);
resultString+= "\"/>";
resultString+= inputString.splitFrom("<Id type=\"UINT32\" value=\"").splitFrom("\"/>");
// convert back to a pdr
pdr.clear();
pdr.fromXML(resultString);
// write the file
pdr.writeToFile((fdc[i].FileName+".new.xml").c_str());
pdr.writeToFile((fdc[i].FileName+".new.bin").c_str());
}
return true;
}
NLMISC_CATEGORISED_COMMAND(ShardMerge,mergeChangeCharacterNames,"change names of characters to thos listed in charcter_names.txt file","<save root directory>")
{
DROP_IF(args.size()!=1,"Syntax error: Requires an argument",return false);
DROP_IF(!NLMISC::CFile::fileExists(args[0]+"/character_names.txt"),"File not found: "+args[0]+"/character_names.txt",return false);
NLMISC::CSString fileContent;
fileContent.readFromFile(args[0]+"/character_names.txt");
NLMISC::CVectorSString fileLines;
fileContent.splitLines(fileLines);
for (uint32 i=0;i<fileLines.size();++i)
{
NLMISC::CSString name= fileLines[i].word(0);
uint32 account= fileLines[i].word(1).atoui();
uint32 slot= fileLines[i].word(2).atoui();
nlinfo("Setting name for character: %d_%d to: %s",account,slot,name.c_str());
// read the file
NLMISC::CSString fileName= args[0]+NLMISC::toString("/characters/account_%d_%d_pdr.bin",account,slot);
DROP_IF(!NLMISC::CFile::fileExists(fileName),"Skipping inexistant file: "+fileName,continue);
static CPersistentDataRecord pdr;
pdr.clear();
pdr.readFromFile(fileName.c_str());
// convert to XML
NLMISC::CSString inputString;
pdr.toXML(inputString);
NLMISC::CSString resultString;
resultString+= inputString.splitTo("<_Name type=\"STRING\" value=\"");
resultString+= "<_Name type=\"STRING\" value=\"";
resultString+= name;
resultString+= "\"/>";
resultString+= inputString.splitFrom("<_Name type=\"STRING\" value=\"").splitFrom("\"/>");
// convert back to a pdr
pdr.clear();
pdr.fromXML(resultString);
// write the file
pdr.writeToFile((fileName+".new.xml").c_str());
pdr.writeToFile((fileName+".new.bin").c_str());
}
return true;
}
NLMISC_CATEGORISED_COMMAND(ShardMerge,mergeBuildCharacterNamesFromCSV,"build a character names file from a CSV file containing columns: account, accountSlot, name","<csv file><character names file>")
{
if (args.size()!=2)
return false;
// read the CSV file
NLMISC::CSString input;
input.readFromFile(args[0].c_str());
// convert CSV input into lines
NLMISC::CVectorSString lines;
input.splitLines(lines);
DROP_IF(lines.empty(),"Failed to extract meaningful data from input file: "+args[0],return false);
// split the first line into column titles
NLMISC::CVectorSString columns;
lines[0].splitByOneOfSeparators(",;",columns);
// run through the column titles and identify the columns that interest us
uint32 accountIdx=~0u;
uint32 accountSlotIdx=~0u;
uint32 nameIdx=~0u;
for (uint32 i=0;i<columns.size();++i)
{
if (columns[i]=="account") accountIdx= i;
if (columns[i]=="accountSlot") accountSlotIdx= i;
if (columns[i]=="name") nameIdx= i;
}
DROP_IF(accountIdx==~0u||accountSlotIdx==~0u||nameIdx==~0u,"Failed to identify columns (account,accountSlot,name) in input file: "+args[0],return false);
// compose the output data by running through the lines of the input data extracting the required columns
NLMISC::CSString result;
for (uint32 i=1;i<lines.size();++i)
{
NLMISC::CVectorSString fields;
lines[i].splitByOneOfSeparators(",;",fields);
BOMB_IF(fields.size()<std::max(nameIdx,std::max(accountIdx,accountSlotIdx)),
"Skipping line from input file '"+args[0]+"' due to insufficient fields: "+lines[i],continue);
result+=fields[nameIdx]+" "+fields[accountIdx]+" "+fields[accountSlotIdx]+"\n";
}
// write the output file
BOMB_IF(result.empty(),"Failed to extract any usable data from input file: "+args[0],return false);
result.writeToFile(args[1]);
return true;
}
NLMISC_CATEGORISED_COMMAND(ShardMerge,mergeIdentifyOverlappingCharacters,"identify overlapping characters from a set of character_name.txt type files","<first file>[<second file>[...]]")
{
if (args.size()<1)
return false;
// setup maps of all account ids and character names accross all input files
std::map<NLMISC::CSString,NLMISC::CSString> accounts; // <account_name,input_file+":"+character name>
std::map<NLMISC::CSString,NLMISC::CSString> names; // <character name,input_file+":"+account_name>
// for each input file: ...
for (uint32 i=0;i<args.size();++i)
{
// read the input file
NLMISC::CSString input;
input.readFromFile(args[i].c_str());
DROP_IF(input.empty(),"Failed to read input file: "+args[i],return false);
// convert to lines
NLMISC::CVectorSString lines;
input.splitLines(lines);
// for each line...
for (uint32 j=0;j<lines.size();++j)
{
// extract interesting info from the line
DROP_IF(lines[j].countWords()!=3,"Invalid line in file '"+args[i]+"': "+lines[j],return false);
const NLMISC::CSString name= lines[i].word(0);
const NLMISC::CSString account= lines[j].word(1)+"_"+lines[j].word(2);
// add entry to accounts map
if (accounts.find(account)==accounts.end())
accounts[account]=args[i]+":"+name;
else
accounts[account]+=","+args[i]+":"+name;
// add entry to character_names map
if (names.find(name)==names.end())
names[name]=args[i]+":"+account;
else
names[name]+=","+args[i]+":"+account;
}
}
// setup a string to record duplicate names into
NLMISC::CSString output;
// run through the accounts map looking for duplicate entries
for (std::map<NLMISC::CSString,NLMISC::CSString>::iterator it= accounts.begin();it!=accounts.end();++it)
{
if ((*it).second.contains(','))
{
output+="Account "+(*it).first+":"+(*it).second+"\n";
nlinfo("Duplicate account: %s @ %s",(*it).first.c_str(),(*it).second.c_str());
}
}
// run through the names map looking for duplicate entries
for (std::map<NLMISC::CSString,NLMISC::CSString>::iterator it= names.begin();it!=names.end();++it)
{
if ((*it).second.contains(','))
{
output+="Name "+(*it).first+":"+(*it).second+"\n";
nlinfo("Duplicate character name: %s @ %s",(*it).first.c_str(),(*it).second.c_str());
}
}
// if no duplicates were found then drop out
DROP_IF(output.empty(),"No duplicates found!",return true);
// dump the output to disk
NLMISC::CSString outputFileName= args[0]+".err";
nlinfo("Writintg duplicate list to output file: %s",outputFileName.c_str());
output.writeToFile(outputFileName);
return true;
}
//-----------------------------------------------------------------------------