diff --git a/source/glest_game/ai/path_finder.cpp b/source/glest_game/ai/path_finder.cpp index 46fe1c6d..f061c5c3 100644 --- a/source/glest_game/ai/path_finder.cpp +++ b/source/glest_game/ai/path_finder.cpp @@ -39,7 +39,7 @@ namespace Glest{ namespace Game{ const int PathFinder::maxFreeSearchRadius = 10; //const int PathFinder::pathFindNodesMax= 400; -int PathFinder::pathFindNodesMax = 1000; +int PathFinder::pathFindNodesMax = 1200; const int PathFinder::pathFindRefresh = 10; const int PathFinder::pathFindBailoutRadius = 20; @@ -59,6 +59,7 @@ PathFinder::PathFinder(const Map *map) { void PathFinder::init(const Map *map) { PathFinder::pathFindNodesMax = Config::getInstance().getInt("MaxPathfinderNodeCount",intToStr(PathFinder::pathFindNodesMax).c_str()); nodePool.resize(pathFindNodesMax); + useMaxNodeCount = PathFinder::pathFindNodesMax; this->map= map; } @@ -312,9 +313,9 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu // ==================== PRIVATE ==================== -void PathFinder::processNode(Unit *unit, Node *node,const Vec2i finalPos, int i, int j, bool &nodeLimitReached) { +bool PathFinder::processNode(Unit *unit, Node *node,const Vec2i finalPos, int i, int j, bool &nodeLimitReached) { + bool result = false; Vec2i sucPos= node->pos + Vec2i(i, j); - bool canUnitMoveToCell = map->aproxCanMove(unit, node->pos, sucPos); if(openPos(sucPos) == false && canUnitMoveToCell == true) { //if node is not open and canMove then generate another node @@ -330,11 +331,14 @@ void PathFinder::processNode(Unit *unit, Node *node,const Vec2i finalPos, int i, } openNodesList[sucNode->heuristic].push_back(sucNode); openPosList[sucNode->pos] = true; + + result = true; } else { nodeLimitReached= true; } } + return result; } //route a unit using A* algorithm @@ -355,118 +359,140 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout const Vec2i unitPos = unit->getPos(); const Vec2i finalPos= computeNearestFreePos(unit, targetPos); + float dist= unitPos.dist(finalPos); + + useMaxNodeCount = PathFinder::pathFindNodesMax; + if(dist <= 10) { + useMaxNodeCount = (int)dist * 20; + if(useMaxNodeCount <= 0) { + useMaxNodeCount = 200; + } + } + if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); UnitPathInterface *path= unit->getPath(); // Check the previous path find cache for the unit to see if its good to // use - const bool tryLastPathCache = Config::getInstance().getBool("EnablePathfinderCache","false"); - if(tryLastPathCache == true && path != NULL) { - UnitPathBasic *basicPathFinder = dynamic_cast(path); - if(basicPathFinder != NULL && basicPathFinder->getLastPathCacheQueueCount() > 0) { - vector cachedPath= basicPathFinder->getLastPathCacheQueue(); - for(int i = 0; i < cachedPath.size(); ++i) { - Vec2i &pos1 = cachedPath[i]; - // Looking to find if the unit is in one of the cells in the cached path - if(unitPos == pos1) { - // Now see if we can re-use this path to get to the final destination - for(int j = i+1; j < cachedPath.size(); ++j) { - Vec2i &pos2 = cachedPath[j]; - bool canUnitMoveToCell = map->aproxCanMove(unit, pos1, pos2); - if(canUnitMoveToCell == true) { - if(pos2 == finalPos) { - //on the way - ts= tsMoving; + const bool showConsoleDebugInfo = Config::getInstance().getBool("EnablePathfinderDistanceOutput","false"); + const bool tryLastPathCache = Config::getInstance().getBool("EnablePathfinderCache","true"); + if((showConsoleDebugInfo || tryLastPathCache) && dist > 60) { + if(showConsoleDebugInfo) printf("Distance from [%d - %s] to destination is %.2f tryLastPathCache = %d\n",unit->getId(),unit->getFullName().c_str(), dist,tryLastPathCache); - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); + if(tryLastPathCache == true && path != NULL) { + UnitPathBasic *basicPathFinder = dynamic_cast(path); + if(basicPathFinder != NULL && basicPathFinder->getLastPathCacheQueueCount() > 0) { + vector cachedPath= basicPathFinder->getLastPathCacheQueue(); + for(int i = 0; i < cachedPath.size(); ++i) { + Vec2i &pos1 = cachedPath[i]; + // Looking to find if the unit is in one of the cells in the cached path + if(unitPos == pos1) { + // Now see if we can re-use this path to get to the final destination + for(int j = i+1; j < cachedPath.size(); ++j) { + Vec2i &pos2 = cachedPath[j]; + bool canUnitMoveToCell = map->aproxCanMove(unit, pos1, pos2); + if(canUnitMoveToCell == true) { + if(pos2 == finalPos) { + //on the way + ts= tsMoving; - //store path - basicPathFinder->clear(); + if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - int pathCount=0; - for(int k=i+1; k <= j; k++) { - if(pathCount < pathFindRefresh) { - basicPathFinder->add(cachedPath[k]); - } - basicPathFinder->addToLastPathCache(cachedPath[k]); - pathCount++; - } + //store path + basicPathFinder->clear(); - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - - if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true) { - char szBuf[4096]=""; - sprintf(szBuf,"[Setting new path for unit] openNodesList.size() [%ld] openPosList.size() [%ld] finalPos [%s] targetPos [%s] inBailout [%d] ts [%d]", - openNodesList.size(),openPosList.size(),finalPos.getString().c_str(),targetPos.getString().c_str(),inBailout,ts); - unit->logSynchData(__FILE__,__LINE__,szBuf); - } - - if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled == true) { - string commandDesc = "none"; - Command *command= unit->getCurrCommand(); - if(command != NULL && command->getCommandType() != NULL) { - commandDesc = command->getCommandType()->toString(); + int pathCount=0; + for(int k=i+1; k <= j; k++) { + if(k >= cachedPath.size()) { + throw runtime_error("k >= cachedPath.size() k = " + intToStr(k) + " cachedPath.size() = " + intToStr(cachedPath.size())); + } + if(pathCount < pathFindRefresh) { + basicPathFinder->add(cachedPath[k]); + } + basicPathFinder->addToLastPathCache(cachedPath[k]); + pathCount++; } - char szBuf[1024]=""; - sprintf(szBuf,"State: moving, cmd [%s] pos: %s dest pos: %s, Queue= %d",commandDesc.c_str(),unit->getPos().getString().c_str(), targetPos.getString().c_str(),path->getQueueCount()); - unit->setCurrentUnitTitle(szBuf); + if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); + + if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true) { + char szBuf[4096]=""; + sprintf(szBuf,"[Setting new path for unit] openNodesList.size() [%ld] openPosList.size() [%ld] finalPos [%s] targetPos [%s] inBailout [%d] ts [%d]", + openNodesList.size(),openPosList.size(),finalPos.getString().c_str(),targetPos.getString().c_str(),inBailout,ts); + unit->logSynchData(__FILE__,__LINE__,szBuf); + } + + if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled == true) { + string commandDesc = "none"; + Command *command= unit->getCurrCommand(); + if(command != NULL && command->getCommandType() != NULL) { + commandDesc = command->getCommandType()->toString(); + } + + char szBuf[1024]=""; + sprintf(szBuf,"State: moving, cmd [%s] pos: %s dest pos: %s, Queue= %d",commandDesc.c_str(),unit->getPos().getString().c_str(), targetPos.getString().c_str(),path->getQueueCount()); + unit->setCurrentUnitTitle(szBuf); + } + + if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); + + return ts; + //break; } + else if(j - i > pathFindRefresh) { + //on the way + ts= tsMoving; - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); + if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - return ts; - //break; + //store path + basicPathFinder->clear(); + + int pathCount=0; + for(int k=i+1; k < cachedPath.size(); k++) { + if(k >= cachedPath.size()) { + throw runtime_error("#2 k >= cachedPath.size() k = " + intToStr(k) + " cachedPath.size() = " + intToStr(cachedPath.size())); + } + + if(pathCount < pathFindRefresh) { + basicPathFinder->add(cachedPath[k]); + } + basicPathFinder->addToLastPathCache(cachedPath[k]); + pathCount++; + } + + if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); + + if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true) { + char szBuf[4096]=""; + sprintf(szBuf,"[Setting new path for unit] openNodesList.size() [%ld] openPosList.size() [%ld] finalPos [%s] targetPos [%s] inBailout [%d] ts [%d]", + openNodesList.size(),openPosList.size(),finalPos.getString().c_str(),targetPos.getString().c_str(),inBailout,ts); + unit->logSynchData(__FILE__,__LINE__,szBuf); + } + + if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled == true) { + string commandDesc = "none"; + Command *command= unit->getCurrCommand(); + if(command != NULL && command->getCommandType() != NULL) { + commandDesc = command->getCommandType()->toString(); + } + + char szBuf[1024]=""; + sprintf(szBuf,"State: moving, cmd [%s] pos: %s dest pos: %s, Queue= %d",commandDesc.c_str(),unit->getPos().getString().c_str(), targetPos.getString().c_str(),path->getQueueCount()); + unit->setCurrentUnitTitle(szBuf); + } + + if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); + + return ts; + } } - else if(j - i > pathFindRefresh) { - //on the way - ts= tsMoving; - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - - //store path - basicPathFinder->clear(); - - int pathCount=0; - for(int k=i+1; k <= cachedPath.size(); k++) { - if(pathCount < pathFindRefresh) { - basicPathFinder->add(cachedPath[k]); - } - basicPathFinder->addToLastPathCache(cachedPath[k]); - pathCount++; - } - - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - - if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true) { - char szBuf[4096]=""; - sprintf(szBuf,"[Setting new path for unit] openNodesList.size() [%ld] openPosList.size() [%ld] finalPos [%s] targetPos [%s] inBailout [%d] ts [%d]", - openNodesList.size(),openPosList.size(),finalPos.getString().c_str(),targetPos.getString().c_str(),inBailout,ts); - unit->logSynchData(__FILE__,__LINE__,szBuf); - } - - if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled == true) { - string commandDesc = "none"; - Command *command= unit->getCurrCommand(); - if(command != NULL && command->getCommandType() != NULL) { - commandDesc = command->getCommandType()->toString(); - } - - char szBuf[1024]=""; - sprintf(szBuf,"State: moving, cmd [%s] pos: %s dest pos: %s, Queue= %d",commandDesc.c_str(),unit->getPos().getString().c_str(), targetPos.getString().c_str(),path->getQueueCount()); - unit->setCurrentUnitTitle(szBuf); - } - - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - - return ts; - } + pos1 = pos2; } - pos1 = pos2; + break; } - - break; } } } @@ -528,38 +554,68 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout closedNodesList[node->heuristic].push_back(node); openPosList[node->pos] = true; + int failureCount = 0; + int cellCount = 0; + int tryDirection = random.randRange(0,3); if(tryDirection == 3) { for(int i = 1; i >= -1 && nodeLimitReached == false; --i) { for(int j = -1; j <= 1 && nodeLimitReached == false; ++j) { - processNode(unit, node, finalPos, i, j, nodeLimitReached); + if(processNode(unit, node, finalPos, i, j, nodeLimitReached) == false) { + failureCount++; + } + cellCount++; } } +// if(failureCount == cellCount && node->pos == unitPos) { +// nodeLimitReached = true; +// } } else if(tryDirection == 2) { for(int i = -1; i <= 1 && nodeLimitReached == false; ++i) { for(int j = 1; j >= -1 && nodeLimitReached == false; --j) { - processNode(unit, node, finalPos, i, j, nodeLimitReached); + if(processNode(unit, node, finalPos, i, j, nodeLimitReached) == false) { + failureCount++; + } + cellCount++; } } +// if(failureCount == cellCount && node->pos == unitPos) { +// nodeLimitReached = true; +// } } else if(tryDirection == 1) { for(int i = -1; i <= 1 && nodeLimitReached == false; ++i) { for(int j = -1; j <= 1 && nodeLimitReached == false; ++j) { - processNode(unit, node, finalPos, i, j, nodeLimitReached); + if(processNode(unit, node, finalPos, i, j, nodeLimitReached) == false) { + failureCount++; + } + cellCount++; } } +// if(failureCount == cellCount && node->pos == unitPos) { +// nodeLimitReached = true; +// } } else { for(int i = 1; i >= -1 && nodeLimitReached == false; --i) { for(int j = 1; j >= -1 && nodeLimitReached == false; --j) { - processNode(unit, node, finalPos, i, j, nodeLimitReached); + if(processNode(unit, node, finalPos, i, j, nodeLimitReached) == false) { + failureCount++; + } + cellCount++; } } +// if(failureCount == cellCount && node->pos == unitPos) { +// nodeLimitReached = true; +// } } } //while - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 1) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); + if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 1) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld nodeLimitReached = %d whileLoopCount = %d nodePoolCount = %d\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis(),nodeLimitReached,whileLoopCount,nodePoolCount); + if(showConsoleDebugInfo && chrono.getMillis() > 2) { + printf("Distance for unit [%d - %s] to destination is %.2f took msecs: %lld nodeLimitReached = %d whileLoopCount = %d nodePoolCount = %d\n",unit->getId(),unit->getFullName().c_str(), dist,(long long int)chrono.getMillis(),nodeLimitReached,whileLoopCount,nodePoolCount); + } Node *lastNode= node; @@ -625,11 +681,20 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout currNode= firstNode; for(int i=0; currNode->next != NULL; currNode= currNode->next, i++) { - if(i < pathFindRefresh) { - path->add(currNode->next->pos); + Vec2i nodePos = currNode->next->pos; + if(map->isInside(nodePos) == false || map->isInsideSurface(map->toSurfCoords(nodePos)) == false) { + throw runtime_error("Pathfinder invalid node path position = " + nodePos.getString() + " i = " + intToStr(i)); } - if(basicPathFinder) { - basicPathFinder->addToLastPathCache(currNode->next->pos); + + if(i < pathFindRefresh) { + path->add(nodePos); + } + else if(tryLastPathCache == false) { + break; + } + + if(tryLastPathCache == true && basicPathFinder) { + basicPathFinder->addToLastPathCache(nodePos); } } @@ -678,7 +743,7 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout } PathFinder::Node *PathFinder::newNode() { - if(nodePoolCount < nodePool.size()) { + if(nodePoolCount < nodePool.size() && nodePoolCount < useMaxNodeCount) { Node *node= &nodePool[nodePoolCount]; node->clear(); nodePoolCount++; diff --git a/source/glest_game/ai/path_finder.h b/source/glest_game/ai/path_finder.h index fbac22d7..84da92af 100644 --- a/source/glest_game/ai/path_finder.h +++ b/source/glest_game/ai/path_finder.h @@ -72,6 +72,7 @@ private: int nodePoolCount; const Map *map; RandomGen random; + int useMaxNodeCount; public: PathFinder(); @@ -89,7 +90,7 @@ private: Node * minHeuristicFastLookup(); - void processNode(Unit *unit, Node *node,const Vec2i finalPos, int i, int j, bool &nodeLimitReached); + bool processNode(Unit *unit, Node *node,const Vec2i finalPos, int i, int j, bool &nodeLimitReached); void processNearestFreePos(const Vec2i &finalPos, int i, int j, int size, Field field, int teamIndex,Vec2i unitPos, Vec2i &nearestPos, float &nearestDist); }; diff --git a/source/glest_game/type_instances/unit.cpp b/source/glest_game/type_instances/unit.cpp index 195a46e5..f00928c0 100644 --- a/source/glest_game/type_instances/unit.cpp +++ b/source/glest_game/type_instances/unit.cpp @@ -41,12 +41,14 @@ UnitPathBasic::UnitPathBasic() { this->blockCount = 0; this->pathQueue.clear(); this->lastPathCacheQueue.clear(); + this->map = NULL; } UnitPathBasic::~UnitPathBasic() { this->blockCount = 0; this->pathQueue.clear(); this->lastPathCacheQueue.clear(); + this->map = NULL; } bool UnitPathBasic::isEmpty() const { @@ -73,15 +75,36 @@ void UnitPathBasic::incBlockCount() { blockCount++; } -void UnitPathBasic::add(const Vec2i &path){ +void UnitPathBasic::add(const Vec2i &path) { + if(this->map != NULL) { + if(this->map->isInside(path) == false) { + throw runtime_error("Invalid map path position = " + path.getString() + " map w x h = " + intToStr(map->getW()) + " " + intToStr(map->getH())); + } + else if(this->map->isInsideSurface(this->map->toSurfCoords(path)) == false) { + throw runtime_error("Invalid map surface path position = " + path.getString() + " map surface w x h = " + intToStr(map->getSurfaceW()) + " " + intToStr(map->getSurfaceH())); + } + } + pathQueue.push_back(path); } void UnitPathBasic::addToLastPathCache(const Vec2i &path) { + if(this->map != NULL) { + if(this->map->isInside(path) == false) { + throw runtime_error("Invalid map path position = " + path.getString() + " map w x h = " + intToStr(map->getW()) + " " + intToStr(map->getH())); + } + else if(this->map->isInsideSurface(this->map->toSurfCoords(path)) == false) { + throw runtime_error("Invalid map surface path position = " + path.getString() + " map surface w x h = " + intToStr(map->getSurfaceW()) + " " + intToStr(map->getSurfaceH())); + } + } + lastPathCacheQueue.push_back(path); } Vec2i UnitPathBasic::pop() { + if(pathQueue.size() <= 0) { + throw runtime_error("pathQueue.size() = " + intToStr(pathQueue.size())); + } Vec2i p= pathQueue.front(); pathQueue.erase(pathQueue.begin()); return p; @@ -182,7 +205,12 @@ Unit::Unit(int id, UnitPathInterface *unitpath, const Vec2i &pos, const UnitType RandomGen random; + if(map->isInside(pos) == false || map->isInsideSurface(map->toSurfCoords(pos)) == false) { + throw runtime_error("#2 Invalid path position = " + pos.getString()); + } + this->unitPath = unitpath; + this->unitPath->setMap(map); this->pos=pos; this->type=type; this->faction=faction; @@ -606,7 +634,11 @@ void Unit::setTarget(const Unit *unit){ targetRef= unit; } -void Unit::setPos(const Vec2i &pos){ +void Unit::setPos(const Vec2i &pos) { + if(map->isInside(pos) == false || map->isInsideSurface(map->toSurfCoords(pos)) == false) { + throw runtime_error("#3 Invalid path position = " + pos.getString()); + } + this->lastPos= this->pos; this->pos= pos; this->meetingPos= pos - Vec2i(1); @@ -617,7 +649,11 @@ void Unit::setPos(const Vec2i &pos){ logSynchData(__FILE__,__LINE__); } -void Unit::setTargetPos(const Vec2i &targetPos){ +void Unit::setTargetPos(const Vec2i &targetPos) { + + if(map->isInside(targetPos) == false || map->isInsideSurface(map->toSurfCoords(targetPos)) == false) { + throw runtime_error("#4 Invalid path position = " + targetPos.getString()); + } Vec2i relPos= targetPos - pos; Vec2f relPosf= Vec2f((float)relPos.x, (float)relPos.y); @@ -1024,6 +1060,11 @@ void Unit::resetHighlight(){ const CommandType *Unit::computeCommandType(const Vec2i &pos, const Unit *targetUnit) const{ const CommandType *commandType= NULL; + + if(map->isInside(pos) == false || map->isInsideSurface(map->toSurfCoords(pos)) == false) { + throw runtime_error("#6 Invalid path position = " + pos.getString()); + } + SurfaceCell *sc= map->getSurfaceCell(Map::toSurfCoords(pos)); if(type == NULL) { @@ -1501,6 +1542,10 @@ bool Unit::morph(const MorphCommandType *mct){ // ==================== PRIVATE ==================== float Unit::computeHeight(const Vec2i &pos) const{ + if(map->isInside(pos) == false || map->isInsideSurface(map->toSurfCoords(pos)) == false) { + throw runtime_error("#7 Invalid path position = " + pos.getString()); + } + float height= map->getCell(pos)->getHeight(); if(currField == fAir) { @@ -1811,6 +1856,10 @@ void Unit::setTargetVec(const Vec3f &targetVec) { } void Unit::setMeetingPos(const Vec2i &meetingPos) { + if(map->isInside(meetingPos) == false || map->isInsideSurface(map->toSurfCoords(meetingPos)) == false) { + throw runtime_error("#8 Invalid path position = " + meetingPos.getString()); + } + this->meetingPos= meetingPos; logSynchData(__FILE__,__LINE__); } diff --git a/source/glest_game/type_instances/unit.h b/source/glest_game/type_instances/unit.h index d174d281..a06da1c9 100644 --- a/source/glest_game/type_instances/unit.h +++ b/source/glest_game/type_instances/unit.h @@ -120,11 +120,15 @@ public: virtual vector getQueue() const = 0; virtual std::string toString() const = 0; + + virtual void setMap(Map *value) = 0; + virtual Map * getMap() = 0; }; class UnitPathBasic : public UnitPathInterface { private: static const int maxBlockCount; + Map *map; private: int blockCount; @@ -152,6 +156,9 @@ public: virtual vector getQueue() const { return pathQueue; } + virtual void setMap(Map *value) { map = value; } + virtual Map * getMap() { return map; } + virtual std::string toString() const; }; @@ -167,9 +174,10 @@ private: private: int blockCount; /**< number of command updates this path has been blocked */ + Map *map; public: - UnitPath() : blockCount(0) {} /**< Construct path object */ + UnitPath() : blockCount(0), map(NULL) {} /**< Construct path object */ virtual bool isBlocked() const {return blockCount >= maxBlockCount;} /**< is this path blocked */ virtual bool isEmpty() const {return list::empty();} /**< is path empty */ virtual bool isStuck() const {return false; } @@ -204,6 +212,9 @@ public: return result; } + virtual void setMap(Map *value) { map = value; } + virtual Map * getMap() { return map; } + virtual std::string toString() const; }; diff --git a/source/glest_game/world/map.cpp b/source/glest_game/world/map.cpp index d26d88aa..51775c06 100644 --- a/source/glest_game/world/map.cpp +++ b/source/glest_game/world/map.cpp @@ -129,9 +129,13 @@ int Map::getSurfaceCellArraySize() const { return (surfaceW * surfaceH); } +SurfaceCell *Map::getSurfaceCell(const Vec2i &sPos) const { + return getSurfaceCell(sPos.x, sPos.y); +} + SurfaceCell *Map::getSurfaceCell(int sx, int sy) const { int arrayIndex = sy * surfaceW + sx; - if(arrayIndex >= getSurfaceCellArraySize()) { + if(arrayIndex < 0 || arrayIndex >= getSurfaceCellArraySize()) { throw runtime_error("arrayIndex >= getSurfaceCellArraySize(), arrayIndex = " + intToStr(arrayIndex) + " surfaceW = " + intToStr(surfaceW) + " surfaceH = " + intToStr(surfaceH)); } else if(surfaceCells == NULL) { @@ -144,9 +148,13 @@ int Map::getCellArraySize() const { return (w * h); } +Cell *Map::getCell(const Vec2i &pos) const { + return getCell(pos.x, pos.y); +} + Cell *Map::getCell(int x, int y) const { int arrayIndex = y * w + x; - if(arrayIndex >= getCellArraySize()) { + if(arrayIndex < 0 || arrayIndex >= getCellArraySize()) { //abort(); throw runtime_error("arrayIndex >= getCellArraySize(), arrayIndex = " + intToStr(arrayIndex) + " w = " + intToStr(w) + " h = " + intToStr(h)); } @@ -565,6 +573,11 @@ bool Map::canMove(const Unit *unit, const Vec2i &pos1, const Vec2i &pos2, std::m //checks if a unit can move from between 2 cells using only visible cells (for pathfinding) bool Map::aproxCanMove(const Unit *unit, const Vec2i &pos1, const Vec2i &pos2, std::map > > > > *lookupCache) const { + if(isInside(pos1) == false || isInsideSurface(toSurfCoords(pos1)) == false || + isInside(pos2) == false || isInsideSurface(toSurfCoords(pos2)) == false) { + return false; + } + int size= unit->getType()->getSize(); int teamIndex= unit->getTeam(); Field field= unit->getCurrField(); @@ -632,9 +645,11 @@ bool Map::aproxCanMove(const Unit *unit, const Vec2i &pos1, const Vec2i &pos2, s else { for(int i = pos2.x; i < pos2.x + size; ++i) { for(int j = pos2.y; j < pos2.y + size; ++j) { - if(isInside(i, j)) { - if(getCell(i, j)->getUnit(unit->getCurrField()) != unit) { - if(isAproxFreeCell(Vec2i(i, j), field, teamIndex) == false) { + + Vec2i cellPos = Vec2i(i,j); + if(isInside(cellPos) && isInsideSurface(toSurfCoords(cellPos))) { + if(getCell(cellPos)->getUnit(unit->getCurrField()) != unit) { + if(isAproxFreeCell(cellPos, field, teamIndex) == false) { if(lookupCache != NULL) { (*lookupCache)[pos1][pos2][teamIndex][size][field]=false; } @@ -665,9 +680,8 @@ bool Map::aproxCanMove(const Unit *unit, const Vec2i &pos1, const Vec2i &pos2, s if(lookupCache != NULL) { (*lookupCache)[pos1][pos2][teamIndex][size][field]=true; } - - return true; } + return true; } Vec2i Map::computeRefPos(const Selection *selection) const { diff --git a/source/glest_game/world/map.h b/source/glest_game/world/map.h index 0a8bb8f6..5515d2b7 100755 --- a/source/glest_game/world/map.h +++ b/source/glest_game/world/map.h @@ -183,10 +183,10 @@ public: //get Cell *getCell(int x, int y) const; int getCellArraySize() const; - Cell *getCell(const Vec2i &pos) const {return getCell(pos.x, pos.y);} + Cell *getCell(const Vec2i &pos) const; int getSurfaceCellArraySize() const; SurfaceCell *getSurfaceCell(int sx, int sy) const; - SurfaceCell *getSurfaceCell(const Vec2i &sPos) const {return getSurfaceCell(sPos.x, sPos.y);} + SurfaceCell *getSurfaceCell(const Vec2i &sPos) const; int getW() const {return w;} int getH() const {return h;} int getSurfaceW() const {return surfaceW;}