diff --git a/source/glest_game/ai/path_finder.cpp b/source/glest_game/ai/path_finder.cpp index 13f11338..4049498f 100644 --- a/source/glest_game/ai/path_finder.cpp +++ b/source/glest_game/ai/path_finder.cpp @@ -19,6 +19,7 @@ #include "unit.h" #include "unit_type.h" #include "platform_common.h" +#include "command.h" #include "leak_dumper.h" using namespace std; @@ -35,24 +36,26 @@ namespace Glest{ namespace Game{ // ===================== PUBLIC ======================== const int PathFinder::maxFreeSearchRadius= 10; -const int PathFinder::pathFindNodesMax= 400; -const int PathFinder::pathFindRefresh= 10; +//const int PathFinder::pathFindNodesMax= 400; +const int PathFinder::pathFindNodesMax= 500; +//const int PathFinder::pathFindRefresh= 10; +const int PathFinder::pathFindRefresh= 5; -PathFinder::PathFinder(){ +PathFinder::PathFinder() { //nodePool= NULL; nodePool.clear(); map=NULL; } -PathFinder::PathFinder(const Map *map){ +PathFinder::PathFinder(const Map *map) { //nodePool= NULL; nodePool.clear(); map=NULL; init(map); } -void PathFinder::init(const Map *map){ +void PathFinder::init(const Map *map) { //if(nodePool != NULL) { // delete [] nodePool; // nodePool = NULL; @@ -70,16 +73,28 @@ PathFinder::~PathFinder(){ map=NULL; } -TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos){ +TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos) { if(map == NULL) { throw runtime_error("map == NULL"); } //route cache UnitPathInterface *path= unit->getPath(); - if(finalPos==unit->getPos()) { + if(finalPos == unit->getPos()) { //if arrived unit->setCurrSkill(scStop); + + 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: arrived#1 at pos: %s, command [%s]",finalPos.getString().c_str(),commandDesc.c_str()); + unit->setCurrentUnitTitle(szBuf); + } + return tsArrived; } else { @@ -113,9 +128,56 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos){ TravelState ts= aStar(unit, finalPos); //post actions - switch(ts){ + switch(ts) { case tsBlocked: case tsArrived: + // The unit is stuck (not only blocked but unable to go anywhere for a while) + // We will try to bail out of the immediate area + if( ts == tsBlocked && unit->getInBailOutAttempt() == false && + path->isStuck() == true) { + unit->setInBailOutAttempt(true); + + // Try to bail out up to 20 cells away + for(int bailoutX = -20; bailoutX <= 20 && ts == tsBlocked; ++bailoutX) { + for(int bailoutY = -20; bailoutY <= 20 && ts == tsBlocked; ++bailoutY) { + const Vec2i newFinalPos = finalPos + Vec2i(bailoutX,bailoutY); + if(map->canMove(unit, unit->getPos(), newFinalPos)) { + ts= aStar(unit, newFinalPos); + if(ts == tsMoving) { + unit->setInBailOutAttempt(false); + + if(dynamic_cast(path) != NULL) { + UnitPathBasic *basicPath = dynamic_cast(path); + Vec2i pos= basicPath->pop(); + if(map->canMove(unit, unit->getPos(), pos)) { + unit->setTargetPos(pos); + } + else { + unit->setCurrSkill(scStop); + return tsBlocked; + } + } + else if(dynamic_cast(path) != NULL) { + UnitPath *advPath = dynamic_cast(path); + Vec2i pos= advPath->peek(); + if(map->canMove(unit, unit->getPos(), pos)) { + advPath->pop(); + unit->setTargetPos(pos); + } + else { + unit->setCurrSkill(scStop); + return tsBlocked; + } + } + else { + throw runtime_error("unsupported or missing path finder detected!"); + } + } + } + } + } + unit->setInBailOutAttempt(false); + } unit->setCurrSkill(scStop); break; case tsMoving: @@ -167,7 +229,17 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos){ const Vec2i finalPos= computeNearestFreePos(unit, targetPos); //if arrived - if(finalPos==unit->getPos()){ + if(finalPos == unit->getPos()) { + 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: arrived#2 at pos: %s, command [%s]",targetPos.getString().c_str(),commandDesc.c_str()); + unit->setCurrentUnitTitle(szBuf); + } return tsArrived; } @@ -175,7 +247,11 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos){ //a) push starting pos into openNodes Node *firstNode= newNode(); - assert(firstNode!=NULL);; + assert(firstNode != NULL); + if(firstNode == NULL) { + throw runtime_error("firstNode == NULL"); + } + firstNode->next= NULL; firstNode->prev= NULL; const Vec2i unitPos = unit->getPos(); @@ -191,10 +267,10 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos){ //if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - while(!nodeLimitReached){ + while(nodeLimitReached == false) { //b1) is open nodes is empty => failed to find the path - if(openNodes.empty()){ + if(openNodes.empty() == true) { pathFound= false; break; } @@ -213,13 +289,13 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos){ //add all succesors that are not in closedNodes or openNodes to openNodes closedNodes.push_back(node); openNodes.erase(it); - for(int i=-1; i<=1 && !nodeLimitReached; ++i){ - for(int j=-1; j<=1 && !nodeLimitReached; ++j){ + for(int i = -1; i <= 1 && nodeLimitReached == false; ++i) { + for(int j = -1; j <= 1 && nodeLimitReached == false; ++j) { Vec2i sucPos= node->pos + Vec2i(i, j); - if(openPos(sucPos) == false && map->aproxCanMove(unit, node->pos, sucPos)){ + if(openPos(sucPos) == false && map->aproxCanMove(unit, node->pos, sucPos)) { //if node is not open and canMove then generate another node Node *sucNode= newNode(); - if(sucNode!=NULL){ + if(sucNode != NULL) { sucNode->pos= sucPos; sucNode->heuristic= heuristic(sucNode->pos, finalPos); sucNode->prev= node; @@ -227,7 +303,7 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos){ sucNode->exploredCell= map->getSurfaceCell(Map::toSurfCoords(sucPos))->isExplored(unit->getTeam()); openNodes.push_back(sucNode); } - else{ + else { nodeLimitReached= true; } } @@ -240,9 +316,9 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos){ Node *lastNode= node; //if consumed all nodes find best node (to avoid strange behaviour) - if(nodeLimitReached){ - for(Nodes::iterator it= closedNodes.begin(); it!=closedNodes.end(); ++it){ - if((*it)->heuristic < lastNode->heuristic){ + if(nodeLimitReached == true) { + for(Nodes::iterator it= closedNodes.begin(); it != closedNodes.end(); ++it) { + if((*it)->heuristic < lastNode->heuristic) { lastNode= *it; } } @@ -251,10 +327,22 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos){ //if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); //check results of path finding - TravelState ts; + TravelState ts = tsImpossible; UnitPathInterface *path= unit->getPath(); - if(pathFound==false || lastNode==firstNode){ + if(pathFound == false || lastNode == firstNode) { //blocked + 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: blocked, cmd [%s] pos: %s, dest pos: %s, reason A= %d, B= %d, C= %d, D= %d, E= %d, F = %d",commandDesc.c_str(),unit->getPos().getString().c_str(), targetPos.getString().c_str(),pathFound,(lastNode == firstNode),path->getBlockCount(), path->isBlocked(), nodeLimitReached,path->isStuck()); + unit->setCurrentUnitTitle(szBuf); + } + ts= tsBlocked; path->incBlockCount(); } @@ -264,7 +352,7 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos){ //build next pointers Node *currNode= lastNode; - while(currNode->prev!=NULL){ + while(currNode->prev != NULL) { currNode->prev->next= currNode; currNode= currNode->prev; } @@ -272,9 +360,21 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos){ path->clear(); currNode= firstNode; - for(int i=0; currNode->next!=NULL && inext, i++){ + for(int i=0; currNode->next != NULL && i < pathFindRefresh; currNode= currNode->next, i++) { path->add(currNode->next->pos); } + + 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(chrono.getMillis() > 2) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); @@ -286,8 +386,8 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos){ return ts; } -PathFinder::Node *PathFinder::newNode(){ - if(nodePoolCount < pathFindNodesMax){ +PathFinder::Node *PathFinder::newNode() { + if(nodePoolCount < pathFindNodesMax) { Node *node= &nodePool[nodePoolCount]; nodePoolCount++; return node; @@ -295,39 +395,39 @@ PathFinder::Node *PathFinder::newNode(){ return NULL; } -Vec2i PathFinder::computeNearestFreePos(const Unit *unit, const Vec2i &finalPos){ +Vec2i PathFinder::computeNearestFreePos(const Unit *unit, const Vec2i &finalPos) { if(map == NULL) { throw runtime_error("map == NULL"); } //unit data - Vec2i unitPos= unit->getPos(); int size= unit->getType()->getSize(); Field field= unit->getCurrField(); int teamIndex= unit->getTeam(); //if finalPos is free return it - if(map->isAproxFreeCells(finalPos, size, field, teamIndex)){ + if(map->isAproxFreeCells(finalPos, size, field, teamIndex)) { return finalPos; } //find nearest pos + Vec2i unitPos= unit->getPos(); Vec2i nearestPos= unitPos; float nearestDist= unitPos.dist(finalPos); - for(int i= -maxFreeSearchRadius; i<=maxFreeSearchRadius; ++i){ - for(int j= -maxFreeSearchRadius; j<=maxFreeSearchRadius; ++j){ + for(int i= -maxFreeSearchRadius; i <= maxFreeSearchRadius; ++i) { + for(int j= -maxFreeSearchRadius; j <= maxFreeSearchRadius; ++j) { Vec2i currPos= finalPos + Vec2i(i, j); - if(map->isAproxFreeCells(currPos, size, field, teamIndex)){ + if(map->isAproxFreeCells(currPos, size, field, teamIndex)) { float dist= currPos.dist(finalPos); //if nearer from finalPos - if(distheuristic < (*minNodeIt)->heuristic){ minNodeIt= it; } @@ -357,17 +460,17 @@ PathFinder::Nodes::iterator PathFinder::minHeuristic(){ return minNodeIt; } -bool PathFinder::openPos(const Vec2i &sucPos){ +bool PathFinder::openPos(const Vec2i &sucPos) { - for(Nodes::reverse_iterator it= closedNodes.rbegin(); it!=closedNodes.rend(); ++it){ - if(sucPos==(*it)->pos){ + for(Nodes::reverse_iterator it= closedNodes.rbegin(); it != closedNodes.rend(); ++it) { + if(sucPos == (*it)->pos) { return true; } } //use reverse iterator to find a node faster - for(Nodes::reverse_iterator it= openNodes.rbegin(); it!=openNodes.rend(); ++it){ - if(sucPos==(*it)->pos){ + for(Nodes::reverse_iterator it= openNodes.rbegin(); it != openNodes.rend(); ++it) { + if(sucPos == (*it)->pos) { return true; } } diff --git a/source/glest_game/facilities/game_util.cpp b/source/glest_game/facilities/game_util.cpp index 9835d684..6fe42d16 100644 --- a/source/glest_game/facilities/game_util.cpp +++ b/source/glest_game/facilities/game_util.cpp @@ -26,7 +26,7 @@ using namespace Shared::Platform; namespace Glest { namespace Game { const string mailString = "contact_game@glest.org"; -const string glestVersionString = "v3.3.7.2"; +const string glestVersionString = "v3.4.0-dev"; const string SVN_Rev = "$Rev$"; string getCrashDumpFileName(){ diff --git a/source/glest_game/game/game.cpp b/source/glest_game/game/game.cpp index dc71c429..d440891d 100644 --- a/source/glest_game/game/game.cpp +++ b/source/glest_game/game/game.cpp @@ -1602,9 +1602,9 @@ void Game::render2d(){ } renderer.renderUnitTitles(coreData.getMenuFontNormal(),Vec3f(1.0f)); } - else if(renderer.getAllowRenderUnitTitles() == true) { - renderer.setAllowRenderUnitTitles(false); - } + //else if(renderer.getAllowRenderUnitTitles() == true) { + // renderer.setAllowRenderUnitTitles(false); + //} //network status if(renderNetworkStatus == true) { diff --git a/source/glest_game/main/main.cpp b/source/glest_game/main/main.cpp index a94296ae..50765a6a 100644 --- a/source/glest_game/main/main.cpp +++ b/source/glest_game/main/main.cpp @@ -758,6 +758,11 @@ int glestMain(int argc, char** argv){ Renderer &renderer= Renderer::getInstance(); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] OpenGL Info:\n%s\n",__FILE__,__FUNCTION__,__LINE__,renderer.getGlInfo().c_str()); + if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled == true) { + renderer.setAllowRenderUnitTitles(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled); + SystemFlags::OutputDebug(SystemFlags::debugPathFinder,"In [%s::%s Line: %d] renderer.setAllowRenderUnitTitles = %d\n",__FILE__,__FUNCTION__,__LINE__,SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled); + } + if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_OPENGL_INFO]) == true) { //Renderer &renderer= Renderer::getInstance(); printf("%s",renderer.getGlInfo().c_str()); diff --git a/source/glest_game/type_instances/unit.cpp b/source/glest_game/type_instances/unit.cpp index 9c27bb48..42ee3d31 100644 --- a/source/glest_game/type_instances/unit.cpp +++ b/source/glest_game/type_instances/unit.cpp @@ -49,6 +49,10 @@ bool UnitPathBasic::isBlocked() const { return blockCount >= maxBlockCount; } +bool UnitPathBasic::isStuck() const { + return (isBlocked() == true && blockCount >= (maxBlockCount * 2)); +} + void UnitPathBasic::clear() { pathQueue.clear(); blockCount= 0; @@ -178,6 +182,7 @@ Unit::Unit(int id, UnitPathInterface *unitpath, const Vec2i &pos, const UnitType this->visible = true; this->retryCurrCommandCount=0; this->screenPos = Vec3f(0.0); + this->inBailOutAttempt = false; level= NULL; loadType= NULL; @@ -1784,6 +1789,8 @@ std::string Unit::toString() const { result += "currentUnitTitle = " + currentUnitTitle + "\n"; + result += "inBailOutAttempt = " + intToStr(inBailOutAttempt) + "\n"; + //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); return result; diff --git a/source/glest_game/type_instances/unit.h b/source/glest_game/type_instances/unit.h index b5f6426a..d168016b 100644 --- a/source/glest_game/type_instances/unit.h +++ b/source/glest_game/type_instances/unit.h @@ -104,12 +104,15 @@ public: virtual bool isBlocked() const = 0; virtual bool isEmpty() const = 0; + virtual bool isStuck() const = 0; virtual void clear() = 0; virtual void clearBlockCount() = 0; virtual void incBlockCount() = 0; virtual void add(const Vec2i &path) = 0; //virtual Vec2i pop() = 0; + virtual int getBlockCount() const = 0; + virtual int getQueueCount() const = 0; virtual std::string toString() const = 0; }; @@ -126,12 +129,15 @@ public: UnitPathBasic(); virtual bool isBlocked() const; virtual bool isEmpty() const; + virtual bool isStuck() const; virtual void clear(); virtual void clearBlockCount() { blockCount = 0; } virtual void incBlockCount(); virtual void add(const Vec2i &path); Vec2i pop(); + virtual int getBlockCount() const { return blockCount; } + virtual int getQueueCount() const { return pathQueue.size(); } virtual std::string toString() const; }; @@ -152,7 +158,9 @@ private: public: UnitPath() : blockCount(0) {} /**< 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 isEmpty() const {return list::empty();} /**< is path empty */ + virtual bool isStuck() const {return false; } + int size() const {return list::size();} /**< size of path */ virtual void clear() {list::clear(); blockCount = 0;} /**< clear the path */ virtual void clearBlockCount() { blockCount = 0; } @@ -172,7 +180,8 @@ public: //virtual Vec2i pop() { Vec2i p= front(); erase(begin()); return p; } /**< pop the next position off the path */ void pop() { erase(begin()); } /**< pop the next position off the path */ #endif - int getBlockCount() const { return blockCount; } + virtual int getBlockCount() const { return blockCount; } + virtual int getQueueCount() const { return this->size(); } virtual std::string toString() const; }; @@ -271,6 +280,8 @@ private: Vec3f screenPos; string currentUnitTitle; + bool inBailOutAttempt; + static Game *game; public: @@ -412,6 +423,9 @@ public: void exploreCells(); + bool getInBailOutAttempt() const { return inBailOutAttempt; } + void setInBailOutAttempt(bool value) { inBailOutAttempt = value; } + std::string toString() const; private: diff --git a/source/shared_lib/sources/platform/common/platform_common.cpp b/source/shared_lib/sources/platform/common/platform_common.cpp index afa80f69..8c1b2c7b 100644 --- a/source/shared_lib/sources/platform/common/platform_common.cpp +++ b/source/shared_lib/sources/platform/common/platform_common.cpp @@ -66,8 +66,8 @@ namespace Shared { namespace PlatformCommon { namespace Private { bool shouldBeFullscreen = false; -int ScreenWidth; -int ScreenHeight; +int ScreenWidth = 800; +int ScreenHeight = 600; }