/* * Copyright (C) 2005-2008 MaNGOS * * Copyright (C) 2008 Trinity * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "VMapManager.h" #include "VMapDefinitions.h" using namespace G3D; namespace VMAP { //========================================================= VMapManager::VMapManager() { #ifdef _VMAP_LOG_DEBUG iCommandLogger.setFileName("vmapcmd.log"); iCommandLogger.setResetFile(); #endif } //========================================================= VMapManager::~VMapManager(void) { Array keyArray = iInstanceMapTrees.getKeys(); for(int i=0;i0) { char lc = str[str.length()-1]; if(lc == '\r' || lc == '\n') { str = str.substr(0,str.length()-1); } else { break; } } } //========================================================= void chompAndTrim(std::string& str) { while(str.length() >0) { char lc = str[str.length()-1]; if(lc == '\r' || lc == '\n' || lc == ' ' || lc == '"' || lc == '\'') { str = str.substr(0,str.length()-1); } else { break; } } while(str.length() >0) { char lc = str[0]; if(lc == ' ' || lc == '"' || lc == '\'') { str = str.substr(1,str.length()-1); } else { break; } } } //========================================================= // result false, if no more id are found bool getNextMapId(const std::string& pString, unsigned int& pStartPos, unsigned int& pId) { bool result = false; unsigned int i; for(i=pStartPos;ipStartPos) { std::string idString = pString.substr(pStartPos, i-pStartPos); pStartPos = i+1; chompAndTrim(idString); pId = atoi(idString.c_str()); result = true; } return(result); } //========================================================= /** Block maps from being used. parameter: String of map ids. Delimiter = "," e.g.: "0,1,590" */ void VMapManager::preventMapsFromBeingUsed(const char* pMapIdString) { if(pMapIdString != NULL) { unsigned int pos =0; unsigned int id; std::string confString(pMapIdString); chompAndTrim(confString); while(getNextMapId(confString, pos, id)) { iIgnoreMapIds.set(id, true); } } } //========================================================= int VMapManager::loadMap(const char* pBasePath, unsigned int pMapId, int x, int y) { int result = VMAP_LOAD_RESULT_IGNORED; if(isMapLoadingEnabled() && !iIgnoreMapIds.containsKey(pMapId)) { bool loaded = _loadMap(pBasePath, pMapId, x, y, false); if(!loaded) { // if we can't load the map it might be splitted into tiles. Try that one and store the result loaded = _loadMap(pBasePath, pMapId, x, y, true); if(loaded) { iMapsSplitIntoTiles.set(pMapId, true); } } if(loaded) { result = VMAP_LOAD_RESULT_OK; // just for debugging #ifdef _VMAP_LOG_DEBUG Command c = Command(); c.fillLoadTileCmd(x, y, pMapId); iCommandLogger.appendCmd(c); #endif } else { result = VMAP_LOAD_RESULT_ERROR; } } return result; } //========================================================= // load one tile (internal use only) bool VMapManager::_loadMap(const char* pBasePath, unsigned int pMapId, int x, int y, bool pForceTileLoad) { bool result = false; std::string dirFileName; if(pForceTileLoad || iMapsSplitIntoTiles.containsKey(pMapId)) { dirFileName = getDirFileName(pMapId,x,y); } else { dirFileName = getDirFileName(pMapId); } MapTree* instanceTree; if(!iInstanceMapTrees.containsKey(pMapId)) { instanceTree = new MapTree(pBasePath); iInstanceMapTrees.set(pMapId, instanceTree); } else instanceTree = iInstanceMapTrees.get(pMapId); unsigned int mapTileIdent = MAP_TILE_IDENT(x,y); result = instanceTree->loadMap(dirFileName, mapTileIdent); if(!result) // remove on fail { if(instanceTree->size() == 0) { iInstanceMapTrees.remove(pMapId); delete instanceTree; } } return(result); } //========================================================= bool VMapManager::_existsMap(const std::string& pBasePath, unsigned int pMapId, int x, int y, bool pForceTileLoad) { bool result = false; std::string dirFileName; if(pForceTileLoad || iMapsSplitIntoTiles.containsKey(pMapId)) { dirFileName = getDirFileName(pMapId,x,y); } else { dirFileName = getDirFileName(pMapId); } size_t len = pBasePath.length() + dirFileName.length(); char *filenameBuffer = new char[len+1]; sprintf(filenameBuffer, "%s%s", pBasePath.c_str(), dirFileName.c_str()); FILE* df = fopen(filenameBuffer, "rb"); if(df) { char lineBuffer[FILENAMEBUFFER_SIZE]; if (fgets(lineBuffer, FILENAMEBUFFER_SIZE-1, df) != 0) { std::string name = std::string(lineBuffer); chomp(name); if(name.length() >1) { sprintf(filenameBuffer, "%s%s", pBasePath.c_str(), name.c_str()); FILE* df2 = fopen(filenameBuffer, "rb"); if(df2) { char magic[8]; fread(magic,1,8,df2); if(!strncmp(VMAP_MAGIC,magic,8)) result = true; fclose(df2); } } } fclose(df); } delete[] filenameBuffer; return result; } //========================================================= bool VMapManager::existsMap(const char* pBasePath, unsigned int pMapId, int x, int y) { std::string basePath = std::string(pBasePath); if(basePath.length() > 0 && (basePath[basePath.length()-1] != '/' || basePath[basePath.length()-1] != '\\')) { basePath.append("/"); } bool found = _existsMap(basePath, pMapId, x, y, false); if(!found) { // if we can't load the map it might be splitted into tiles. Try that one and store the result found = _existsMap(basePath, pMapId, x, y, true); if(found) { iMapsSplitIntoTiles.set(pMapId, true); } } return found; } //========================================================= void VMapManager::unloadMap(unsigned int pMapId, int x, int y) { _unloadMap(pMapId, x, y); #ifdef _VMAP_LOG_DEBUG Command c = Command(); c.fillUnloadTileCmd(pMapId, x,y); iCommandLogger.appendCmd(c); #endif } //========================================================= void VMapManager::_unloadMap(unsigned int pMapId, int x, int y) { if(iInstanceMapTrees.containsKey(pMapId)) { MapTree* instanceTree = iInstanceMapTrees.get(pMapId); std::string dirFileName; if(iMapsSplitIntoTiles.containsKey(pMapId)) { dirFileName = getDirFileName(pMapId,x,y); } else { dirFileName = getDirFileName(pMapId); } unsigned int mapTileIdent = MAP_TILE_IDENT(x,y); instanceTree->unloadMap(dirFileName, mapTileIdent); if(instanceTree->size() == 0) { iInstanceMapTrees.remove(pMapId); delete instanceTree; } } } //========================================================= void VMapManager::unloadMap(unsigned int pMapId) { if(iInstanceMapTrees.containsKey(pMapId)) { MapTree* instanceTree = iInstanceMapTrees.get(pMapId); std::string dirFileName = getDirFileName(pMapId); instanceTree->unloadMap(dirFileName, 0, true); if(instanceTree->size() == 0) { iInstanceMapTrees.remove(pMapId); delete instanceTree; } #ifdef _VMAP_LOG_DEBUG Command c = Command(); c.fillUnloadTileCmd(pMapId); iCommandLogger.appendCmd(c); #endif } } //========================================================== bool VMapManager::isInLineOfSight(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2) { bool result = true; if(isLineOfSightCalcEnabled() && iInstanceMapTrees.containsKey(pMapId)) { Vector3 pos1 = convertPositionToInternalRep(x1,y1,z1); Vector3 pos2 = convertPositionToInternalRep(x2,y2,z2); if(pos1 != pos2) { MapTree* mapTree = iInstanceMapTrees.get(pMapId); result = mapTree->isInLineOfSight(pos1, pos2); #ifdef _VMAP_LOG_DEBUG Command c = Command(); // save the orig vectors c.fillTestVisCmd(pMapId,Vector3(x1,y1,z1),Vector3(x2,y2,z2),result); iCommandLogger.appendCmd(c); #endif } } return(result); } //========================================================= /** get the hit position and return true if we hit something otherwise the result pos will be the dest pos */ bool VMapManager::getObjectHitPos(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float &ry, float& rz, float pModifyDist) { bool result = false; rx=x2; ry=y2; rz=z2; if(isLineOfSightCalcEnabled()) { if(iInstanceMapTrees.containsKey(pMapId)) { Vector3 pos1 = convertPositionToInternalRep(x1,y1,z1); Vector3 pos2 = convertPositionToInternalRep(x2,y2,z2); Vector3 resultPos; MapTree* mapTree = iInstanceMapTrees.get(pMapId); result = mapTree->getObjectHitPos(pos1, pos2, resultPos, pModifyDist); resultPos = convertPositionToTrinityRep(resultPos.x,resultPos.y,resultPos.z); rx = resultPos.x; ry = resultPos.y; rz = resultPos.z; #ifdef _VMAP_LOG_DEBUG Command c = Command(); c.fillTestObjectHitCmd(pMapId, pos1, pos2, resultPos, result); iCommandLogger.appendCmd(c); #endif } } return result; } //========================================================= /** get height or INVALID_HEIGHT if to hight was calculated */ //int gGetHeightCounter = 0; float VMapManager::getHeight(unsigned int pMapId, float x, float y, float z) { float height = VMAP_INVALID_HEIGHT_VALUE; //no height if(isHeightCalcEnabled() && iInstanceMapTrees.containsKey(pMapId)) { Vector3 pos = convertPositionToInternalRep(x,y,z); MapTree* mapTree = iInstanceMapTrees.get(pMapId); height = mapTree->getHeight(pos); if(!(height < inf())) { height = VMAP_INVALID_HEIGHT_VALUE; //no height } #ifdef _VMAP_LOG_DEBUG Command c = Command(); c.fillTestHeightCmd(pMapId,Vector3(x,y,z),height); iCommandLogger.appendCmd(c); #endif } return(height); } //========================================================= /** used for debugging */ bool VMapManager::processCommand(char *pCommand) { bool result = false; std::string cmd = std::string(pCommand); if(cmd == "startlog") { #ifdef _VMAP_LOG_DEBUG iCommandLogger.enableWriting(true); #endif result = true; } else if(cmd == "stoplog") { #ifdef _VMAP_LOG_DEBUG iCommandLogger.appendCmd(Command()); // Write stop command iCommandLogger.enableWriting(false); #endif result = true; } else if(cmd.find_first_of("pos ") == 0) { float x,y,z; sscanf(pCommand, "pos %f,%f,%f",&x,&y,&z); #ifdef _VMAP_LOG_DEBUG Command c = Command(); c.fillSetPosCmd(convertPositionToInternalRep(x,y,z)); iCommandLogger.appendCmd(c); iCommandLogger.enableWriting(false); #endif result = true; } return result; } //========================================================= //========================================================= //========================================================= MapTree::MapTree(const char* pBaseDir) { iBasePath = std::string(pBaseDir); if(iBasePath.length() > 0 && (iBasePath[iBasePath.length()-1] != '/' || iBasePath[iBasePath.length()-1] != '\\')) { iBasePath.append("/"); } iTree = new AABSPTree(); } //========================================================= MapTree::~MapTree() { Array mcArray; iTree->getMembers(mcArray); int no = mcArray.size(); while(no >0) { --no; delete mcArray[no]; } delete iTree; } //========================================================= // just for visual debugging with an external debug class #ifdef _DEBUG_VMAPS #ifndef gBoxArray extern Vector3 p1,p2,p3,p4,p5,p6,p7; extern ArraygBoxArray; extern int gCount1, gCount2, gCount3, gCount4; extern bool myfound; #endif #endif //========================================================= /** return dist to hit or inf() if no hit */ float MapTree::getIntersectionTime(const Ray& pRay, float pMaxDist, bool pStopAtFirstHit) { float firstDistance = inf(); IntersectionCallBack intersectionCallBack; float t = pMaxDist; iTree->intersectRay(pRay, intersectionCallBack, t, pStopAtFirstHit, false); #ifdef _DEBUG_VMAPS { if(t < pMaxDist) { myfound = true; p4 = pRay.origin + pRay.direction*t; } } #endif if(t > 0 && t < inf() && pMaxDist > t) { firstDistance = t; } return firstDistance; } //========================================================= bool MapTree::isInLineOfSight(const Vector3& pos1, const Vector3& pos2) { bool result = true; float maxDist = abs((pos2 - pos1).magnitude()); // direction with length of 1 Ray ray = Ray::fromOriginAndDirection(pos1, (pos2 - pos1)/maxDist); float resultDist = getIntersectionTime(ray, maxDist, true); if(resultDist < maxDist) { result = false; } return result; } //========================================================= /** When moving from pos1 to pos2 check if we hit an object. Return true and the position if we hit one Return the hit pos or the original dest pos */ bool MapTree::getObjectHitPos(const Vector3& pPos1, const Vector3& pPos2, Vector3& pResultHitPos, float pModifyDist) { bool result; float maxDist = abs((pPos2 - pPos1).magnitude()); Vector3 dir = (pPos2 - pPos1)/maxDist; // direction with length of 1 Ray ray = Ray::fromOriginAndDirection(pPos1, dir); float dist = getIntersectionTime(ray, maxDist, false); if(dist < maxDist) { pResultHitPos = pPos1 + dir * dist; if(pModifyDist < 0) { if(abs((pResultHitPos - pPos1).magnitude()) > -pModifyDist) { pResultHitPos = pResultHitPos + dir*pModifyDist; } else { pResultHitPos = pPos1; } } else { pResultHitPos = pResultHitPos + dir*pModifyDist; } result = true; } else { pResultHitPos = pPos2; result = false; } return result; } //========================================================= float MapTree::getHeight(const Vector3& pPos) { float height = inf(); Vector3 dir = Vector3(0,-1,0); Ray ray = Ray::fromOriginAndDirection(pPos, dir); // direction with length of 1 float maxDist = VMapDefinitions::getMaxCanFallDistance(); float dist = getIntersectionTime(ray, maxDist, false); if(dist < inf()) { height = (pPos + dir * dist).y; } return(height); } //========================================================= bool MapTree::PrepareTree() { iTree->balance(); return true; } bool MapTree::loadMap(const std::string& pDirFileName, unsigned int pMapTileIdent) { bool result = true; size_t len = iBasePath.length() + pDirFileName.length(); char *filenameBuffer = new char[len+1]; if(!hasDirFile(pDirFileName)) { FilesInDir filesInDir; result = false; sprintf(filenameBuffer, "%s%s", iBasePath.c_str(), pDirFileName.c_str()); FILE* df = fopen(filenameBuffer, "rb"); if(df) { char lineBuffer[FILENAMEBUFFER_SIZE]; result = true; bool newModelLoaded = false; while(result && (fgets(lineBuffer, FILENAMEBUFFER_SIZE-1, df) != 0)) { std::string name = std::string(lineBuffer); chomp(name); if(name.length() >1) { filesInDir.append(name); ManagedModelContainer *mc; if(!isAlreadyLoaded(name)) { std::string fname = iBasePath; fname.append(name); mc = new ManagedModelContainer(); result = mc->readFile(fname.c_str()); if(result) { addModelContainer(name, mc); newModelLoaded = true; } } else { mc = getModelContainer(name); } mc->incRefCount(); } } if(result && newModelLoaded) { iTree->balance(); } if(result && ferror(df) != 0) { result = false; } fclose(df); if(result) { filesInDir.incRefCount(); addDirFile(pDirFileName, filesInDir); setLoadedMapTile(pMapTileIdent); } } } else { // Already loaded, so just inc. the ref count if mapTileIdent is new if(!containsLoadedMapTile(pMapTileIdent)) { setLoadedMapTile(pMapTileIdent); FilesInDir& filesInDir = getDirFiles(pDirFileName); filesInDir.incRefCount(); } } delete [] filenameBuffer; return (result); } //========================================================= void MapTree::unloadMap(const std::string& dirFileName, unsigned int pMapTileIdent, bool pForce) { if(hasDirFile(dirFileName) && (pForce || containsLoadedMapTile(pMapTileIdent))) { if(containsLoadedMapTile(pMapTileIdent)) removeLoadedMapTile(pMapTileIdent); FilesInDir& filesInDir = getDirFiles(dirFileName); filesInDir.decRefCount(); if(filesInDir.getRefCount() <= 0) { Array fileNames = filesInDir.getFiles(); bool treeChanged = false; for(int i=0; idecRefCount(); if(mc->getRefCount() <= 0) { iLoadedModelContainer.remove(name); iTree->remove(mc); delete mc; treeChanged = true; } } iLoadedDirFiles.remove(dirFileName); if(treeChanged) { iTree->balance(); } } } } //========================================================= //========================================================= void MapTree::addModelContainer(const std::string& pName, ManagedModelContainer *pMc) { iLoadedModelContainer.set(pName, pMc); iTree->insert(pMc); } //========================================================= //========================================================= //========================================================= }