// Ryzom - MMORPG Framework // 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 . //----------------------------------------------------------------------------- // includes //----------------------------------------------------------------------------- #include "stdpch.h" #include "utils.h" #include "nel/misc/file.h" #include "nel/misc/command.h" //#include "game_share/utils.h" #include "scenario_entry_points.h" #include "nel/misc/o_xml.h" #include "nel/misc/i_xml.h" //----------------------------------------------------------------------------- // namespaces //----------------------------------------------------------------------------- using namespace NLMISC; //----------------------------------------------------------------------------- // R2 namespace //----------------------------------------------------------------------------- namespace R2 { CScenarioEntryPoints *CScenarioEntryPoints::_Instance = NULL; CScenarioEntryPoints::CScenarioEntryPoints() { _IsLoaded= false; _CompleteIslandsLoaded = false; _LastTestedCoords.set(FLT_MAX, FLT_MAX); _LastFoundIsland = NULL; init(); } //----------------------------------------------------------------------------- void CScenarioEntryPoints::init() { _CompleteIslandsFilename = "r2_islands.xml"; _EntryPointsFilename = "r2_entry_points.txt"; } //----------------------------------------------------------------------------- CScenarioEntryPoints &CScenarioEntryPoints::getInstance() { // allocate our singleton if need be if(!_Instance) { _Instance = new CScenarioEntryPoints(); } // return ref to our singleton return *_Instance; } //----------------------------------------------------------------------------- void CScenarioEntryPoints::releaseInstance() { if( _Instance ) delete _Instance; _Instance = NULL; } //----------------------------------------------------------------------------- const CScenarioEntryPoints::TEntryPoints& CScenarioEntryPoints::getEntryPoints() { // if need be load the entry points vector from disk file if(!_IsLoaded) { loadFromFile(); } // return the entry points vector return _EntryPoints; } //----------------------------------------------------------------------------- // TEMP uint32 CScenarioEntryPoints::getIslandId(const CSString& island) { // if need be load the entry points vector from disk file loadCompleteIslands(); uint32 count=0; for (uint32 i=0;i<_CompleteIslands.size();++i) { // if this entry point corresponds to the one we're looking for then stop here if (island==_CompleteIslands[i].Island) return count; // increment the entry point id each time we get here (ie for each entry point in package definition) ++count; } return count; } //----------------------------------------------------------------------------- CScenarioEntryPoints::CCompleteIsland * CScenarioEntryPoints::getIslandFromId(const NLMISC::CSString& islandId) { // if need be load the entry points vector from disk file loadCompleteIslands(); for (uint32 i=0;i<_CompleteIslands.size();++i) { // if this entry point corresponds to the one we're looking for then stop here if (islandId==_CompleteIslands[i].Island) return &_CompleteIslands[i]; } return NULL; } //----------------------------------------------------------------------------- CScenarioEntryPoints::CShortEntryPoint * CScenarioEntryPoints::getEntryPointFromIds(const NLMISC::CSString& islandId, const NLMISC::CSString& entryPointId) { // if need be load the entry points vector from disk file loadCompleteIslands(); for (uint32 i=0;i<_CompleteIslands.size();++i) { // if this entry point corresponds to the one we're looking for then stop here if (islandId==_CompleteIslands[i].Island) { for (uint32 e=0;e<_CompleteIslands[i].EntryPoints.size();++e) { if (entryPointId==_CompleteIslands[i].EntryPoints[e].Location) { return &_CompleteIslands[i].EntryPoints[e]; } } } } return NULL; } //----------------------------------------------------------------------------- void CScenarioEntryPoints::loadFromFile() { // clear out the entry point vector before we begin _EntryPoints.clear(); // setup the file name std::string pathFileName = CPath::lookup(_EntryPointsFilename.c_str()); // open our input file CIFile inf; inf.open(pathFileName); // read the file contents into a string 's' CSString s; s.resize(inf.getFileSize()); inf.serialBuffer((uint8*)&s[0],(uint)s.size()); // close the file inf.close(); // split the string into lines CVectorSString lines; s.splitLines(lines); // run through the lines looking for stuff that's valid for (uint32 i=0;i 20.f || fabs((double) pos.y - _LastTestedCoords.y) > 20.f) { _LastTestedCoords = pos; for(uint k = 0; k < _CompleteIslands.size(); ++k) { if (pos.x >= (float) _CompleteIslands[k].XMin && pos.x <= (float) _CompleteIslands[k].XMax && pos.y >= (float) _CompleteIslands[k].YMin && pos.y <= (float) _CompleteIslands[k].YMax) { _LastFoundIsland = &_CompleteIslands[k]; return _LastFoundIsland; } } _LastFoundIsland = NULL; return _LastFoundIsland; } else { // coords similar to previous test, reuse result return _LastFoundIsland; } } // FIXME : ugly duplicate from the client src ... put this in a lib static bool getZonePosFromZoneName(const std::string &name, sint &x, sint &y) { if (name.empty()) { nlwarning ("getPosFromZoneName(): empty name, can't getPosFromZoneName"); return false; } static std::string zoneName; static std::string xStr, yStr; xStr.clear(); yStr.clear(); zoneName = NLMISC::CFile::getFilenameWithoutExtension(name); uint32 i = 0; while (zoneName[i] != '_') { if (!::isdigit(zoneName[i])) return false; yStr += zoneName[i]; ++i; if (i == zoneName.size()) return false; } ++i; while (i < zoneName.size()) { if (!::isalpha(zoneName[i])) return false; xStr += (char) ::toupper(zoneName[i]); ++i; } if (xStr.size() != 2) return false; x = (xStr[0] - 'A') * 26 + (xStr[1] - 'A'); fromString(yStr, y); y = -y; return true; } //----------------------------------------------------------------------------- void CScenarioEntryPoints::loadFromXMLFile() { loadFromFile(); // clear out the entry point vector before we begin _CompleteIslands.clear(); // File stream CIFile file; // setup the file name std::string pathFileName = CPath::lookup(_CompleteIslandsFilename.c_str()); // Open the file if (!file.open(pathFileName.c_str())) { nlinfo("Can't open the file for reading : %s", pathFileName.c_str()); } // Create the XML stream CIXml input; // Init if(input.init(file)) { xmlNodePtr islands = input.getRootNode(); xmlNodePtr islandNode = input.getFirstChildNode(islands, "complete_island"); while (islandNode != 0) { CCompleteIsland completeIsland; // island name const char *island = (const char*) xmlGetProp(islandNode, (xmlChar*) "island"); if(island == 0) { nlinfo("no 'island' tag in %s", _CompleteIslandsFilename.c_str()); continue; } else completeIsland.Island = CSString(island); // package /* const char *package = (const char*) xmlGetProp(islandNode, (xmlChar*) "package"); if(package == 0) nlinfo("no 'package' tag in %s island", island); else completeIsland.Package = CSString(package); */ // continent const char *continent = (const char*) xmlGetProp(islandNode, (xmlChar*) "continent"); if(continent == 0) nlinfo("no 'continent' tag in %s island", island); else completeIsland.Continent = CSString(continent); // xmin const char *xmin = (const char*) xmlGetProp(islandNode, (xmlChar*) "xmin"); if(xmin == 0) nlinfo("no 'xmin' tag in %s island", island); else fromString(xmin, completeIsland.XMin); // ymin const char *ymin = (const char*) xmlGetProp(islandNode, (xmlChar*) "ymin"); if(ymin == 0) nlinfo("no 'ymin' tag in %s island", island); else fromString(ymin, completeIsland.YMin); // xmax const char *xmax = (const char*) xmlGetProp(islandNode, (xmlChar*) "xmax"); if(xmax == 0) nlinfo("no 'xmax' tag in %s island", island); else fromString(xmax, completeIsland.XMax); // ymax const char *ymax = (const char*) xmlGetProp(islandNode, (xmlChar*) "ymax"); if(ymax == 0) nlinfo("no 'ymax' tag in %s island", island); else fromString(ymax, completeIsland.YMax); //entry points and package TShortEntryPoints entryPoints; std::string package; for(uint e=0; e<_EntryPoints.size(); e++) { const CEntryPoint & entryPoint = _EntryPoints[e]; CShortEntryPoint shortEntryPoint; if(entryPoint.Island == island) { shortEntryPoint.Location = entryPoint.Location; shortEntryPoint.X = entryPoint.X; shortEntryPoint.Y = entryPoint.Y; entryPoints.push_back(shortEntryPoint); if(package=="") package=entryPoint.Package; else if(package!=entryPoint.Package) nlinfo("Different packages for island '%s' in file %s", island, _EntryPointsFilename.c_str()); } } if(package.empty()) nlinfo("no 'package' tag in %s island", island); else completeIsland.Package = CSString(package); // zones xmlNodePtr zoneNode = input.getFirstChildNode(islandNode, "zone"); while(zoneNode != 0) { // island name const char *zoneName = (const char*) xmlGetProp(zoneNode, (xmlChar*) "name"); if(zoneName == 0) { nlinfo("no 'zone name' tag in %s", _CompleteIslandsFilename.c_str()); } else completeIsland.Zones.push_back(std::string(zoneName)); zoneNode = input.getNextChildNode(zoneNode, "zone"); } // compute zones ids from zone names for(std::list::iterator it = completeIsland.Zones.begin(); it != completeIsland.Zones.end(); ++it) { sint x, y; if (getZonePosFromZoneName(*it, x, y)) { completeIsland.ZoneIDs.push_back(((uint16) x&255)+((uint16) (-y - 1)<<8)); } } if(entryPoints.size()>0) { completeIsland.EntryPoints = entryPoints; _CompleteIslands.push_back(completeIsland); } islandNode = input.getNextChildNode(islandNode, "complete_island"); } } // Close the file file.close (); _CompleteIslandsLoaded = true; } //----------------------------------------------------------------------------- void CScenarioEntryPoints::loadCompleteIslands() { if(!_CompleteIslandsLoaded) { loadFromXMLFile(); } } //----------------------------------------------------------------------------- const CScenarioEntryPoints::TCompleteIslands & CScenarioEntryPoints::getCompleteIslands() { loadCompleteIslands(); // return the islands vector return _CompleteIslands; } //----------------------------------------------------------------------------- void CScenarioEntryPoints::saveXMLFile(const TCompleteIslands & completeIslands, const std::string & fileName) { // File stream COFile file; // setup the file name std::string pathFilename = CPath::lookup(fileName.c_str()); // Open the file if (!file.open(pathFilename.c_str())) { nlinfo("Can't open the file for writing : %s", fileName.c_str()); return; } // Create the XML stream COXml output; // Init if(output.init(&file, "1.0")) { xmlDocPtr xmlDoc = output.getDocument(); // Create the first node xmlNodePtr root = xmlNewDocNode(xmlDoc, NULL, (const xmlChar*)"islands", NULL); xmlDocSetRootElement(xmlDoc, root); std::map< std::string, xmlNodePtr > islandNodes; for (uint32 i=0;i::const_iterator itZone; for(itZone=completeIslands[i].Zones.begin(); itZone!=completeIslands[i].Zones.end(); itZone++) { xmlNodePtr zoneNode = xmlNewChild(islandNode, NULL, (const xmlChar*)"zone", NULL); xmlSetProp(zoneNode, (const xmlChar*)"name", (const xmlChar*)(*itZone).c_str()); } islandNodes[completeIslands[i].Island] = islandNode; } } // Flush the stream, write all the output file output.flush(); } // Close the file file.close(); } /* //----------------------------------------------------------------------------- void CScenarioEntryPoints::getIslands(const CSString& packageDefinition, CVectorSString& islands) { // if need be load the entry points vector from disk file if (!_IsLoaded) { loadFromFile(); } islands.clear(); std::set found; for (uint32 i=0;i<_EntryPoints.size();++i) { CSString& island= _EntryPoints[i].Island; // skip entry points from inaccessible packages if (!packageDefinition.contains(_EntryPoints[i].Package.c_str())) continue; // skip dumplicate names if (found.find(island)!=found.end()) continue; // add the island to the output vector and set of found islands islands.push_back(island); found.insert(island); } } //----------------------------------------------------------------------------- void CScenarioEntryPoints::getEntryPoints(const CSString& packageDefinition, const CSString& island, CVectorSString& entryPoints) { // if need be load the entry points vector from disk file if (!_IsLoaded) { loadFromFile(); } entryPoints.clear(); for (uint32 i=0;i<_EntryPoints.size();++i) { CSString& entryPoint= _EntryPoints[i].Location; // skip entry points from inaccessible packages if (!packageDefinition.contains(_EntryPoints[i].Package.c_str())) continue; // skip entry points from the wrong island if (island!=_EntryPoints[i].Island) continue; // add the island to the output vector and set of found islands entryPoints.push_back(entryPoint); } } //----------------------------------------------------------------------------- uint32 CScenarioEntryPoints::getEntryPointId(const CSString& packageDefinition, const CSString& island, const CSString& entryPoint) { // if need be load the entry points vector from disk file if (!_IsLoaded) { loadFromFile(); } uint32 count=0; for (uint32 i=0;i<_EntryPoints.size();++i) { // skip entry points from inaccessible packages if (!packageDefinition.contains(_EntryPoints[i].Package.c_str())) continue; // if this entry point corresponds to the one we're looking for then stop here if (island==_EntryPoints[i].Island && entryPoint==_EntryPoints[i].Location) return count; // increment the entry point id each time we get here (ie for each entry point in package definition) ++count; } // bomb out - we didn't find a match - on live shards this case is to be ignored as it only means we have a data // error and not necessarily a code bug... in debug we might as well STOP to flag that there's a problem STOP("ERROR: entry point '"+island+":"+entryPoint+"' not found in package description: "+packageDefinition); return count; } //----------------------------------------------------------------------------- void CScenarioEntryPoints::getEntryPointCoordsFromId(const CSString& packageDefinition, uint32 id, sint32& x, sint32& y) { // if need be load the entry points vector from disk file if (!_IsLoaded) { loadFromFile(); } uint32 count=0; for (uint32 i=0;i<_EntryPoints.size();++i) { // skip entry points from inaccessible packages if (!packageDefinition.contains(_EntryPoints[i].Package.c_str())) continue; // if this entry point corresponds to the one we're looking for then stop here if (count==id) { x= _EntryPoints[i].X; y= _EntryPoints[i].Y; return; } // increment the entry point id each time we get here (ie for each entry point in package definition) ++count; } // bomb out - we didn't find a match - on live shards this case is to be ignored as it only means we have a data // error and not necessarily a code bug... in debug we might as well STOP to flag that there's a problem STOP("ERROR: entry point '"+NLMISC::toString(id)+"' not found in package description: "+packageDefinition); x= y= 0; return; } */ } // namespace R2 /* NLMISC_COMMAND(displayScenarioEntryPoints,"display the list of scenario entry points (either the complete list or the list for a given input string","[]") { // check that we have a valid number of arguments if (args.size()>1) return false; // setup the package definition string CSString packageDefinition; if (!args.empty()) { packageDefinition= args[0]; } // display a fancy title line nlinfo("Displaying scenario entry points correspoding to package definition: '%s'",packageDefinition.c_str()); // get the vector of islands that we are allowed access to CVectorSString islands; R2::CScenarioEntryPoints::getInstance().getIslands(packageDefinition,islands); // run through the islands displaying them with their lists of entry points for (uint32 i=0;i