Initial Patch of Auction House bot rev. 135
[auctionmangos.git] / src / shared / vmap / VMapManager.cpp
blob86e017c96b087445d66cb06103efe5c146857bc3
1 /*
2 * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "VMapManager.h"
20 #include "VMapDefinitions.h"
22 using namespace G3D;
24 namespace VMAP
27 //=========================================================
29 VMapManager::VMapManager()
31 #ifdef _VMAP_LOG_DEBUG
32 iCommandLogger.setFileName("vmapcmd.log");
33 iCommandLogger.setResetFile();
34 #endif
37 //=========================================================
39 VMapManager::~VMapManager(void)
41 Array<unsigned int > keyArray = iInstanceMapTrees.getKeys();
42 for(int i=0;i<keyArray.size(); ++i)
44 delete iInstanceMapTrees.get(keyArray[i]);
45 iInstanceMapTrees.remove(keyArray[i]);
49 //=========================================================
51 Vector3 VMapManager::convertPositionToInternalRep(float x, float y, float z) const
53 float pos[3];
54 pos[0] = y;
55 pos[1] = z;
56 pos[2] = x;
57 double full = 64.0*533.33333333;
58 double mid = full/2.0;
59 pos[0] = full- (pos[0] + mid);
60 pos[2] = full- (pos[2] + mid);
62 return(Vector3(pos));
65 //=========================================================
67 Vector3 VMapManager::convertPositionToMangosRep(float x, float y, float z) const
69 float pos[3];
70 pos[0] = z;
71 pos[1] = x;
72 pos[2] = y;
73 double full = 64.0*533.33333333;
74 double mid = full/2.0;
75 pos[0] = -((mid+pos[0])-full);
76 pos[1] = -((mid+pos[1])-full);
78 return(Vector3(pos));
80 //=========================================================
82 std::string VMapManager::getDirFileName(unsigned int pMapId, int x, int y) const
84 char name[FILENAMEBUFFER_SIZE];
86 sprintf(name, "%03u_%d_%d%s",pMapId, x, y, DIR_FILENAME_EXTENSION);
87 return(std::string(name));
90 //=========================================================
91 std::string VMapManager::getDirFileName(unsigned int pMapId) const
93 char name[FILENAMEBUFFER_SIZE];
95 sprintf(name, "%03d%s",pMapId, DIR_FILENAME_EXTENSION);
96 return(std::string(name));
98 //=========================================================
99 // remote last return or LF
100 void chomp(std::string& str)
102 while(str.length() >0)
104 char lc = str[str.length()-1];
105 if(lc == '\r' || lc == '\n')
107 str = str.substr(0,str.length()-1);
109 else
111 break;
115 //=========================================================
117 void chompAndTrim(std::string& str)
119 while(str.length() >0)
121 char lc = str[str.length()-1];
122 if(lc == '\r' || lc == '\n' || lc == ' ' || lc == '"' || lc == '\'')
124 str = str.substr(0,str.length()-1);
126 else
128 break;
131 while(str.length() >0)
133 char lc = str[0];
134 if(lc == ' ' || lc == '"' || lc == '\'')
136 str = str.substr(1,str.length()-1);
138 else
140 break;
145 //=========================================================
146 // result false, if no more id are found
148 bool getNextMapId(const std::string& pString, unsigned int& pStartPos, unsigned int& pId)
150 bool result = false;
151 unsigned int i;
152 for(i=pStartPos;i<pString.size(); ++i)
154 if(pString[i] == ',')
156 break;
159 if(i>pStartPos)
161 std::string idString = pString.substr(pStartPos, i-pStartPos);
162 pStartPos = i+1;
163 chompAndTrim(idString);
164 pId = atoi(idString.c_str());
165 result = true;
167 return(result);
170 //=========================================================
172 Block maps from being used.
173 parameter: String of map ids. Delimiter = ","
174 e.g.: "0,1,590"
177 void VMapManager::preventMapsFromBeingUsed(const char* pMapIdString)
179 if(pMapIdString != NULL)
181 unsigned int pos =0;
182 unsigned int id;
183 std::string confString(pMapIdString);
184 chompAndTrim(confString);
185 while(getNextMapId(confString, pos, id))
187 iIgnoreMapIds.set(id, true);
192 //=========================================================
194 int VMapManager::loadMap(const char* pBasePath, unsigned int pMapId, int x, int y)
196 int result = VMAP_LOAD_RESULT_IGNORED;
197 if(isMapLoadingEnabled() && !iIgnoreMapIds.containsKey(pMapId))
199 bool loaded = _loadMap(pBasePath, pMapId, x, y, false);
200 if(!loaded)
202 // if we can't load the map it might be splitted into tiles. Try that one and store the result
203 loaded = _loadMap(pBasePath, pMapId, x, y, true);
204 if(loaded)
206 iMapsSplitIntoTiles.set(pMapId, true);
209 if(loaded)
211 result = VMAP_LOAD_RESULT_OK;
212 // just for debugging
213 #ifdef _VMAP_LOG_DEBUG
214 Command c = Command();
215 c.fillLoadTileCmd(x, y, pMapId);
216 iCommandLogger.appendCmd(c);
217 #endif
219 else
221 result = VMAP_LOAD_RESULT_ERROR;
224 return result;
227 //=========================================================
228 // load one tile (internal use only)
230 bool VMapManager::_loadMap(const char* pBasePath, unsigned int pMapId, int x, int y, bool pForceTileLoad)
232 bool result = false;
233 std::string dirFileName;
234 if(pForceTileLoad || iMapsSplitIntoTiles.containsKey(pMapId))
236 dirFileName = getDirFileName(pMapId,x,y);
238 else
240 dirFileName = getDirFileName(pMapId);
242 MapTree* instanceTree;
243 if(!iInstanceMapTrees.containsKey(pMapId))
245 instanceTree = new MapTree(pBasePath);
246 iInstanceMapTrees.set(pMapId, instanceTree);
248 else
249 instanceTree = iInstanceMapTrees.get(pMapId);
251 unsigned int mapTileIdent = MAP_TILE_IDENT(x,y);
252 result = instanceTree->loadMap(dirFileName, mapTileIdent);
253 if(!result) // remove on fail
255 if(instanceTree->size() == 0)
257 iInstanceMapTrees.remove(pMapId);
258 delete instanceTree;
261 return(result);
264 //=========================================================
266 bool VMapManager::_existsMap(const std::string& pBasePath, unsigned int pMapId, int x, int y, bool pForceTileLoad)
268 bool result = false;
269 std::string dirFileName;
270 if(pForceTileLoad || iMapsSplitIntoTiles.containsKey(pMapId))
272 dirFileName = getDirFileName(pMapId,x,y);
274 else
276 dirFileName = getDirFileName(pMapId);
278 size_t len = pBasePath.length() + dirFileName.length();
279 char *filenameBuffer = new char[len+1];
280 sprintf(filenameBuffer, "%s%s", pBasePath.c_str(), dirFileName.c_str());
281 FILE* df = fopen(filenameBuffer, "rb");
282 if(df)
284 char lineBuffer[FILENAMEBUFFER_SIZE];
285 if (fgets(lineBuffer, FILENAMEBUFFER_SIZE-1, df) != 0)
287 std::string name = std::string(lineBuffer);
288 chomp(name);
289 if(name.length() >1)
291 sprintf(filenameBuffer, "%s%s", pBasePath.c_str(), name.c_str());
292 FILE* df2 = fopen(filenameBuffer, "rb");
293 if(df2)
295 char magic[8];
296 fread(magic,1,8,df2);
297 if(!strncmp(VMAP_MAGIC,magic,8))
298 result = true;
299 fclose(df2);
303 fclose(df);
305 delete[] filenameBuffer;
306 return result;
309 //=========================================================
311 bool VMapManager::existsMap(const char* pBasePath, unsigned int pMapId, int x, int y)
313 std::string basePath = std::string(pBasePath);
314 if(basePath.length() > 0 && (basePath[basePath.length()-1] != '/' || basePath[basePath.length()-1] != '\\'))
316 basePath.append("/");
318 bool found = _existsMap(basePath, pMapId, x, y, false);
319 if(!found)
321 // if we can't load the map it might be splitted into tiles. Try that one and store the result
322 found = _existsMap(basePath, pMapId, x, y, true);
323 if(found)
325 iMapsSplitIntoTiles.set(pMapId, true);
328 return found;
331 //=========================================================
333 void VMapManager::unloadMap(unsigned int pMapId, int x, int y)
335 _unloadMap(pMapId, x, y);
337 #ifdef _VMAP_LOG_DEBUG
338 Command c = Command();
339 c.fillUnloadTileCmd(pMapId, x,y);
340 iCommandLogger.appendCmd(c);
341 #endif
344 //=========================================================
346 void VMapManager::_unloadMap(unsigned int pMapId, int x, int y)
348 if(iInstanceMapTrees.containsKey(pMapId))
350 MapTree* instanceTree = iInstanceMapTrees.get(pMapId);
351 std::string dirFileName;
352 if(iMapsSplitIntoTiles.containsKey(pMapId))
354 dirFileName = getDirFileName(pMapId,x,y);
356 else
358 dirFileName = getDirFileName(pMapId);
360 unsigned int mapTileIdent = MAP_TILE_IDENT(x,y);
361 instanceTree->unloadMap(dirFileName, mapTileIdent);
362 if(instanceTree->size() == 0)
364 iInstanceMapTrees.remove(pMapId);
365 delete instanceTree;
370 //=========================================================
372 void VMapManager::unloadMap(unsigned int pMapId)
374 if(iInstanceMapTrees.containsKey(pMapId))
376 MapTree* instanceTree = iInstanceMapTrees.get(pMapId);
377 std::string dirFileName = getDirFileName(pMapId);
378 instanceTree->unloadMap(dirFileName, 0, true);
379 if(instanceTree->size() == 0)
381 iInstanceMapTrees.remove(pMapId);
382 delete instanceTree;
384 #ifdef _VMAP_LOG_DEBUG
385 Command c = Command();
386 c.fillUnloadTileCmd(pMapId);
387 iCommandLogger.appendCmd(c);
388 #endif
391 //==========================================================
393 bool VMapManager::isInLineOfSight(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2)
395 bool result = true;
396 if(isLineOfSightCalcEnabled() && iInstanceMapTrees.containsKey(pMapId))
398 Vector3 pos1 = convertPositionToInternalRep(x1,y1,z1);
399 Vector3 pos2 = convertPositionToInternalRep(x2,y2,z2);
400 if(pos1 != pos2)
402 MapTree* mapTree = iInstanceMapTrees.get(pMapId);
403 result = mapTree->isInLineOfSight(pos1, pos2);
404 #ifdef _VMAP_LOG_DEBUG
405 Command c = Command();
406 // save the orig vectors
407 c.fillTestVisCmd(pMapId,Vector3(x1,y1,z1),Vector3(x2,y2,z2),result);
408 iCommandLogger.appendCmd(c);
409 #endif
412 return(result);
414 //=========================================================
416 get the hit position and return true if we hit something
417 otherwise the result pos will be the dest pos
419 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)
421 bool result = false;
422 rx=x2;
423 ry=y2;
424 rz=z2;
425 if(isLineOfSightCalcEnabled())
427 if(iInstanceMapTrees.containsKey(pMapId))
429 Vector3 pos1 = convertPositionToInternalRep(x1,y1,z1);
430 Vector3 pos2 = convertPositionToInternalRep(x2,y2,z2);
431 Vector3 resultPos;
432 MapTree* mapTree = iInstanceMapTrees.get(pMapId);
433 result = mapTree->getObjectHitPos(pos1, pos2, resultPos, pModifyDist);
434 resultPos = convertPositionToMangosRep(resultPos.x,resultPos.y,resultPos.z);
435 rx = resultPos.x;
436 ry = resultPos.y;
437 rz = resultPos.z;
438 #ifdef _VMAP_LOG_DEBUG
439 Command c = Command();
440 c.fillTestObjectHitCmd(pMapId, pos1, pos2, resultPos, result);
441 iCommandLogger.appendCmd(c);
442 #endif
445 return result;
448 //=========================================================
450 get height or INVALID_HEIGHT if to hight was calculated
453 //int gGetHeightCounter = 0;
454 float VMapManager::getHeight(unsigned int pMapId, float x, float y, float z)
456 float height = VMAP_INVALID_HEIGHT_VALUE; //no height
457 if(isHeightCalcEnabled() && iInstanceMapTrees.containsKey(pMapId))
459 Vector3 pos = convertPositionToInternalRep(x,y,z);
460 MapTree* mapTree = iInstanceMapTrees.get(pMapId);
461 height = mapTree->getHeight(pos);
462 if(!(height < inf()))
464 height = VMAP_INVALID_HEIGHT_VALUE; //no height
466 #ifdef _VMAP_LOG_DEBUG
467 Command c = Command();
468 c.fillTestHeightCmd(pMapId,Vector3(x,y,z),height);
469 iCommandLogger.appendCmd(c);
470 #endif
472 return(height);
475 //=========================================================
477 used for debugging
479 bool VMapManager::processCommand(char *pCommand)
481 bool result = false;
482 std::string cmd = std::string(pCommand);
483 if(cmd == "startlog")
485 #ifdef _VMAP_LOG_DEBUG
487 iCommandLogger.enableWriting(true);
488 #endif
489 result = true;
491 else if(cmd == "stoplog")
493 #ifdef _VMAP_LOG_DEBUG
494 iCommandLogger.appendCmd(Command()); // Write stop command
495 iCommandLogger.enableWriting(false);
496 #endif
497 result = true;
499 else if(cmd.find_first_of("pos ") == 0)
501 float x,y,z;
502 sscanf(pCommand, "pos %f,%f,%f",&x,&y,&z);
503 #ifdef _VMAP_LOG_DEBUG
504 Command c = Command();
505 c.fillSetPosCmd(convertPositionToInternalRep(x,y,z));
506 iCommandLogger.appendCmd(c);
507 iCommandLogger.enableWriting(false);
508 #endif
509 result = true;
511 return result;
514 //=========================================================
515 //=========================================================
516 //=========================================================
518 MapTree::MapTree(const char* pBaseDir)
520 iBasePath = std::string(pBaseDir);
521 if(iBasePath.length() > 0 && (iBasePath[iBasePath.length()-1] != '/' || iBasePath[iBasePath.length()-1] != '\\'))
523 iBasePath.append("/");
525 iTree = new AABSPTree<ModelContainer *>();
528 //=========================================================
529 MapTree::~MapTree()
531 Array<ModelContainer *> mcArray;
532 iTree->getMembers(mcArray);
533 int no = mcArray.size();
534 while(no >0)
536 --no;
537 delete mcArray[no];
539 delete iTree;
541 //=========================================================
543 // just for visual debugging with an external debug class
544 #ifdef _DEBUG_VMAPS
545 #ifndef gBoxArray
546 extern Vector3 p1,p2,p3,p4,p5,p6,p7;
547 extern Array<AABox>gBoxArray;
548 extern int gCount1, gCount2, gCount3, gCount4;
549 extern bool myfound;
550 #endif
551 #endif
553 //=========================================================
555 return dist to hit or inf() if no hit
558 float MapTree::getIntersectionTime(const Ray& pRay, float pMaxDist, bool pStopAtFirstHit)
560 float firstDistance = inf();
561 IntersectionCallBack<ModelContainer> intersectionCallBack;
562 float t = pMaxDist;
563 iTree->intersectRay(pRay, intersectionCallBack, t, pStopAtFirstHit, false);
564 #ifdef _DEBUG_VMAPS
566 if(t < pMaxDist)
568 myfound = true;
569 p4 = pRay.origin + pRay.direction*t;
572 #endif
573 if(t > 0 && t < inf() && pMaxDist > t)
575 firstDistance = t;
577 return firstDistance;
579 //=========================================================
581 bool MapTree::isInLineOfSight(const Vector3& pos1, const Vector3& pos2)
583 bool result = true;
584 float maxDist = abs((pos2 - pos1).magnitude());
585 // direction with length of 1
586 Ray ray = Ray::fromOriginAndDirection(pos1, (pos2 - pos1)/maxDist);
587 float resultDist = getIntersectionTime(ray, maxDist, true);
588 if(resultDist < maxDist)
590 result = false;
592 return result;
594 //=========================================================
596 When moving from pos1 to pos2 check if we hit an object. Return true and the position if we hit one
597 Return the hit pos or the original dest pos
600 bool MapTree::getObjectHitPos(const Vector3& pPos1, const Vector3& pPos2, Vector3& pResultHitPos, float pModifyDist)
602 bool result;
603 float maxDist = abs((pPos2 - pPos1).magnitude());
604 Vector3 dir = (pPos2 - pPos1)/maxDist; // direction with length of 1
605 Ray ray = Ray::fromOriginAndDirection(pPos1, dir);
606 float dist = getIntersectionTime(ray, maxDist, false);
607 if(dist < maxDist)
609 pResultHitPos = pPos1 + dir * dist;
610 if(pModifyDist < 0)
612 if(abs((pResultHitPos - pPos1).magnitude()) > -pModifyDist)
614 pResultHitPos = pResultHitPos + dir*pModifyDist;
616 else
618 pResultHitPos = pPos1;
621 else
623 pResultHitPos = pResultHitPos + dir*pModifyDist;
625 result = true;
627 else
629 pResultHitPos = pPos2;
630 result = false;
632 return result;
635 //=========================================================
637 float MapTree::getHeight(const Vector3& pPos)
639 float height = inf();
640 Vector3 dir = Vector3(0,-1,0);
641 Ray ray = Ray::fromOriginAndDirection(pPos, dir); // direction with length of 1
642 float maxDist = VMapDefinitions::getMaxCanFallDistance();
643 float dist = getIntersectionTime(ray, maxDist, false);
644 if(dist < inf())
646 height = (pPos + dir * dist).y;
648 return(height);
651 //=========================================================
653 bool MapTree::PrepareTree()
655 iTree->balance();
656 return true;
659 bool MapTree::loadMap(const std::string& pDirFileName, unsigned int pMapTileIdent)
661 bool result = true;
662 size_t len = iBasePath.length() + pDirFileName.length();
663 char *filenameBuffer = new char[len+1];
664 if(!hasDirFile(pDirFileName))
666 FilesInDir filesInDir;
667 result = false;
668 sprintf(filenameBuffer, "%s%s", iBasePath.c_str(), pDirFileName.c_str());
669 FILE* df = fopen(filenameBuffer, "rb");
670 if(df)
672 char lineBuffer[FILENAMEBUFFER_SIZE];
673 result = true;
674 bool newModelLoaded = false;
675 while(result && (fgets(lineBuffer, FILENAMEBUFFER_SIZE-1, df) != 0))
677 std::string name = std::string(lineBuffer);
678 chomp(name);
679 if(name.length() >1)
681 filesInDir.append(name);
682 ManagedModelContainer *mc;
683 if(!isAlreadyLoaded(name))
685 std::string fname = iBasePath;
686 fname.append(name);
687 mc = new ManagedModelContainer();
688 result = mc->readFile(fname.c_str());
689 if(result)
691 addModelContainer(name, mc);
692 newModelLoaded = true;
695 else
697 mc = getModelContainer(name);
699 mc->incRefCount();
702 if(result && newModelLoaded)
704 iTree->balance();
706 if(result && ferror(df) != 0)
708 result = false;
710 fclose(df);
711 if(result)
713 filesInDir.incRefCount();
714 addDirFile(pDirFileName, filesInDir);
715 setLoadedMapTile(pMapTileIdent);
719 else
721 // Already loaded, so just inc. the ref count if mapTileIdent is new
722 if(!containsLoadedMapTile(pMapTileIdent))
724 setLoadedMapTile(pMapTileIdent);
725 FilesInDir& filesInDir = getDirFiles(pDirFileName);
726 filesInDir.incRefCount();
729 delete [] filenameBuffer;
730 return (result);
733 //=========================================================
735 void MapTree::unloadMap(const std::string& dirFileName, unsigned int pMapTileIdent, bool pForce)
737 if(hasDirFile(dirFileName) && (pForce || containsLoadedMapTile(pMapTileIdent)))
739 if(containsLoadedMapTile(pMapTileIdent))
740 removeLoadedMapTile(pMapTileIdent);
741 FilesInDir& filesInDir = getDirFiles(dirFileName);
742 filesInDir.decRefCount();
743 if(filesInDir.getRefCount() <= 0)
745 Array<std::string> fileNames = filesInDir.getFiles();
746 bool treeChanged = false;
747 for(int i=0; i<fileNames.size(); ++i)
749 std::string name = fileNames[i];
750 ManagedModelContainer* mc = getModelContainer(name);
751 mc->decRefCount();
752 if(mc->getRefCount() <= 0)
754 iLoadedModelContainer.remove(name);
755 iTree->remove(mc);
756 delete mc;
757 treeChanged = true;
760 iLoadedDirFiles.remove(dirFileName);
761 if(treeChanged)
763 iTree->balance();
769 //=========================================================
770 //=========================================================
772 void MapTree::addModelContainer(const std::string& pName, ManagedModelContainer *pMc)
774 iLoadedModelContainer.set(pName, pMc);
775 iTree->insert(pMc);
777 //=========================================================
778 //=========================================================
779 //=========================================================