From 0f5f4c07921e144565ec1897356b600d133b317d Mon Sep 17 00:00:00 2001 From: Mark Vejvoda Date: Fri, 8 Nov 2013 17:01:32 +0000 Subject: [PATCH] bugfix for nig's issue --- source/glest_game/ai/path_finder.cpp | 347 +-------------------------- source/glest_game/ai/path_finder.h | 159 +++++------- 2 files changed, 62 insertions(+), 444 deletions(-) diff --git a/source/glest_game/ai/path_finder.cpp b/source/glest_game/ai/path_finder.cpp index 9413befa..f5ea2c58 100644 --- a/source/glest_game/ai/path_finder.cpp +++ b/source/glest_game/ai/path_finder.cpp @@ -566,348 +566,6 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu // ==================== PRIVATE ==================== -bool PathFinder::addToOpenSet(Unit *unit, Node *node,const Vec2i finalPos, Vec2i sucPos, bool &nodeLimitReached,int maxNodeCount,Node **newNodeAdded, bool bypassChecks) { - bool result = false; - - *newNodeAdded=NULL; - //Vec2i sucPos= node->pos + Vec2i(i, j); - if(bypassChecks == true || - (canUnitMoveSoon(unit, node->pos, sucPos) == true && openPos(sucPos, factions[unit->getFactionIndex()]) == false)) { - //if node is not open and canMove then generate another node - Node *sucNode= newNode(factions[unit->getFactionIndex()],maxNodeCount); - if(sucNode != NULL) { - sucNode->pos= sucPos; - sucNode->heuristic= heuristic(sucNode->pos, finalPos); - sucNode->prev= node; - sucNode->next= NULL; - sucNode->exploredCell= map->getSurfaceCell(Map::toSurfCoords(sucPos))->isExplored(unit->getTeam()); - - static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); - MutexSafeWrapper safeMutex(factionMutex,mutexOwnerId); - - if(factions[unit->getFactionIndex()].openNodesList.find(sucNode->heuristic) == factions[unit->getFactionIndex()].openNodesList.end()) { - factions[unit->getFactionIndex()].openNodesList[sucNode->heuristic].clear(); - } - factions[unit->getFactionIndex()].openNodesList[sucNode->heuristic].push_back(sucNode); - factions[unit->getFactionIndex()].openPosList[sucNode->pos] = true; - - *newNodeAdded=sucNode; - result = true; - } - else { - nodeLimitReached= true; - } - } - return result; -} - - -direction PathFinder::directionOfMove(Vec2i to, Vec2i from) const { - if (from.x == to.x) { - if (from.y == to.y) - return 0; - else if (from.y < to.y) - return 4; - else // from.y > to.y - return 0; - } - else if (from.x < to.x) { - if (from.y == to.y) - return 2; - else if (from.y < to.y) - return 3; - else // from.y > to.y - return 1; - } - else { // from.x > to.x - if (from.y == to.y) - return 6; - else if (from.y < to.y) - return 5; - else // from.y > to.y - return 7; - } - -} - -direction PathFinder::directionWeCameFrom(Vec2i node, Vec2i nodeFrom) const { - direction result = NO_DIRECTION; - if(nodeFrom.x >= 0 && nodeFrom.y >= 0) { - result = directionOfMove(node, nodeFrom); - } - - //printf("directionWeCameFrom node [%s] nodeFrom [%s] result = %d\n",node.getString().c_str(),nodeFrom.getString().c_str(),result); - - return result; -} - -// is this coordinate contained within the map bounds? -bool PathFinder::contained(Vec2i c) { - return (map->isInside(c) == true && map->isInsideSurface(map->toSurfCoords(c)) == true); -} - -// is this coordinate within the map bounds, and also walkable? -bool PathFinder::isEnterable(Vec2i coord) { - //node node = getIndex (astar->bounds, coord); - //return contained(coord) && astar->grid[node]; - return contained(coord); -} -// the coordinate one tile in the given direction -Vec2i PathFinder::adjustInDirection(Vec2i c, int dir) { - // we want to implement "rotation" - that is, for instance, we can - // subtract 2 from the direction "north" and get "east" - // C's modulo operator doesn't quite behave the right way to do this, - // but for our purposes this kluge should be good enough - switch ((dir + 65536) % 8) { - case 0: return Vec2i(c.x, c.y - 1); - case 1: return Vec2i(c.x + 1, c.y - 1); - case 2: return Vec2i(c.x + 1, c.y ); - case 3: return Vec2i(c.x + 1, c.y + 1); - case 4: return Vec2i(c.x, c.y + 1); - case 5: return Vec2i(c.x - 1, c.y + 1); - case 6: return Vec2i(c.x - 1, c.y); - case 7: return Vec2i(c.x - 1, c.y - 1); - } - return Vec2i( -1, -1 ); -} - -bool PathFinder::directionIsDiagonal(direction dir) const { - return (dir % 2) != 0; -} - -// logical implication operator -bool PathFinder::implies(bool a, bool b) const { - return a ? b : true; -} - -directionset PathFinder::addDirectionToSet(directionset dirs, direction dir) const { - return dirs | 1 << dir; -} - -directionset PathFinder::forcedNeighbours(Vec2i coord,direction dir) { - if (dir == NO_DIRECTION) - return 0; - - directionset dirs = 0; -#define ENTERABLE(n) isEnterable(adjustInDirection(coord, (dir + (n)) % 8)) - if (directionIsDiagonal(dir)) { - if (!implies (ENTERABLE (6), ENTERABLE (5))) - dirs = addDirectionToSet (dirs, (dir + 6) % 8); - if (!implies (ENTERABLE (2), ENTERABLE (3))) - dirs = addDirectionToSet (dirs, (dir + 2) % 8); - } - else { - if (!implies (ENTERABLE (7), ENTERABLE (6))) - dirs = addDirectionToSet (dirs, (dir + 7) % 8); - if (!implies (ENTERABLE (1), ENTERABLE (2))) - dirs = addDirectionToSet (dirs, (dir + 1) % 8); - } -#undef ENTERABLE - return dirs; -} - -directionset PathFinder::naturalNeighbours(direction dir) const { - if (dir == NO_DIRECTION) - return 255; - - directionset dirs = 0; - dirs = addDirectionToSet (dirs, dir); - if (directionIsDiagonal (dir)) { - dirs = addDirectionToSet (dirs, (dir + 1) % 8); - dirs = addDirectionToSet (dirs, (dir + 7) % 8); - } - return dirs; -} - -// return and remove a direction from the set -// returns NO_DIRECTION if the set was empty -direction PathFinder::nextDirectionInSet(directionset *dirs) const { - for (int i = 0; i < 8; i++) { - char bit = 1 << i; - if (*dirs & bit) { - *dirs ^= bit; - return i; - } - } - return NO_DIRECTION; -} - -// directly translated from "algorithm 2" in the paper -Vec2i PathFinder::jump(Vec2i dest, direction dir, Vec2i start,std::vector &path, int pathLength) { - Vec2i coord = adjustInDirection(start, dir); - //printf("jump dir [%u] start [%s] coord [%s] dest [%s]\n",dir,start.getString().c_str(),coord.getString().c_str(),dest.getString().c_str()); - - if (!isEnterable(coord)) - return Vec2i(-1,-1); - - if(path.size() > max(300,pathLength*2)) { - //if(path.size() > 2000) { - //printf("path.size() > pathLength [%d]\n",pathLength); - //return Vec2i(-1,-1); - return coord; - } - path.push_back(coord); - - //int node = getIndex (astar->bounds, coord); - if (coord == dest || forcedNeighbours(coord, dir)) { - //path.push_back(coord); - //printf("jump #1 = %d [%d]\n",(int)path.size(),pathLength); - return coord; - } - - if(directionIsDiagonal(dir)) { - Vec2i next = jump(dest, (dir + 7) % 8, coord,path,pathLength); - if (next.x >= 0) { - //path.push_back(coord); - //printf("jump #2 = %d [%d]\n",(int)path.size(),pathLength); - return coord; - } - next = jump(dest, (dir + 1) % 8, coord, path,pathLength); - if (next.x >= 0) { - //path.push_back(coord); - //printf("jump #3 = %d [%d]\n",(int)path.size(),pathLength); - return coord; - } - } - //else { - //path.push_back(coord); - //} - return jump(dest, dir, coord, path,pathLength); -} - - -void PathFinder::astarJPS(std::map cameFrom, Node *& node, - const Vec2i & finalPos, std::map closedNodes, - std::map ,bool> canAddNode, Unit *& unit, - bool & nodeLimitReached, int & maxNodeCount) { - Vec2i cameFromPos(-1, -1); - if(cameFrom.find(node->pos) != cameFrom.end()) { - cameFromPos = cameFrom[node->pos]; - } - direction from = directionWeCameFrom(node->pos, cameFromPos); - directionset dirs = forcedNeighbours(node->pos, from) | naturalNeighbours(from); - bool canAddEntirePath = false; - bool foundQuickRoute = false; - for (int dir = nextDirectionInSet(&dirs); dir != NO_DIRECTION; dir = nextDirectionInSet(&dirs)) { - //for (int dir = 0; dir < 8; dir++) { - std::vector path; - Vec2i newNode = jump(finalPos, dir, node->pos,path,(int)node->pos.dist(finalPos)); - //Vec2i newNode = adjustInDirection(node->pos, dir); - - //printf("examine node from [%u][%u] - current node [%s] next possible node [%s]\n",from,dirs,node->pos.getString().c_str(),newNode.getString().c_str()); - - //coord_t newCoord = getCoord (bounds, newNode); - - // this'll also bail out if jump() returned -1 - if (!contained(newNode)) - continue; - - if(closedNodes.find(newNode) != closedNodes.end()) - continue; - //if(factions[unit->getFactionIndex()].closedNodesList.find(node->heuristic) == factions[unit->getFactionIndex()].closedNodesList.end()) { - - //addToOpenSet (&astar, newNode, node); - //printf("JPS #2 node->pos [%s] newNode [%s] path.size() [%d] pos [%s]\n",node->pos.getString().c_str(),newNode.getString().c_str(),(int)path.size(),path[0].getString().c_str()); - - Vec2i newPath = path[0]; - - //bool canUnitMoveToCell = map->aproxCanMove(unit, node->pos, newPath); - //bool posOpen = (openPos(newPath, factions[unit->getFactionIndex()]) == false); - //bool isFreeCell = map->isFreeCell(newPath,unit->getType()->getField()); - - if(canAddNode.find(make_pair(node->pos,newPath)) == canAddNode.end()) { - Node *newNode=NULL; - if(addToOpenSet(unit, node, finalPos, newPath, nodeLimitReached, maxNodeCount,&newNode,false) == true) { - //cameFrom = node->pos; - cameFrom[newPath]=node->pos; - foundQuickRoute = true; - - if(path.size() > 1 && path[path.size()-1] == finalPos) { - canAddEntirePath = true; - for(unsigned int x = 1; x < path.size(); ++x) { - Vec2i futureNode = path[x]; - - bool canUnitMoveToCell = canUnitMoveSoon(unit, newNode->pos, futureNode); - if(canUnitMoveToCell != true || openPos(futureNode, factions[unit->getFactionIndex()]) == true) { - canAddEntirePath = false; - canAddNode[make_pair(node->pos,futureNode)]=false; - //printf("COULD NOT ADD ENTIRE PATH! canUnitMoveToCell = %d\n",canUnitMoveToCell); - break; - } - } - if(canAddEntirePath == true) { - //printf("add node - ENTIRE PATH!\n"); - - for(unsigned int x = 1; x < path.size(); ++x) { - Vec2i futureNode = path[x]; - - Node *newNode2=NULL; - addToOpenSet(unit, newNode, finalPos, futureNode, nodeLimitReached, maxNodeCount,&newNode2, true); - newNode=newNode2; - } - - //Node *result = factions[unit->getFactionIndex()].openNodesList.begin()->second[0]; - //if(result->pos == finalPos || result->exploredCell == false) { - // printf("Will break out of pathfinding now!\n"); - //} - } - } - //printf("add node - current node [%s] next possible node [%s] canUnitMoveToCell [%d] posOpen [%d] isFreeCell [%d]\n",node->pos.getString().c_str(),newPath.getString().c_str(),canUnitMoveToCell,posOpen,isFreeCell); - } - else { - //printf("COULD NOT add node - current node [%s] next possible node [%s] canUnitMoveToCell [%d] posOpen [%d] isFreeCell [%d]\n",node->pos.getString().c_str(),newPath.getString().c_str(),canUnitMoveToCell,posOpen,isFreeCell); - canAddNode[make_pair(node->pos,newPath)]=false; - } - } - - //if(canAddEntirePath == true) { - // break; - //} - } - if(foundQuickRoute == false) { - for (int dir = 0; dir < 8; dir++) { - Vec2i newNode = adjustInDirection(node->pos, dir); - - //printf("examine node from [%u][%u] - current node [%s] next possible node [%s]\n",from,dirs,node->pos.getString().c_str(),newNode.getString().c_str()); - - //coord_t newCoord = getCoord (bounds, newNode); - - // this'll also bail out if jump() returned -1 - if (!contained(newNode)) - continue; - - if(closedNodes.find(newNode) != closedNodes.end()) - continue; - //if(factions[unit->getFactionIndex()].closedNodesList.find(node->heuristic) == factions[unit->getFactionIndex()].closedNodesList.end()) { - - //addToOpenSet (&astar, newNode, node); - //printf("JPS #3 node->pos [%s] newNode [%s]\n",node->pos.getString().c_str(),newNode.getString().c_str()); - - Vec2i newPath = newNode; - - //bool canUnitMoveToCell = map->aproxCanMove(unit, node->pos, newPath); - //bool posOpen = (openPos(newPath, factions[unit->getFactionIndex()]) == false); - //bool isFreeCell = map->isFreeCell(newPath,unit->getType()->getField()); - - if(canAddNode.find(make_pair(node->pos,newPath)) == canAddNode.end()) { - Node *newNode=NULL; - if(addToOpenSet(unit, node, finalPos, newPath, nodeLimitReached, maxNodeCount,&newNode, false) == true) { - //cameFrom = node->pos; - cameFrom[newPath]=node->pos; - //foundQuickRoute = true; - - //printf("#2 add node - current node [%s] next possible node [%s] canUnitMoveToCell [%d] posOpen [%d] isFreeCell [%d]\n",node->pos.getString().c_str(),newPath.getString().c_str(),canUnitMoveToCell,posOpen,isFreeCell); - } - else { - //printf("#2 COULD NOT add node - current node [%s] next possible node [%s] canUnitMoveToCell [%d] posOpen [%d] isFreeCell [%d]\n",node->pos.getString().c_str(),newPath.getString().c_str(),canUnitMoveToCell,posOpen,isFreeCell); - canAddNode[make_pair(node->pos,newPath)]=false; - } - } - } - } -} - - //route a unit using A* algorithm TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout, int frameIndex, int maxNodeCount, uint32 *searched_node_count) { @@ -1385,9 +1043,6 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout int whileLoopCount = 0; if(nodeLimitReached == false) { codeLocation = "32"; - //printf("\n\n\n====== START AStar-JPS Pathfinder start [%s] end [%s]\n",unitPos.getString().c_str(),finalPos.getString().c_str()); - - const bool tryJPSPathfinder = false; if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; @@ -1397,7 +1052,7 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout } doAStarPathSearch(nodeLimitReached, whileLoopCount, unitFactionIndex, - pathFound, node, finalPos, tryJPSPathfinder, + pathFound, node, finalPos, closedNodes, cameFrom, canAddNode, unit, maxNodeCount,frameIndex); codeLocation = "33"; diff --git a/source/glest_game/ai/path_finder.h b/source/glest_game/ai/path_finder.h index 7f060434..fa3ab275 100644 --- a/source/glest_game/ai/path_finder.h +++ b/source/glest_game/ai/path_finder.h @@ -280,72 +280,36 @@ private: void processNearestFreePos(const Vec2i &finalPos, int i, int j, int size, Field field, int teamIndex,Vec2i unitPos, Vec2i &nearestPos, float &nearestDist); int getPathFindExtendRefreshNodeCount(int factionIndex); - - void astarJPS(std::map cameFrom, Node *& node, - const Vec2i & finalPos, std::map closedNodes, - std::map ,bool> canAddNode, Unit *& unit, - bool & nodeLimitReached, int & maxNodeCount); - - bool contained(Vec2i c); - direction directionOfMove(Vec2i to, Vec2i from) const; - direction directionWeCameFrom(Vec2i node, Vec2i nodeFrom) const; - bool isEnterable(Vec2i coord); - Vec2i adjustInDirection(Vec2i c, int dir); - bool directionIsDiagonal(direction dir) const; - directionset forcedNeighbours(Vec2i coord,direction dir); - bool implies(bool a, bool b) const; - directionset addDirectionToSet(directionset dirs, direction dir) const; - directionset naturalNeighbours(direction dir) const; - direction nextDirectionInSet(directionset *dirs) const; - Vec2i jump(Vec2i dest, direction dir, Vec2i start,std::vector &path,int pathLength); - bool addToOpenSet(Unit *unit, Node *node,const Vec2i finalPos, Vec2i sucPos, bool &nodeLimitReached,int maxNodeCount,Node **newNodeAdded,bool bypassChecks); - - //bool canUnitMoveSoon(const Unit *unit, const Vec2i &pos1, const Vec2i &pos2); inline bool canUnitMoveSoon(const Unit *unit, const Vec2i &pos1, const Vec2i &pos2) { - //bool result = true; - - // std::map > &badCellList = factions[unit->getFactionIndex()].badCellList; - // if(badCellList.find(unit->getType()->getSize()) != badCellList.end()) { - // std::map &badFieldList = badCellList[unit->getType()->getSize()]; - // if(badFieldList.find(unit->getCurrField()) != badFieldList.end()) { - // BadUnitNodeList &badList = badFieldList[unit->getCurrField()]; - // if(badList.isPosBad(pos1,pos2) == true) { - // result = false; - // } - // } - // } - // if(result == true) { - // //bool canUnitMoveToCell = map->canMove(unit, unitPos, pos); - // //bool canUnitMoveToCell = map->aproxCanMove(unit, unitPos, pos); - // result = map->aproxCanMoveSoon(unit, pos1, pos2); - // if(result == false) { - // badCellList[unit->getType()->getSize()][unit->getCurrField()].badPosList[pos1][pos2]=false; - // } - // } - bool result = map->aproxCanMoveSoon(unit, pos1, pos2); return result; } inline void doAStarPathSearch(bool & nodeLimitReached, int & whileLoopCount, int & unitFactionIndex, bool & pathFound, Node *& node, const Vec2i & finalPos, - const bool tryJPSPathfinder, std::map closedNodes, + std::map closedNodes, std::map cameFrom, std::map , bool> canAddNode, Unit *& unit, int & maxNodeCount, int curFrameIndex) { - //Chrono chrono; - //if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start(); - //chrono.start(); + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutexFaction(factionMutex,mutexOwnerId); FactionState &factionState = factions[unitFactionIndex]; + + safeMutexFaction.ReleaseLock(true); + while(nodeLimitReached == false) { whileLoopCount++; + + safeMutexFaction.Lock(); if(factionState.openNodesList.empty() == true) { + safeMutexFaction.ReleaseLock(true); pathFound = false; break; } node = minHeuristicFastLookup(factionState); if(node->pos == finalPos || node->exploredCell == false) { + safeMutexFaction.ReleaseLock(true); pathFound = true; break; } @@ -367,71 +331,70 @@ private: // } // } - if(tryJPSPathfinder == true) { - closedNodes[node->pos] = true; - } if(factionState.closedNodesList.find(node->heuristic) == factionState.closedNodesList.end()) { factionState.closedNodesList[node->heuristic].clear(); //factionState.closedNodesList[node->heuristic].reserve(PathFinder::pathFindNodesMax); } factionState.closedNodesList[node->heuristic].push_back(node); factionState.openPosList[node->pos] = true; - if(tryJPSPathfinder == true) { - astarJPS(cameFrom, node, finalPos, closedNodes, canAddNode, unit, nodeLimitReached, maxNodeCount); + safeMutexFaction.ReleaseLock(true); + + int failureCount = 0; + int cellCount = 0; + + safeMutexFaction.Lock(); + int tryDirection = factionState.random.randRange(0, 3); + safeMutexFaction.ReleaseLock(true); + + if(tryDirection == 3) { + for(int i = 1;i >= -1 && nodeLimitReached == false;--i) { + for(int j = -1;j <= 1 && nodeLimitReached == false;++j) { + safeMutexFaction.Lock(); + if(processNode(unit, node, finalPos, i, j, nodeLimitReached, maxNodeCount) == false) { + failureCount++; + } + safeMutexFaction.ReleaseLock(true); + cellCount++; + } + } + } + else if(tryDirection == 2) { + for(int i = -1;i <= 1 && nodeLimitReached == false;++i) { + for(int j = 1;j >= -1 && nodeLimitReached == false;--j) { + safeMutexFaction.Lock(); + if(processNode(unit, node, finalPos, i, j, nodeLimitReached, maxNodeCount) == false) { + failureCount++; + } + safeMutexFaction.ReleaseLock(true); + cellCount++; + } + } + } + else if(tryDirection == 1) { + for(int i = -1;i <= 1 && nodeLimitReached == false;++i) { + for(int j = -1;j <= 1 && nodeLimitReached == false;++j) { + safeMutexFaction.Lock(); + if(processNode(unit, node, finalPos, i, j, nodeLimitReached, maxNodeCount) == false) { + failureCount++; + } + safeMutexFaction.ReleaseLock(true); + cellCount++; + } + } } else { - int failureCount = 0; - int cellCount = 0; - int tryDirection = factionState.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) { - if(processNode(unit, node, finalPos, i, j, nodeLimitReached, maxNodeCount) == false) { - failureCount++; - } - cellCount++; - } - } - } - else if(tryDirection == 2) { - for(int i = -1;i <= 1 && nodeLimitReached == false;++i) { - for(int j = 1;j >= -1 && nodeLimitReached == false;--j) { - if(processNode(unit, node, finalPos, i, j, nodeLimitReached, maxNodeCount) == false) { - failureCount++; - } - cellCount++; - } - } - } - else if(tryDirection == 1) { - for(int i = -1;i <= 1 && nodeLimitReached == false;++i) { - for(int j = -1;j <= 1 && nodeLimitReached == false;++j) { - if(processNode(unit, node, finalPos, i, j, nodeLimitReached, maxNodeCount) == false) { - failureCount++; - } - cellCount++; - } - } - } - else { - for(int i = 1;i >= -1 && nodeLimitReached == false;--i) { - for(int j = 1;j >= -1 && nodeLimitReached == false;--j) { - if(processNode(unit, node, finalPos, i, j, nodeLimitReached, maxNodeCount) == false) { - failureCount++; - } - cellCount++; + for(int i = 1;i >= -1 && nodeLimitReached == false;--i) { + for(int j = 1;j >= -1 && nodeLimitReached == false;--j) { + safeMutexFaction.Lock(); + if(processNode(unit, node, finalPos, i, j, nodeLimitReached, maxNodeCount) == false) { + failureCount++; } + safeMutexFaction.ReleaseLock(true); + cellCount++; } } } } - - //!!! - //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,factionState.nodePoolCount); - //if(chrono.getMillis() > 1) { - //printf("AStar for unit [%d - %s] took msecs: %lld nodeLimitReached = %d whileLoopCount = %d nodePoolCount = %d curFrameIndex = %d travel distance = %f\n",unit->getId(),unit->getFullName().c_str(), (long long int)chrono.getMillis(),nodeLimitReached,whileLoopCount,factionState.nodePoolCount,curFrameIndex,unit->getPos().dist(finalPos)); - //} } };