khanat-opennel-code/code/ryzom/tools/leveldesign/mission_compiler_lib/main.cpp
2016-01-18 21:31:23 +01:00

287 lines
8.6 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/>.
#include "nel/misc/i18n.h"
#include "mission_compiler.h"
#include "nel/misc/config_file.h"
using namespace std;
using namespace NLMISC;
using namespace NLLIGO;
class CMissionData;
class IStep;
int main(int argc, char *argv[])
{
NLMISC::CApplicationContext appContext;
const char *leveldesignPath = getenv("RYZOM_LEVELDESIGN");
if (leveldesignPath == NULL)
{
printf("Error: You need to define RYZOM_LEVELDESIGN environment variable that points to previous L:\\ equivalent under Windows\n");
return -1;
}
CPath::addSearchPath(NLMISC::CPath::standardizePath(leveldesignPath), true, false);
bool test = false;
if (argc == 4 && string(argv[3]) == "-test")
{
test = true;
}
else if ( argc != 3)
{
printf("%s <world_edit_class> <primitive_file> [-test]", argv[0]);
return -1;
}
string sourceDocName;
if (!test)
sourceDocName = argv[2];
else
sourceDocName = "test_compilateur.primitive";
// remove the path
sourceDocName = CFile::getFilename(sourceDocName);
// init ligo
NLLIGO::CLigoConfig LigoConfig;
CPrimitiveContext::instance().CurrentLigoConfig = &LigoConfig;
nlinfo("Reading ligo configuration file...");
if (!LigoConfig.readPrimitiveClass (argv[1], false))
{
nlwarning("Can't read '%s' !", argv[1]);
return -1;
}
NLLIGO::Register();
nlinfo("Reading primitive file...");
CPrimitives primDoc;
CPrimitiveContext::instance().CurrentPrimitive = &primDoc;
loadXmlPrimitiveFile(primDoc, sourceDocName, LigoConfig);
CMissionCompiler mc;
if (test)
{
nlinfo("Compiling test mission");
try
{
mc.compileMissions(primDoc.RootNode, sourceDocName);
TMissionDataPtr testMission = mc.getMission(0);
CSString script = testMission->generateMissionScript(sourceDocName);
script += "======================================================"+NL;
script += testMission->generatePhraseFile();
script += "======================================================"+NL;
script += testMission->generateDotScript();
script = script.replace(NL.c_str(), "\n");
const char *tmp = ::getenv("TEMP");
FILE *fp = ::fopen((string(tmp)+"/compiled_mission.script").c_str(), "w");
::fwrite(script.data(), script.size(), 1, fp);
::fclose(fp);
// TODO: set diff program in .cfg
std::string compareApp = "";
std::string command = NLMISC::toString("%s %s/compiled_mission.script test_compilateur.script", compareApp.c_str(), tmp);
sint error = system(command.c_str());
if (error)
nlwarning("'%s' failed with error code %d", "", error);
}
catch(const EParseException &e)
{
nlwarning(e.Why.c_str());
return -1;
}
return 0;
}
nlinfo("Compiling missions...");
try
{
mc.compileMissions(primDoc.RootNode, sourceDocName);
mc.installCompiledMission(LigoConfig, sourceDocName);
/* std::vector <TMissionDataPtr> &missions = mc.getMissions();
// generate the mission script into the npcs...
{
map<string, TLoadedPrimitive > loadedPrimitives;
// First loop to remove any mission that belong to the compiled primitive file
for (uint i=0; i<missions.size(); ++i)
{
CMissionData &mission = *(missions[i]);
// first, look for the primitive file to load
string fileName = mission.getGiverPrimitive();
if (fileName.empty())
{
// use mission primitive instead
fileName = sourceDocName;
}
if (loadedPrimitives.find(fileName) == loadedPrimitives.end())
{
string fullFileName = CPath::lookup(fileName);
if (fullFileName.empty())
{
nlwarning("Can't find primitive file '%s' in path", fileName.c_str());
throw EParseException(NULL, "Destination primitive file not found");
}
// we need to load this primitive file.
CPrimitives *primDoc = new CPrimitives;
if (loadXmlPrimitiveFile(*primDoc, fullFileName, LigoConfig))
{
// the primitive file is loaded correctly
loadedPrimitives.insert(make_pair(fileName, TLoadedPrimitive(primDoc, fullFileName)));
}
else
throw EParseException(NULL, "Can't read primitive file");
}
TLoadedPrimitive &loadedPrim = loadedPrimitives[fileName];
CPrimitives *primDoc = loadedPrim.PrimDoc;
TPrimitiveSet scripts;
CPrimitiveSet<TPrimitiveClassPredicate> filter;
filter.buildSet(primDoc->RootNode, TPrimitiveClassPredicate("mission"), scripts);
// for each script, check if it was generated, and if so, check the name
// of the source primitive file.
for (uint i=0; i<scripts.size(); ++i)
{
vector<string> *script;
if (scripts[i]->getPropertyByName("script", script) && !script->empty())
{
// Format should be : #compiled from <source_primitive_name>
if (script->front().find("compiled from"))
{
// we have a compiled mission
if (script->front().find(sourceDocName))
{
// ok, this mission is compiled from the same primitive, remove it
scripts[i]->getParent()->removeChild(scripts[i]);
}
}
}
}
}
// second loop to assign compiled mission to giver npc
for (uint i=0; i<missions.size(); ++i)
{
CMissionData &mission = *(missions[i]);
string fileName = mission.getGiverPrimitive();
if (fileName.empty())
{
// no giver primitive file specified in the mission, use the mission primitive instead
fileName = sourceDocName;
}
TLoadedPrimitive &loadedPrim = loadedPrimitives[fileName];
CPrimitives *primDoc = loadedPrim.PrimDoc;
TPrimitiveSet bots;
CPrimitiveSet<TPrimitiveClassAndNamePredicate> filter;
filter.buildSet(primDoc->RootNode, TPrimitiveClassAndNamePredicate("npc_bot", mission.getGiverName()), bots);
if (bots.empty())
{
nlwarning("Can't find bot '%s' in primitive '%s' !",
mission.getGiverName().c_str(),
fileName.c_str());
throw EParseException(NULL, "Can't find giver in primitive");
}
else if (bots.size() > 1)
{
nlwarning("Found more than one bot named '%s' in primitive '%s' !",
mission.getGiverName().c_str(),
fileName.c_str());
throw EParseException(NULL, "More than one bot with giver name in primitive");
}
// ok, all is good, we can add the mission node to the giver
IPrimitive *giver = bots.front();
// create a new node for the mission
IPrimitive *script = new CPrimNode;
// set the class
script->addPropertyByName("class", new CPropertyString("mission"));
// set the name
script->addPropertyByName("name", new CPropertyString(mission.getMissionName()));
// string alias(toString("%u", makeHash32(mission.getMissionName())));
script->addPropertyByName("alias", new CPropertyString(mission.getAlias()));
string scriptLines = mission.generateMissionScript();
vector<string> lines;
explode(scriptLines, NL, lines, false);
script->addPropertyByName("script", new CPropertyStringArray(lines));
// insert the script into the giver
giver->insertChild(script);
}
// Save the modified primitive files
while (!loadedPrimitives.empty())
{
TLoadedPrimitive &loadedPrim = loadedPrimitives.begin()->second;
saveXmlPrimitiveFile(*(loadedPrim.PrimDoc), loadedPrim.FullFileName);
// Free the memory
delete loadedPrim.PrimDoc;
loadedPrimitives.erase(loadedPrimitives.begin());
}
}
// generate the phrase file (in any)
{
string phraseFileName = CFile::getFilenameWithoutExtension(sourceDocName) + "_en.txt";
CSString content;
for (uint i=0; i<missions.size(); ++i)
{
content += missions[i]->generatePhraseFile();
}
// transform NL (\n\r) into single \n
content = content.replace(NL.c_str(), "\n");
ucstring ucs;
ucs.fromUtf8(content);
CI18N::writeTextFile(phraseFileName, ucs, true);
}
*/
}
catch (const EParseException &e)
{
CPrimitiveContext::instance().CurrentLigoConfig = NULL;
nlerror("Compilation error : '%s'", e.Why.c_str());
}
CPrimitiveContext::instance().CurrentLigoConfig = NULL;
return 0;
}