From 07f56669b7351fa0d39c766f53127759264abbd2 Mon Sep 17 00:00:00 2001 From: Mark Vejvoda Date: Fri, 18 Mar 2011 03:53:06 +0000 Subject: [PATCH] - attempt to see if threaded pathfinding will work and if it improves performance --- source/glest_game/ai/path_finder.cpp | 335 ++++++--- source/glest_game/ai/path_finder.h | 47 +- source/glest_game/type_instances/faction.cpp | 206 ++++- source/glest_game/type_instances/faction.h | 28 + source/glest_game/type_instances/unit.cpp | 60 +- source/glest_game/type_instances/unit.h | 3 +- source/glest_game/types/command_type.cpp | 40 +- source/glest_game/types/command_type.h | 48 +- source/glest_game/world/unit_updater.cpp | 746 ++++++++++--------- source/glest_game/world/unit_updater.h | 23 +- source/glest_game/world/world.cpp | 40 +- source/glest_game/world/world.h | 2 + 12 files changed, 1054 insertions(+), 524 deletions(-) diff --git a/source/glest_game/ai/path_finder.cpp b/source/glest_game/ai/path_finder.cpp index 886cec75..37b56705 100644 --- a/source/glest_game/ai/path_finder.cpp +++ b/source/glest_game/ai/path_finder.cpp @@ -45,12 +45,19 @@ const int PathFinder::pathFindBailoutRadius = 20; PathFinder::PathFinder() { - nodePool.clear(); + for(int i = 0; i < GameConstants::maxPlayers; ++i) { + factions.push_back(FactionState()); + } + //nodePool.clear(); map=NULL; } PathFinder::PathFinder(const Map *map) { - nodePool.clear(); + for(int i = 0; i < GameConstants::maxPlayers; ++i) { + factions.push_back(FactionState()); + } + + //nodePool.clear(); map=NULL; init(map); @@ -58,22 +65,35 @@ 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; + + for(int i = 0; i < GameConstants::maxPlayers; ++i) { + factions[i].nodePool.resize(pathFindNodesMax); + factions[i].useMaxNodeCount = PathFinder::pathFindNodesMax; + } this->map= map; } -PathFinder::~PathFinder(){ - nodePool.clear(); +PathFinder::~PathFinder() { + for(int i = 0; i < GameConstants::maxPlayers; ++i) { + factions[i].nodePool.clear(); + } map=NULL; } -TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStuck) { +void PathFinder::clearUnitPrecache(Unit *unit) { + factions[unit->getFactionIndex()].precachedTravelState[unit->getId()] = tsImpossible; + factions[unit->getFactionIndex()].precachedPath[unit->getId()].clear(); +} + +TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStuck, int frameIndex) { //printf("PathFinder::findPath...\n"); if(map == NULL) { throw runtime_error("map == NULL"); } + if(frameIndex >= 0) { + clearUnitPrecache(unit); + } if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true) { char szBuf[4096]=""; @@ -83,11 +103,11 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu } //route cache - UnitPathInterface *path= unit->getPath(); if(finalPos == unit->getPos()) { - //if arrived - unit->setCurrSkill(scStop); - + if(frameIndex < 0) { + //if arrived + unit->setCurrSkill(scStop); + } if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled == true) { string commandDesc = "none"; Command *command= unit->getCurrCommand(); @@ -102,36 +122,39 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu //unit->getFaction()->addCachedPath(finalPos,unit); return tsArrived; } - else { - if(path->isEmpty() == false) { - if(dynamic_cast(path) != NULL) { - //route cache - UnitPathBasic *basicPath = dynamic_cast(path); - Vec2i pos= basicPath->pop(); - //if(map->canMove(unit, unit->getPos(), pos, &lookupCacheCanMove)) { - if(map->canMove(unit, unit->getPos(), pos)) { + UnitPathInterface *path= unit->getPath(); + if(path->isEmpty() == false) { + if(dynamic_cast(path) != NULL) { + //route cache + UnitPathBasic *basicPath = dynamic_cast(path); + Vec2i pos= basicPath->pop(frameIndex < 0); + + if(map->canMove(unit, unit->getPos(), pos)) { + if(frameIndex < 0) { unit->setTargetPos(pos); unit->addCurrentTargetPathTakenCell(finalPos,pos); - return tsMoving; } - } - else if(dynamic_cast(path) != NULL) { - UnitPath *advPath = dynamic_cast(path); - //route cache - Vec2i pos= advPath->peek(); - //if(map->canMove(unit, unit->getPos(), pos, &lookupCacheCanMove)) { - if(map->canMove(unit, unit->getPos(), pos)) { - advPath->pop(); - unit->setTargetPos(pos); - return tsMoving; - } - } - else { - throw runtime_error("unsupported or missing path finder detected!"); + return tsMoving; } } + else if(dynamic_cast(path) != NULL) { + UnitPath *advPath = dynamic_cast(path); + //route cache + Vec2i pos= advPath->peek(); + if(map->canMove(unit, unit->getPos(), pos)) { + if(frameIndex < 0) { + advPath->pop(); + unit->setTargetPos(pos); + } + return tsMoving; + } + } + else { + throw runtime_error("unsupported or missing path finder detected!"); + } } + TravelState ts = tsImpossible; //std::vector cachedPath = unit->getFaction()->findCachedPath(finalPos, unit); @@ -144,10 +167,10 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu //} //else { //route cache miss - ts = aStar(unit, finalPos, false); + ts = aStar(unit, finalPos, false, frameIndex); //} - if(ts == tsBlocked) { + //if(ts == tsBlocked) { //std::vector cachedPath = unit->getFaction()->findCachedPath(finalPos, unit); //if(cachedPath.size() > 0) { // path->clear(); @@ -158,16 +181,16 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu // ts = tsMoving; // unit->addCurrentTargetPathTakenCell(Vec2i(-1),Vec2i(-1)); //} - } + //} //post actions switch(ts) { case tsBlocked: case tsArrived: - if(ts == tsArrived) { + //if(ts == tsArrived) { //unit->getFaction()->addCachedPath(finalPos,unit); - } + //} // 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 @@ -224,7 +247,7 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu if(useBailoutRadius == true) { //int tryRadius = random.randRange(-PathFinder::pathFindBailoutRadius, PathFinder::pathFindBailoutRadius); - int tryRadius = random.randRange(0,1); + int tryRadius = factions[unit->getFactionIndex()].random.randRange(0,1); //printf("#4 BAILOUT test unitid [%d] useBailoutRadius [%d] tryRadius [%d]\n",unit->getId(),useBailoutRadius,tryRadius); @@ -243,7 +266,7 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu } if(canUnitMove) { - ts= aStar(unit, newFinalPos, true); + ts= aStar(unit, newFinalPos, true, frameIndex); } } } @@ -262,7 +285,7 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu } if(canUnitMove) { - ts= aStar(unit, newFinalPos, true); + ts= aStar(unit, newFinalPos, true, frameIndex); } } } @@ -271,35 +294,50 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu unit->setInBailOutAttempt(false); } if(ts == tsArrived || ts == tsBlocked) { - unit->setCurrSkill(scStop); + if(frameIndex < 0) { + unit->setCurrSkill(scStop); + } } break; case tsMoving: { if(dynamic_cast(path) != NULL) { UnitPathBasic *basicPath = dynamic_cast(path); - Vec2i pos= basicPath->pop(); + Vec2i pos; + if(frameIndex < 0) { + pos = basicPath->pop(frameIndex < 0); + } + else { + pos = factions[unit->getFactionIndex()].precachedPath[unit->getId()][0]; + } //if(map->canMove(unit, unit->getPos(), pos, &lookupCacheCanMove)) { if(map->canMove(unit, unit->getPos(), pos)) { - unit->setTargetPos(pos); - unit->addCurrentTargetPathTakenCell(finalPos,pos); + if(frameIndex < 0) { + unit->setTargetPos(pos); + unit->addCurrentTargetPathTakenCell(finalPos,pos); + } } else { - unit->setCurrSkill(scStop); + if(frameIndex < 0) { + 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, &lookupCacheCanMove)) { if(map->canMove(unit, unit->getPos(), pos)) { - advPath->pop(); - unit->setTargetPos(pos); + if(frameIndex < 0) { + advPath->pop(); + unit->setTargetPos(pos); + } } else { - unit->setCurrSkill(scStop); + if(frameIndex < 0) { + unit->setCurrSkill(scStop); + } return tsBlocked; } } @@ -319,20 +357,20 @@ bool PathFinder::processNode(Unit *unit, Node *node,const Vec2i finalPos, int i, 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(openPos(sucPos, factions[unit->getFactionIndex()]) == false && canUnitMoveToCell == true) { //if node is not open and canMove then generate another node - Node *sucNode= newNode(); + Node *sucNode= newNode(factions[unit->getFactionIndex()]); 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()); - if(openNodesList.find(sucNode->heuristic) == openNodesList.end()) { - openNodesList[sucNode->heuristic].clear(); + if(factions[unit->getFactionIndex()].openNodesList.find(sucNode->heuristic) == factions[unit->getFactionIndex()].openNodesList.end()) { + factions[unit->getFactionIndex()].openNodesList[sucNode->heuristic].clear(); } - openNodesList[sucNode->heuristic].push_back(sucNode); - openPosList[sucNode->pos] = true; + factions[unit->getFactionIndex()].openNodesList[sucNode->heuristic].push_back(sucNode); + factions[unit->getFactionIndex()].openPosList[sucNode->pos] = true; result = true; } @@ -344,7 +382,8 @@ bool PathFinder::processNode(Unit *unit, Node *node,const Vec2i finalPos, int i, } //route a unit using A* algorithm -TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout) { +TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout, + int frameIndex) { //printf("PathFinder::aStar...\n"); Chrono chrono; @@ -354,18 +393,78 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout throw runtime_error("map == NULL"); } - nodePoolCount= 0; - openNodesList.clear(); - openPosList.clear(); - closedNodesList.clear(); + UnitPathInterface *path= unit->getPath(); + + factions[unit->getFactionIndex()].nodePoolCount= 0; + factions[unit->getFactionIndex()].openNodesList.clear(); + factions[unit->getFactionIndex()].openPosList.clear(); + factions[unit->getFactionIndex()].closedNodesList.clear(); TravelState ts = tsImpossible; + + if(frameIndex < 0) { + if(factions[unit->getFactionIndex()].precachedTravelState.find(unit->getId()) != factions[unit->getFactionIndex()].precachedTravelState.end()) { + if(factions[unit->getFactionIndex()].precachedTravelState[unit->getId()] == tsMoving) { + bool canMoveToCells = true; + + Vec2i lastPos = unit->getPos(); + for(int i=0; i < factions[unit->getFactionIndex()].precachedPath[unit->getId()].size(); i++) { + Vec2i nodePos = factions[unit->getFactionIndex()].precachedPath[unit->getId()][i]; + 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(i < pathFindRefresh) { + if(map->aproxCanMove(unit, lastPos, nodePos) == false) { + canMoveToCells = false; + break; + } + lastPos = nodePos; + } + else { + break; + } + } + + if(canMoveToCells == true) { + path->clear(); + UnitPathBasic *basicPathFinder = dynamic_cast(path); + + for(int i=0; i < factions[unit->getFactionIndex()].precachedPath[unit->getId()].size(); i++) { + Vec2i nodePos = factions[unit->getFactionIndex()].precachedPath[unit->getId()][i]; + 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(i < pathFindRefresh) { + path->add(nodePos); + } + else { + break; + } + } + return factions[unit->getFactionIndex()].precachedTravelState[unit->getId()]; + } + else { + clearUnitPrecache(unit); + } + } + else if(factions[unit->getFactionIndex()].precachedTravelState[unit->getId()] == tsBlocked) { + path->incBlockCount(); + return factions[unit->getFactionIndex()].precachedTravelState[unit->getId()]; + } + } + } + else { + clearUnitPrecache(unit); + } + const Vec2i unitPos = unit->getPos(); const Vec2i finalPos= computeNearestFreePos(unit, targetPos); float dist= unitPos.dist(finalPos); - useMaxNodeCount = PathFinder::pathFindNodesMax; + factions[unit->getFactionIndex()].useMaxNodeCount = PathFinder::pathFindNodesMax; // if(dist <= 10) { // useMaxNodeCount = (int)dist * 20; // if(useMaxNodeCount <= 0) { @@ -375,7 +474,6 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout 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 showConsoleDebugInfo = Config::getInstance().getBool("EnablePathfinderDistanceOutput","false"); @@ -422,7 +520,7 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true) { char szBuf[4096]=""; sprintf(szBuf,"[Setting new path for unit] openNodesList.size() [%lu] openPosList.size() [%lu] finalPos [%s] targetPos [%s] inBailout [%d] ts [%d]", - openNodesList.size(),openPosList.size(),finalPos.getString().c_str(),targetPos.getString().c_str(),inBailout,ts); + factions[unit->getFactionIndex()].openNodesList.size(),factions[unit->getFactionIndex()].openPosList.size(),finalPos.getString().c_str(),targetPos.getString().c_str(),inBailout,ts); unit->logSynchData(__FILE__,__LINE__,szBuf); } @@ -470,7 +568,7 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true) { char szBuf[4096]=""; sprintf(szBuf,"[Setting new path for unit] openNodesList.size() [%lu] openPosList.size() [%lu] finalPos [%s] targetPos [%s] inBailout [%d] ts [%d]", - openNodesList.size(),openPosList.size(),finalPos.getString().c_str(),targetPos.getString().c_str(),inBailout,ts); + factions[unit->getFactionIndex()].openNodesList.size(),factions[unit->getFactionIndex()].openPosList.size(),finalPos.getString().c_str(),targetPos.getString().c_str(),inBailout,ts); unit->logSynchData(__FILE__,__LINE__,szBuf); } @@ -506,7 +604,7 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout //path find algorithm //a) push starting pos into openNodes - Node *firstNode= newNode(); + Node *firstNode= newNode(factions[unit->getFactionIndex()]); assert(firstNode != NULL); if(firstNode == NULL) { throw runtime_error("firstNode == NULL"); @@ -517,11 +615,11 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout firstNode->pos= unitPos; firstNode->heuristic= heuristic(unitPos, finalPos); firstNode->exploredCell= true; - if(openNodesList.find(firstNode->heuristic) == openNodesList.end()) { - openNodesList[firstNode->heuristic].clear(); + if(factions[unit->getFactionIndex()].openNodesList.find(firstNode->heuristic) == factions[unit->getFactionIndex()].openNodesList.end()) { + factions[unit->getFactionIndex()].openNodesList[firstNode->heuristic].clear(); } - openNodesList[firstNode->heuristic].push_back(firstNode); - openPosList[firstNode->pos] = true; + factions[unit->getFactionIndex()].openNodesList[firstNode->heuristic].push_back(firstNode); + factions[unit->getFactionIndex()].openPosList[firstNode->pos] = true; //b) loop bool pathFound = true; @@ -592,14 +690,14 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout whileLoopCount++; //b1) is open nodes is empty => failed to find the path - if(openNodesList.empty() == true) { + if(factions[unit->getFactionIndex()].openNodesList.empty() == true) { pathFound= false; break; } //b2) get the minimum heuristic node //Nodes::iterator it = minHeuristic(); - node = minHeuristicFastLookup(); + node = minHeuristicFastLookup(factions[unit->getFactionIndex()]); //b3) if minHeuristic is the finalNode, or the path is no more explored => path was found if(node->pos == finalPos || node->exploredCell == false) { @@ -609,16 +707,16 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout //b4) move this node from closedNodes to openNodes //add all succesors that are not in closedNodes or openNodes to openNodes - if(closedNodesList.find(node->heuristic) == closedNodesList.end()) { - closedNodesList[node->heuristic].clear(); + if(factions[unit->getFactionIndex()].closedNodesList.find(node->heuristic) == factions[unit->getFactionIndex()].closedNodesList.end()) { + factions[unit->getFactionIndex()].closedNodesList[node->heuristic].clear(); } - closedNodesList[node->heuristic].push_back(node); - openPosList[node->pos] = true; + factions[unit->getFactionIndex()].closedNodesList[node->heuristic].push_back(node); + factions[unit->getFactionIndex()].openPosList[node->pos] = true; int failureCount = 0; int cellCount = 0; - int tryDirection = random.randRange(0,3); + int tryDirection = factions[unit->getFactionIndex()].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) { @@ -673,19 +771,19 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout } } //while - 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(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,factions[unit->getFactionIndex()].nodePoolCount); if(showConsoleDebugInfo && chrono.getMillis() > 2) { - printf("Distance for unit [%d - %s] from [%s] to [%s] is %.2f took msecs: %lld nodeLimitReached = %d whileLoopCount = %d nodePoolCount = %d\n",unit->getId(),unit->getFullName().c_str(), unitPos.getString().c_str(), finalPos.getString().c_str(), dist,(long long int)chrono.getMillis(),nodeLimitReached,whileLoopCount,nodePoolCount); + printf("Distance for unit [%d - %s] from [%s] to [%s] is %.2f took msecs: %lld nodeLimitReached = %d whileLoopCount = %d nodePoolCount = %d\n",unit->getId(),unit->getFullName().c_str(), unitPos.getString().c_str(), finalPos.getString().c_str(), dist,(long long int)chrono.getMillis(),nodeLimitReached,whileLoopCount,factions[unit->getFactionIndex()].nodePoolCount); } Node *lastNode= node; //if consumed all nodes find best node (to avoid strange behaviour) if(nodeLimitReached == true) { - if(closedNodesList.size() > 0) { - float bestHeuristic = closedNodesList.begin()->first; + if(factions[unit->getFactionIndex()].closedNodesList.size() > 0) { + float bestHeuristic = factions[unit->getFactionIndex()].closedNodesList.begin()->first; if(bestHeuristic < lastNode->heuristic) { - lastNode= closedNodesList.begin()->second[0]; + lastNode= factions[unit->getFactionIndex()].closedNodesList.begin()->second[0]; } } } @@ -712,12 +810,14 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout } ts= tsBlocked; - path->incBlockCount(); + if(frameIndex < 0) { + path->incBlockCount(); + } if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true) { char szBuf[4096]=""; sprintf(szBuf,"[path for unit BLOCKED] openNodesList.size() [%lu] openPosList.size() [%lu] finalPos [%s] targetPos [%s] inBailout [%d] ts [%d]", - openNodesList.size(),openPosList.size(),finalPos.getString().c_str(),targetPos.getString().c_str(),inBailout,ts); + factions[unit->getFactionIndex()].openNodesList.size(),factions[unit->getFactionIndex()].openPosList.size(),finalPos.getString().c_str(),targetPos.getString().c_str(),inBailout,ts); unit->logSynchData(__FILE__,__LINE__,szBuf); } @@ -737,7 +837,10 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout 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 - path->clear(); + if(frameIndex < 0) { + path->clear(); + } + UnitPathBasic *basicPathFinder = dynamic_cast(path); currNode= firstNode; @@ -747,15 +850,20 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout throw runtime_error("Pathfinder invalid node path position = " + nodePos.getString() + " i = " + intToStr(i)); } - if(i < pathFindRefresh) { - path->add(nodePos); - } - else if(tryLastPathCache == false) { - break; + if(frameIndex >= 0) { + factions[unit->getFactionIndex()].precachedPath[unit->getId()].push_back(nodePos); } + else { + if(i < pathFindRefresh) { + path->add(nodePos); + } + else if(tryLastPathCache == false) { + break; + } - if(tryLastPathCache == true && basicPathFinder) { - basicPathFinder->addToLastPathCache(nodePos); + if(tryLastPathCache == true && basicPathFinder) { + basicPathFinder->addToLastPathCache(nodePos); + } } } @@ -764,7 +872,7 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true) { char szBuf[4096]=""; sprintf(szBuf,"[Setting new path for unit] openNodesList.size() [%lu] openPosList.size() [%lu] finalPos [%s] targetPos [%s] inBailout [%d] ts [%d]", - openNodesList.size(),openPosList.size(),finalPos.getString().c_str(),targetPos.getString().c_str(),inBailout,ts); + factions[unit->getFactionIndex()].openNodesList.size(),factions[unit->getFactionIndex()].openPosList.size(),finalPos.getString().c_str(),targetPos.getString().c_str(),inBailout,ts); unit->logSynchData(__FILE__,__LINE__,szBuf); string pathToTake = ""; @@ -794,20 +902,27 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout 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()); } - openNodesList.clear(); - openPosList.clear(); - closedNodesList.clear(); + factions[unit->getFactionIndex()].openNodesList.clear(); + factions[unit->getFactionIndex()].openPosList.clear(); + factions[unit->getFactionIndex()].closedNodesList.clear(); if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); + if(frameIndex >= 0) { + factions[unit->getFactionIndex()].precachedTravelState[unit->getId()] = ts; + } + else { + if(SystemFlags::VERBOSE_MODE_ENABLED && chrono.getMillis() >= 5) printf("In [%s::%s Line: %d] astar took [%lld] msecs, ts = %d.\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis(),ts); + } return ts; } -PathFinder::Node *PathFinder::newNode() { - if(nodePoolCount < nodePool.size() && nodePoolCount < useMaxNodeCount) { - Node *node= &nodePool[nodePoolCount]; +PathFinder::Node *PathFinder::newNode(FactionState &faction) { + if( faction.nodePoolCount < faction.nodePool.size() && + faction.nodePoolCount < faction.useMaxNodeCount) { + Node *node= &(faction.nodePool[faction.nodePoolCount]); node->clear(); - nodePoolCount++; + faction.nodePoolCount++; return node; } return NULL; @@ -864,22 +979,22 @@ float PathFinder::heuristic(const Vec2i &pos, const Vec2i &finalPos) { return pos.dist(finalPos); } -PathFinder::Node * PathFinder::minHeuristicFastLookup() { - assert(openNodesList.empty() == false); - if(openNodesList.empty() == true) { +PathFinder::Node * PathFinder::minHeuristicFastLookup(FactionState &faction) { + assert(faction.openNodesList.empty() == false); + if(faction.openNodesList.empty() == true) { throw runtime_error("openNodesList.empty() == true"); } - Node *result = openNodesList.begin()->second[0]; - openNodesList.begin()->second.erase(openNodesList.begin()->second.begin()); - if(openNodesList.begin()->second.size() == 0) { - openNodesList.erase(openNodesList.begin()); + Node *result = faction.openNodesList.begin()->second[0]; + faction.openNodesList.begin()->second.erase(faction.openNodesList.begin()->second.begin()); + if(faction.openNodesList.begin()->second.size() == 0) { + faction.openNodesList.erase(faction.openNodesList.begin()); } return result; } -bool PathFinder::openPos(const Vec2i &sucPos) { - if(openPosList.find(sucPos) == openPosList.end()) { +bool PathFinder::openPos(const Vec2i &sucPos, FactionState &faction) { + if(faction.openPosList.find(sucPos) == faction.openPosList.end()) { return false; } return true; diff --git a/source/glest_game/ai/path_finder.h b/source/glest_game/ai/path_finder.h index 84da92af..d6d418cc 100644 --- a/source/glest_game/ai/path_finder.h +++ b/source/glest_game/ai/path_finder.h @@ -57,38 +57,59 @@ public: }; typedef vector Nodes; + class FactionState { + public: + FactionState() { + openPosList.clear(); + openNodesList.clear(); + closedNodesList.clear(); + nodePool.clear(); + nodePoolCount = 0; + useMaxNodeCount = 0; + precachedTravelState.clear(); + precachedPath.clear(); + } + std::map openPosList; + std::map openNodesList; + std::map closedNodesList; + std::vector nodePool; + int nodePoolCount; + RandomGen random; + int useMaxNodeCount; + + std::map precachedTravelState; + std::map > precachedPath; + }; + typedef vector FactionStateList; + public: static const int maxFreeSearchRadius; - static int pathFindNodesMax; static const int pathFindRefresh; static const int pathFindBailoutRadius; private: - std::map openPosList; - std::map openNodesList; - std::map closedNodesList; - std::vector nodePool; - int nodePoolCount; + static int pathFindNodesMax; + + FactionStateList factions; const Map *map; - RandomGen random; - int useMaxNodeCount; public: PathFinder(); PathFinder(const Map *map); ~PathFinder(); void init(const Map *map); - TravelState findPath(Unit *unit, const Vec2i &finalPos, bool *wasStuck=NULL); + TravelState findPath(Unit *unit, const Vec2i &finalPos, bool *wasStuck=NULL,int frameIndex=-1); + void clearUnitPrecache(Unit *unit); private: - TravelState aStar(Unit *unit, const Vec2i &finalPos, bool inBailout); - Node *newNode(); + TravelState aStar(Unit *unit, const Vec2i &finalPos, bool inBailout, int frameIndex); + Node *newNode(FactionState &faction); Vec2i computeNearestFreePos(const Unit *unit, const Vec2i &targetPos); float heuristic(const Vec2i &pos, const Vec2i &finalPos); - bool openPos(const Vec2i &sucPos); + bool openPos(const Vec2i &sucPos,FactionState &faction); - Node * minHeuristicFastLookup(); + Node * minHeuristicFastLookup(FactionState &faction); 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/faction.cpp b/source/glest_game/type_instances/faction.cpp index 3ae3b85b..9c206a03 100644 --- a/source/glest_game/type_instances/faction.cpp +++ b/source/glest_game/type_instances/faction.cpp @@ -26,7 +26,164 @@ using namespace Shared::Util; -namespace Glest{ namespace Game{ +namespace Glest { namespace Game { + +// ===================================================== +// class FactionThread +// ===================================================== + +FactionThread::FactionThread(Faction *faction) : BaseThread() { + this->faction = faction; +} + +void FactionThread::setQuitStatus(bool value) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d value = %d\n",__FILE__,__FUNCTION__,__LINE__,value); + + BaseThread::setQuitStatus(value); + if(value == true) { + signalPathfinder(-1); + } + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); +} + +void FactionThread::signalPathfinder(int frameIndex) { + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] event = %p\n",__FILE__,__FUNCTION__,__LINE__,event); + + //if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] frameIndex = %d this = %p\n",__FILE__,__FUNCTION__,__LINE__,frameIndex, this); + + if(frameIndex >= 0) { + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutex(&triggerIdMutex,mutexOwnerId); + this->frameIndex.first = frameIndex; + this->frameIndex.second = false; + safeMutex.ReleaseLock(); + } + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + semTaskSignalled.signal(); +} + +void FactionThread::setTaskCompleted(int frameIndex) { + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + + //if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] frameIndex = %d this = %p\n",__FILE__,__FUNCTION__,__LINE__,frameIndex, this); + + if(frameIndex >= 0) { + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutex(&triggerIdMutex,mutexOwnerId); + if(this->frameIndex.first == frameIndex) { + this->frameIndex.second = true; + } + safeMutex.ReleaseLock(); + } + + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); +} + +bool FactionThread::canShutdown(bool deleteSelfIfShutdownDelayed) { + bool ret = (getExecutingTask() == false); + if(ret == false && deleteSelfIfShutdownDelayed == true) { + setDeleteSelfOnExecutionDone(deleteSelfIfShutdownDelayed); + signalQuit(); + } + + return ret; +} + +bool FactionThread::isSignalPathfinderCompleted(int frameIndex) { + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] slotIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,slotIndex); + if(getRunningStatus() == false) { + return true; + } + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutex(&triggerIdMutex,mutexOwnerId); + //bool result = (event != NULL ? event->eventCompleted : true); + bool result = (this->frameIndex.first == frameIndex && this->frameIndex.second == true); + + //if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] worker thread this = %p, this->frameIndex.first = %d, this->frameIndex.second = %d\n",__FILE__,__FUNCTION__,__LINE__,this,this->frameIndex.first,this->frameIndex.second); + + safeMutex.ReleaseLock(); + //if(result == false) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] slotIndex = %d, result = %d\n",__FILE__,__FUNCTION__,__LINE__,slotIndex,result); + return result; +} + +void FactionThread::execute() { + RunningStatusSafeWrapper runningStatus(this); + try { + //setRunningStatus(true); + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] ****************** STARTING worker thread this = %p\n",__FILE__,__FUNCTION__,__LINE__,this); + + unsigned int idx = 0; + for(;this->faction != NULL;) { + if(getQuitStatus() == true) { + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + break; + } + + //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + semTaskSignalled.waitTillSignalled(); + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + + if(getQuitStatus() == true) { + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + break; + } + + //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutex(&triggerIdMutex,mutexOwnerId); + bool executeTask = (frameIndex.first >= 0); + + //if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] frameIndex = %d this = %p executeTask = %d\n",__FILE__,__FUNCTION__,__LINE__,frameIndex.first, this, executeTask); + + safeMutex.ReleaseLock(); + + if(executeTask == true) { + ExecutingTaskSafeWrapper safeExecutingTaskMutex(this); + //this->slotInterface->slotUpdateTask(&eventCopy); + + World *world = faction->getWorld(); + int unitCount = faction->getUnitCount(); + for(int j = 0; j < unitCount; ++j) { + Unit *unit = faction->getUnit(j); + if(unit == NULL) { + throw runtime_error("unit == NULL"); + } + + bool update = unit->needToUpdate(); + if(update == true) { + world->getUnitUpdater()->updateUnitCommand(unit,frameIndex.first); + } + } + + setTaskCompleted(frameIndex.first); + } + + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + + if(getQuitStatus() == true) { + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + break; + } + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + } + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] ****************** ENDING worker thread this = %p\n",__FILE__,__FUNCTION__,__LINE__,this); + } + catch(const exception &ex) { + //setRunningStatus(false); + + SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + throw runtime_error(ex.what()); + } + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + //setRunningStatus(false); +} + // ===================================================== // class Faction @@ -37,6 +194,7 @@ Faction::Faction() { //lastResourceTargettListPurge = 0; cachingDisabled=false; factionDisconnectHandled=false; + workerThread = NULL; } Faction::~Faction() { @@ -50,11 +208,33 @@ Faction::~Faction() { //texture->end(); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + if(workerThread != NULL) { + workerThread->signalQuit(); + if(workerThread->shutdownAndWait() == true) { + delete workerThread; + } + workerThread = NULL; + } + //delete texture; texture = NULL; SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } +void Faction::signalWorkerThread(int frameIndex) { + if(workerThread != NULL) { + workerThread->signalPathfinder(frameIndex); + } +} + +bool Faction::isWorkerThreadSignalCompleted(int frameIndex) { + if(workerThread != NULL) { + return workerThread->isSignalPathfinderCompleted(frameIndex); + } + return true; +} + + void Faction::init( FactionType *factionType, ControlType control, TechTree *techTree, Game *game, int factionIndex, int teamIndex, int startLocationIndex, bool thisFaction, bool giveResources) @@ -84,11 +264,33 @@ void Faction::init( string data_path = getGameReadWritePath(GameConstants::path_data_CacheLookupKey); texture->load(data_path + "data/core/faction_textures/faction"+intToStr(startLocationIndex)+".tga"); + if(Config::getInstance().getBool("EnableFactionWorkerThreads","true") == true) { + if(workerThread != NULL) { + workerThread->signalQuit(); + if(workerThread->shutdownAndWait() == true) { + delete workerThread; + } + workerThread = NULL; + } + this->workerThread = new FactionThread(this); + this->workerThread->setUniqueID(__FILE__); + this->workerThread->start(); + } + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } -void Faction::end(){ +void Faction::end() { SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + if(workerThread != NULL) { + workerThread->signalQuit(); + if(workerThread->shutdownAndWait() == true) { + delete workerThread; + } + workerThread = NULL; + } + deleteValues(units.begin(), units.end()); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } diff --git a/source/glest_game/type_instances/faction.h b/source/glest_game/type_instances/faction.h index ac00c578..14c65728 100644 --- a/source/glest_game/type_instances/faction.h +++ b/source/glest_game/type_instances/faction.h @@ -20,12 +20,14 @@ #include "resource.h" #include "game_constants.h" #include "command_type.h" +#include "base_thread.h" #include "leak_dumper.h" using std::map; using std::vector; using Shared::Graphics::Texture2D; +using namespace Shared::PlatformCommon; namespace Glest{ namespace Game{ @@ -39,6 +41,7 @@ class UnitType; class Game; class ScriptManager; class World; +class Faction; // ===================================================== // class Faction @@ -54,6 +57,25 @@ public: vector, int> > pathQueue; }; +class FactionThread : public BaseThread { +protected: + + Faction *faction; + Semaphore semTaskSignalled; + Mutex triggerIdMutex; + std::pair frameIndex; + + virtual void setQuitStatus(bool value); + virtual void setTaskCompleted(int frameIndex); + virtual bool canShutdown(bool deleteSelfIfShutdownDelayed=false); + +public: + FactionThread(Faction *faction); + virtual void execute(); + void signalPathfinder(int frameIndex); + bool isSignalPathfinderCompleted(int frameIndex); +}; + class Faction { private: typedef vector Resources; @@ -98,6 +120,8 @@ private: // update of the faction //std::map > > localCacheForUnitCellMovement; + FactionThread *workerThread; + public: Faction(); ~Faction(); @@ -186,7 +210,11 @@ public: void deletePixels(); + World * getWorld() { return world; } int getFrameCount(); + void signalWorkerThread(int frameIndex); + bool isWorkerThreadSignalCompleted(int frameIndex); + std::string toString() const; private: diff --git a/source/glest_game/type_instances/unit.cpp b/source/glest_game/type_instances/unit.cpp index 0397b557..58cbbff8 100644 --- a/source/glest_game/type_instances/unit.cpp +++ b/source/glest_game/type_instances/unit.cpp @@ -101,12 +101,14 @@ void UnitPathBasic::addToLastPathCache(const Vec2i &path) { lastPathCacheQueue.push_back(path); } -Vec2i UnitPathBasic::pop() { +Vec2i UnitPathBasic::pop(bool removeFrontPos) { if(pathQueue.size() <= 0) { throw runtime_error("pathQueue.size() = " + intToStr(pathQueue.size())); } Vec2i p= pathQueue.front(); - pathQueue.erase(pathQueue.begin()); + if(removeFrontPos == true) { + pathQueue.erase(pathQueue.begin()); + } return p; } std::string UnitPathBasic::toString() const { @@ -1105,6 +1107,60 @@ const CommandType *Unit::computeCommandType(const Vec2i &pos, const Unit *target return commandType; } + +bool Unit::needToUpdate() { + assert(progress <= 1.f); + + if(currSkill == NULL) { + char szBuf[4096]=""; + sprintf(szBuf,"In [%s::%s Line: %d] ERROR: currSkill == NULL, Unit = [%s]\n",__FILE__,__FUNCTION__,__LINE__,this->toString().c_str()); + throw runtime_error(szBuf); + } + + //speed + int speed = currSkill->getTotalSpeed(&totalUpgrade); + + //speed modifier + float diagonalFactor= 1.f; + float heightFactor= 1.f; + if(currSkill->getClass() == scMove) { + //if moving in diagonal move slower + Vec2i dest= pos-lastPos; + if(abs(dest.x) + abs(dest.y) == 2) { + diagonalFactor= 0.71f; + } + + //if movig to an higher cell move slower else move faster + float heightDiff= map->getCell(pos)->getHeight() - map->getCell(targetPos)->getHeight(); + heightFactor= clamp(1.f + heightDiff / 5.f, 0.2f, 5.f); + } + + //update progresses + float newProgress = progress; + const Game *game = Renderer::getInstance().getGame(); + newProgress += (speed * diagonalFactor * heightFactor) / (speedDivider * game->getWorld()->getUpdateFps(this->getFactionIndex())); + + //checks + bool return_value = false; + //checks + if(newProgress >= 1.f) { + if(currSkill->getClass() != scDie) { + newProgress= 0.f; + return_value = true; + } + else { + newProgress= 1.f; + int newDeadCount = deadCount; + newDeadCount++; + if(newDeadCount >= maxDeadCount) { + return_value = false; + } + } + } + + return return_value; +} + bool Unit::update() { assert(progress<=1.f); diff --git a/source/glest_game/type_instances/unit.h b/source/glest_game/type_instances/unit.h index a06da1c9..64a4fbb8 100644 --- a/source/glest_game/type_instances/unit.h +++ b/source/glest_game/type_instances/unit.h @@ -147,7 +147,7 @@ public: virtual void incBlockCount(); virtual void add(const Vec2i &path); void addToLastPathCache(const Vec2i &path); - Vec2i pop(); + Vec2i pop(bool removeFrontPos=true); virtual int getBlockCount() const { return blockCount; } virtual int getQueueCount() const { return pathQueue.size(); } @@ -494,6 +494,7 @@ public: void logSynchData(string file,int line,string source=""); std::string toString() const; + bool needToUpdate(); private: float computeHeight(const Vec2i &pos) const; diff --git a/source/glest_game/types/command_type.cpp b/source/glest_game/types/command_type.cpp index 6aa2978b..275bbac8 100644 --- a/source/glest_game/types/command_type.cpp +++ b/source/glest_game/types/command_type.cpp @@ -88,8 +88,8 @@ StopCommandType::StopCommandType(){ clicks= cOne; } -void StopCommandType::update(UnitUpdater *unitUpdater, Unit *unit) const{ - unitUpdater->updateStop(unit); +void StopCommandType::update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const { + unitUpdater->updateStop(unit, frameIndex); } string StopCommandType::getDesc(const TotalUpgrade *totalUpgrade) const{ @@ -131,8 +131,8 @@ MoveCommandType::MoveCommandType(){ clicks= cTwo; } -void MoveCommandType::update(UnitUpdater *unitUpdater, Unit *unit) const{ - unitUpdater->updateMove(unit); +void MoveCommandType::update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const { + unitUpdater->updateMove(unit, frameIndex); } void MoveCommandType::load(int id, const XmlNode *n, const string &dir, @@ -180,8 +180,8 @@ AttackCommandType::AttackCommandType(){ clicks= cTwo; } -void AttackCommandType::update(UnitUpdater *unitUpdater, Unit *unit) const{ - unitUpdater->updateAttack(unit); +void AttackCommandType::update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const { + unitUpdater->updateAttack(unit, frameIndex); } void AttackCommandType::load(int id, const XmlNode *n, const string &dir, @@ -272,8 +272,8 @@ AttackStoppedCommandType::AttackStoppedCommandType(){ clicks= cOne; } -void AttackStoppedCommandType::update(UnitUpdater *unitUpdater, Unit *unit) const{ - unitUpdater->updateAttackStopped(unit); +void AttackStoppedCommandType::update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const { + unitUpdater->updateAttackStopped(unit, frameIndex); } void AttackStoppedCommandType::load(int id, const XmlNode *n, const string &dir, @@ -359,8 +359,8 @@ BuildCommandType::~BuildCommandType() { deleteValues(startSounds.getSounds().begin(), startSounds.getSounds().end()); } -void BuildCommandType::update(UnitUpdater *unitUpdater, Unit *unit) const{ - unitUpdater->updateBuild(unit); +void BuildCommandType::update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const { + unitUpdater->updateBuild(unit, frameIndex); } void BuildCommandType::load(int id, const XmlNode *n, const string &dir, @@ -457,8 +457,8 @@ HarvestCommandType::HarvestCommandType(){ clicks= cTwo; } -void HarvestCommandType::update(UnitUpdater *unitUpdater, Unit *unit) const{ - unitUpdater->updateHarvest(unit); +void HarvestCommandType::update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const { + unitUpdater->updateHarvest(unit, frameIndex); } void HarvestCommandType::load(int id, const XmlNode *n, const string &dir, @@ -538,8 +538,8 @@ RepairCommandType::RepairCommandType(){ RepairCommandType::~RepairCommandType(){ } -void RepairCommandType::update(UnitUpdater *unitUpdater, Unit *unit) const{ - unitUpdater->updateRepair(unit); +void RepairCommandType::update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const { + unitUpdater->updateRepair(unit, frameIndex); } void RepairCommandType::load(int id, const XmlNode *n, const string &dir, @@ -615,8 +615,8 @@ ProduceCommandType::ProduceCommandType(){ clicks= cOne; } -void ProduceCommandType::update(UnitUpdater *unitUpdater, Unit *unit) const{ - unitUpdater->updateProduce(unit); +void ProduceCommandType::update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const { + unitUpdater->updateProduce(unit, frameIndex); } void ProduceCommandType::load(int id, const XmlNode *n, const string &dir, @@ -680,8 +680,8 @@ UpgradeCommandType::UpgradeCommandType(){ clicks= cOne; } -void UpgradeCommandType::update(UnitUpdater *unitUpdater, Unit *unit) const{ - unitUpdater->updateUpgrade(unit); +void UpgradeCommandType::update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const { + unitUpdater->updateUpgrade(unit, frameIndex); } void UpgradeCommandType::load(int id, const XmlNode *n, const string &dir, @@ -737,8 +737,8 @@ MorphCommandType::MorphCommandType(){ clicks= cOne; } -void MorphCommandType::update(UnitUpdater *unitUpdater, Unit *unit) const{ - unitUpdater->updateMorph(unit); +void MorphCommandType::update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const { + unitUpdater->updateMorph(unit, frameIndex); } void MorphCommandType::load(int id, const XmlNode *n, const string &dir, diff --git a/source/glest_game/types/command_type.h b/source/glest_game/types/command_type.h index 34d0e106..b53b6844 100644 --- a/source/glest_game/types/command_type.h +++ b/source/glest_game/types/command_type.h @@ -21,7 +21,7 @@ #include "sound_container.h" #include "leak_dumper.h" -namespace Glest{ namespace Game{ +namespace Glest { namespace Game { using Shared::Util::MultiFactory; @@ -31,7 +31,7 @@ class UnitType; class TechTree; class FactionType; -enum CommandClass{ +enum CommandClass { ccStop, ccMove, ccAttack, @@ -47,7 +47,7 @@ enum CommandClass{ ccNull }; -enum Clicks{ +enum Clicks { cOne, cTwo }; @@ -80,7 +80,7 @@ public: clicks = cOne; id = -1; } - virtual void update(UnitUpdater *unitUpdater, Unit *unit) const= 0; + virtual void update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const= 0; virtual void load(int id, const XmlNode *n, const string &dir, const TechTree *tt, const FactionType *ft, const UnitType &ut, std::map &loadedFileList); @@ -109,13 +109,13 @@ public: // class StopCommandType // =============================== -class StopCommandType: public CommandType{ +class StopCommandType: public CommandType { private: const StopSkillType* stopSkillType; public: StopCommandType(); - virtual void update(UnitUpdater *unitUpdater, Unit *unit) const; + virtual void update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const; virtual void load(int id, const XmlNode *n, const string &dir, const TechTree *tt, const FactionType *ft, const UnitType &ut, std::map &loadedFileList); virtual string getDesc(const TotalUpgrade *totalUpgrade) const; @@ -131,13 +131,13 @@ public: // class MoveCommandType // =============================== -class MoveCommandType: public CommandType{ +class MoveCommandType: public CommandType { private: const MoveSkillType *moveSkillType; public: MoveCommandType(); - virtual void update(UnitUpdater *unitUpdater, Unit *unit) const; + virtual void update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const; virtual void load(int id, const XmlNode *n, const string &dir, const TechTree *tt, const FactionType *ft, const UnitType &ut, std::map &loadedFileList); @@ -153,14 +153,14 @@ public: // class AttackCommandType // =============================== -class AttackCommandType: public CommandType{ +class AttackCommandType: public CommandType { private: const MoveSkillType* moveSkillType; const AttackSkillType* attackSkillType; public: AttackCommandType(); - virtual void update(UnitUpdater *unitUpdater, Unit *unit) const; + virtual void update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const; virtual void load(int id, const XmlNode *n, const string &dir, const TechTree *tt, const FactionType *ft, const UnitType &ut, std::map &loadedFileList); @@ -177,14 +177,14 @@ public: // class AttackStoppedCommandType // ======================================= -class AttackStoppedCommandType: public CommandType{ +class AttackStoppedCommandType: public CommandType { private: const StopSkillType* stopSkillType; const AttackSkillType* attackSkillType; public: AttackStoppedCommandType(); - virtual void update(UnitUpdater *unitUpdater, Unit *unit) const; + virtual void update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const; virtual void load(int id, const XmlNode *n, const string &dir, const TechTree *tt, const FactionType *ft, const UnitType &ut, std::map &loadedFileList); @@ -201,7 +201,7 @@ public: // class BuildCommandType // =============================== -class BuildCommandType: public CommandType{ +class BuildCommandType: public CommandType { private: const MoveSkillType* moveSkillType; const BuildSkillType* buildSkillType; @@ -212,7 +212,7 @@ private: public: BuildCommandType(); ~BuildCommandType(); - virtual void update(UnitUpdater *unitUpdater, Unit *unit) const; + virtual void update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const; virtual void load(int id, const XmlNode *n, const string &dir, const TechTree *tt, const FactionType *ft, const UnitType &ut, std::map &loadedFileList); @@ -233,7 +233,7 @@ public: // class HarvestCommandType // =============================== -class HarvestCommandType: public CommandType{ +class HarvestCommandType: public CommandType { private: const MoveSkillType *moveSkillType; const MoveSkillType *moveLoadedSkillType; @@ -245,7 +245,7 @@ private: public: HarvestCommandType(); - virtual void update(UnitUpdater *unitUpdater, Unit *unit) const; + virtual void update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const; virtual void load(int id, const XmlNode *n, const string &dir, const TechTree *tt, const FactionType *ft, const UnitType &ut, std::map &loadedFileList); @@ -270,7 +270,7 @@ public: // class RepairCommandType // =============================== -class RepairCommandType: public CommandType{ +class RepairCommandType: public CommandType { private: const MoveSkillType* moveSkillType; const RepairSkillType* repairSkillType; @@ -279,7 +279,7 @@ private: public: RepairCommandType(); ~RepairCommandType(); - virtual void update(UnitUpdater *unitUpdater, Unit *unit) const; + virtual void update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const; virtual void load(int id, const XmlNode *n, const string &dir, const TechTree *tt, const FactionType *ft, const UnitType &ut, std::map &loadedFileList); @@ -301,14 +301,14 @@ public: // class ProduceCommandType // =============================== -class ProduceCommandType: public CommandType{ +class ProduceCommandType: public CommandType { private: const ProduceSkillType* produceSkillType; const UnitType *producedUnit; public: ProduceCommandType(); - virtual void update(UnitUpdater *unitUpdater, Unit *unit) const; + virtual void update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const; virtual void load(int id, const XmlNode *n, const string &dir, const TechTree *tt, const FactionType *ft, const UnitType &ut, std::map &loadedFileList); @@ -328,14 +328,14 @@ public: // class UpgradeCommandType // =============================== -class UpgradeCommandType: public CommandType{ +class UpgradeCommandType: public CommandType { private: const UpgradeSkillType* upgradeSkillType; const UpgradeType* producedUpgrade; public: UpgradeCommandType(); - virtual void update(UnitUpdater *unitUpdater, Unit *unit) const; + virtual void update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const; virtual void load(int id, const XmlNode *n, const string &dir, const TechTree *tt, const FactionType *ft, const UnitType &ut, std::map &loadedFileList); @@ -354,7 +354,7 @@ public: // class MorphCommandType // =============================== -class MorphCommandType: public CommandType{ +class MorphCommandType: public CommandType { private: const MorphSkillType* morphSkillType; const UnitType* morphUnit; @@ -362,7 +362,7 @@ private: public: MorphCommandType(); - virtual void update(UnitUpdater *unitUpdater, Unit *unit) const; + virtual void update(UnitUpdater *unitUpdater, Unit *unit, int frameIndex) const; virtual void load(int id, const XmlNode *n, const string &dir, const TechTree *tt, const FactionType *ft, const UnitType &ut, std::map &loadedFileList); diff --git a/source/glest_game/world/unit_updater.cpp b/source/glest_game/world/unit_updater.cpp index 5775381e..6dbd2772 100644 --- a/source/glest_game/world/unit_updater.cpp +++ b/source/glest_game/world/unit_updater.cpp @@ -83,6 +83,12 @@ void UnitUpdater::init(Game *game){ } } +void UnitUpdater::clearUnitPrecache(Unit *unit) { + if(pathFinder != NULL) { + pathFinder->clearUnitPrecache(unit); + } +} + UnitUpdater::~UnitUpdater() { //UnitRangeCellsLookupItemCache.clear(); @@ -139,7 +145,7 @@ void UnitUpdater::updateUnit(Unit *unit) { if(update == true) { //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); - updateUnitCommand(unit); + updateUnitCommand(unit,-1); if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld [after updateUnitCommand()]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); @@ -236,7 +242,12 @@ void UnitUpdater::updateUnit(Unit *unit) { // ==================== progress commands ==================== //VERY IMPORTANT: compute next state depending on the first order of the list -void UnitUpdater::updateUnitCommand(Unit *unit) { +void UnitUpdater::updateUnitCommand(Unit *unit, int frameIndex) { + // Clear previous cached unit data + if(frameIndex >= 0) { + clearUnitPrecache(unit); + } + Chrono chrono; chrono.start(); @@ -245,28 +256,35 @@ void UnitUpdater::updateUnitCommand(Unit *unit) { SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] unit [%s] has command [%s]\n",__FILE__,__FUNCTION__,__LINE__,unit->toString().c_str(), unit->getCurrCommand()->toString().c_str()); CommandClass cc = unit->getCurrCommand()->getCommandType()->commandTypeClass; - unit->getCurrCommand()->getCommandType()->update(this, unit); + unit->getCurrCommand()->getCommandType()->update(this, unit, frameIndex); } if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - //if no commands stop and add stop command - if(unit->anyCommand() == false && unit->isOperative()) { - SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); - unit->setCurrSkill(scStop); + if(frameIndex < 0) { + //if no commands stop and add stop command + if(unit->anyCommand() == false && unit->isOperative()) { + SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + unit->setCurrSkill(scStop); - if(unit->getType()->hasCommandClass(ccStop)) { - //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); - unit->giveCommand(new Command(unit->getType()->getFirstCtOfClass(ccStop))); + if(unit->getType()->hasCommandClass(ccStop)) { + //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + unit->giveCommand(new Command(unit->getType()->getFirstCtOfClass(ccStop))); + } } - } - + } if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); } // ==================== updateStop ==================== -void UnitUpdater::updateStop(Unit *unit) { +void UnitUpdater::updateStop(Unit *unit, int frameIndex) { + // Nothing to do + if(frameIndex >= 0) { + clearUnitPrecache(unit); + return; + } + Chrono chrono; chrono.start(); @@ -329,7 +347,7 @@ void UnitUpdater::updateStop(Unit *unit) { // ==================== updateMove ==================== -void UnitUpdater::updateMove(Unit *unit) { +void UnitUpdater::updateMove(Unit *unit, int frameIndex) { Chrono chrono; chrono.start(); @@ -349,7 +367,7 @@ void UnitUpdater::updateMove(Unit *unit) { TravelState tsValue = tsImpossible; switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: - tsValue = pathFinder->findPath(unit, pos); + tsValue = pathFinder->findPath(unit, pos, NULL, frameIndex); break; case pfRoutePlanner: tsValue = routePlanner->findPath(unit, pos); @@ -360,29 +378,30 @@ void UnitUpdater::updateMove(Unit *unit) { if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - switch (tsValue) { - case tsMoving: - unit->setCurrSkill(mct->getMoveSkillType()); - break; + if(frameIndex < 0) { + switch (tsValue) { + case tsMoving: + unit->setCurrSkill(mct->getMoveSkillType()); + break; - case tsBlocked: - unit->setCurrSkill(scStop); - if(unit->getPath()->isBlocked()){ + case tsBlocked: + unit->setCurrSkill(scStop); + if(unit->getPath()->isBlocked()){ + unit->finishCommand(); + } + break; + + default: unit->finishCommand(); } - break; - - default: - unit->finishCommand(); - } - + } if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); } // ==================== updateAttack ==================== -void UnitUpdater::updateAttack(Unit *unit) { +void UnitUpdater::updateAttack(Unit *unit, int frameIndex) { Chrono chrono; chrono.start(); @@ -392,28 +411,31 @@ void UnitUpdater::updateAttack(Unit *unit) { if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - if( (command->getUnit()==NULL || !(command->getUnit()->isAlive()) ) && unit->getCommandSize()>1) - { - unit->finishCommand(); // all queued "ground attacks" are skipped if somthing else is queued after them. + if( (command->getUnit() == NULL || !(command->getUnit()->isAlive()) ) && unit->getCommandSize() > 1) { + + if(frameIndex < 0) { + unit->finishCommand(); // all queued "ground attacks" are skipped if somthing else is queued after them. + } return; } //if found if(attackableOnRange(unit, &target, act->getAttackSkillType())) { - if(unit->getEp()>=act->getAttackSkillType()->getEpCost()) { - unit->setCurrSkill(act->getAttackSkillType()); - unit->setTarget(target); - } - else { - unit->setCurrSkill(scStop); - } - + if(frameIndex < 0) { + if(unit->getEp() >= act->getAttackSkillType()->getEpCost()) { + unit->setCurrSkill(act->getAttackSkillType()); + unit->setTarget(target); + } + else { + unit->setCurrSkill(scStop); + } + } if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); } else { //compute target pos Vec2i pos; - if(command->getUnit()!=NULL) { + if(command->getUnit() != NULL) { pos= command->getUnit()->getCenteredPos(); } else if(attackableOnSight(unit, &target, act->getAttackSkillType())) { @@ -435,7 +457,7 @@ void UnitUpdater::updateAttack(Unit *unit) { TravelState tsValue = tsImpossible; switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: - tsValue = pathFinder->findPath(unit, pos); + tsValue = pathFinder->findPath(unit, pos, NULL, frameIndex); break; case pfRoutePlanner: tsValue = routePlanner->findPath(unit, pos); @@ -446,27 +468,28 @@ void UnitUpdater::updateAttack(Unit *unit) { if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - - if(command->getUnit()!=NULL && !command->getUnit()->isAlive() && unit->getCommandSize()>1) - {// don't run over to dead body if there is still something to do in the queue - unit->finishCommand(); - } - else { - //if unit arrives destPos order has ended - switch (tsValue){ - case tsMoving: - unit->setCurrSkill(act->getMoveSkillType()); - break; - case tsBlocked: - if(unit->getPath()->isBlocked()){ - unit->finishCommand(); - } - break; - default: + if(frameIndex < 0) { + if(command->getUnit() != NULL && !command->getUnit()->isAlive() && unit->getCommandSize() > 1) { + // don't run over to dead body if there is still something to do in the queue unit->finishCommand(); } + else { + //if unit arrives destPos order has ended + switch (tsValue){ + case tsMoving: + unit->setCurrSkill(act->getMoveSkillType()); + break; + case tsBlocked: + if(unit->getPath()->isBlocked()){ + unit->finishCommand(); + } + break; + default: + unit->finishCommand(); + } + } } - if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); + if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); } if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); @@ -475,7 +498,13 @@ void UnitUpdater::updateAttack(Unit *unit) { // ==================== updateAttackStopped ==================== -void UnitUpdater::updateAttackStopped(Unit *unit) { +void UnitUpdater::updateAttackStopped(Unit *unit, int frameIndex) { + // Nothing to do + if(frameIndex >= 0) { + clearUnitPrecache(unit); + return; + } + Chrono chrono; chrono.start(); @@ -483,7 +512,7 @@ void UnitUpdater::updateAttackStopped(Unit *unit) { const AttackStoppedCommandType *asct= static_cast(command->getCommandType()); Unit *enemy; - if(unit->getCommandSize()>1) + if(unit->getCommandSize() > 1) { unit->finishCommand(); // attackStopped is skipped if somthing else is queued after this. return; @@ -503,7 +532,7 @@ void UnitUpdater::updateAttackStopped(Unit *unit) { // ==================== updateBuild ==================== -void UnitUpdater::updateBuild(Unit *unit) { +void UnitUpdater::updateBuild(Unit *unit, int frameIndex) { Chrono chrono; chrono.start(); @@ -540,7 +569,7 @@ void UnitUpdater::updateBuild(Unit *unit) { unit->logSynchData(__FILE__,__LINE__,szBuf); } - tsValue = pathFinder->findPath(unit, buildPos); + tsValue = pathFinder->findPath(unit, buildPos, NULL, frameIndex); } break; case pfRoutePlanner: @@ -553,166 +582,168 @@ void UnitUpdater::updateBuild(Unit *unit) { //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsValue = %d\n",__FILE__,__FUNCTION__,__LINE__,tsValue); - switch (tsValue) { - case tsMoving: - SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsMoving\n",__FILE__,__FUNCTION__,__LINE__); + if(frameIndex < 0) { + switch (tsValue) { + case tsMoving: + SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsMoving\n",__FILE__,__FUNCTION__,__LINE__); - unit->setCurrSkill(bct->getMoveSkillType()); - break; + unit->setCurrSkill(bct->getMoveSkillType()); + break; - case tsArrived: - { - SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsArrived:\n",__FILE__,__FUNCTION__,__LINE__); + case tsArrived: + { + SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsArrived:\n",__FILE__,__FUNCTION__,__LINE__); - //if arrived destination - assert(ut); - if(ut == NULL) { - throw runtime_error("ut == NULL"); - } - - bool canOccupyCell = false; - switch(this->game->getGameSettings()->getPathFinderType()) { - case pfBasic: - SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsArrived about to call map->isFreeCells() for command->getPos() = %s, ut->getSize() = %d\n",__FILE__,__FUNCTION__,__LINE__,command->getPos().getString().c_str(),ut->getSize()); - canOccupyCell = map->isFreeCells(command->getPos(), ut->getSize(), fLand); - break; - case pfRoutePlanner: - canOccupyCell = map->canOccupy(command->getPos(), ut->getField(), ut, command->getFacing()); - break; - default: - throw runtime_error("detected unsupported pathfinder type!"); - } - - SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] canOccupyCell = %d\n",__FILE__,__FUNCTION__,__LINE__,canOccupyCell); - - if (canOccupyCell == true) { - const UnitType *builtUnitType= command->getUnitType(); - CardinalDir facing = command->getFacing(); - - UnitPathInterface *newpath = NULL; - switch(this->game->getGameSettings()->getPathFinderType()) { - case pfBasic: - newpath = new UnitPathBasic(); - break; - case pfRoutePlanner: - newpath = new UnitPath(); - break; - default: - throw runtime_error("detected unsupported pathfinder type!"); - } - - //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); - - Vec2i buildPos = command->getPos(); - Unit *builtUnit= new Unit(world->getNextUnitId(unit->getFaction()), newpath, buildPos, builtUnitType, unit->getFaction(), world->getMap(), facing); - - SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); - - builtUnit->create(); - - if(builtUnitType->hasSkillClass(scBeBuilt) == false) { - throw runtime_error("Unit " + builtUnitType->getName() + "has no be_built skill"); + //if arrived destination + assert(ut); + if(ut == NULL) { + throw runtime_error("ut == NULL"); } - builtUnit->setCurrSkill(scBeBuilt); - - unit->setCurrSkill(bct->getBuildSkillType()); - unit->setTarget(builtUnit); - map->prepareTerrain(builtUnit); - - SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); - + bool canOccupyCell = false; switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: + SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsArrived about to call map->isFreeCells() for command->getPos() = %s, ut->getSize() = %d\n",__FILE__,__FUNCTION__,__LINE__,command->getPos().getString().c_str(),ut->getSize()); + canOccupyCell = map->isFreeCells(command->getPos(), ut->getSize(), fLand); break; case pfRoutePlanner: - world->getCartographer()->updateMapMetrics(builtUnit->getPos(), builtUnit->getType()->getSight()); + canOccupyCell = map->canOccupy(command->getPos(), ut->getField(), ut, command->getFacing()); break; default: throw runtime_error("detected unsupported pathfinder type!"); } - command->setUnit(builtUnit); + SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] canOccupyCell = %d\n",__FILE__,__FUNCTION__,__LINE__,canOccupyCell); - //play start sound - if(unit->getFactionIndex() == world->getThisFactionIndex()) { - SoundRenderer::getInstance().playFx( - bct->getStartSound(), - unit->getCurrVector(), - gameCamera->getPos()); + if (canOccupyCell == true) { + const UnitType *builtUnitType= command->getUnitType(); + CardinalDir facing = command->getFacing(); + + UnitPathInterface *newpath = NULL; + switch(this->game->getGameSettings()->getPathFinderType()) { + case pfBasic: + newpath = new UnitPathBasic(); + break; + case pfRoutePlanner: + newpath = new UnitPath(); + break; + default: + throw runtime_error("detected unsupported pathfinder type!"); + } + + //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + Vec2i buildPos = command->getPos(); + Unit *builtUnit= new Unit(world->getNextUnitId(unit->getFaction()), newpath, buildPos, builtUnitType, unit->getFaction(), world->getMap(), facing); + + SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + builtUnit->create(); + + if(builtUnitType->hasSkillClass(scBeBuilt) == false) { + throw runtime_error("Unit " + builtUnitType->getName() + "has no be_built skill"); + } + + builtUnit->setCurrSkill(scBeBuilt); + + unit->setCurrSkill(bct->getBuildSkillType()); + unit->setTarget(builtUnit); + map->prepareTerrain(builtUnit); + + SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + switch(this->game->getGameSettings()->getPathFinderType()) { + case pfBasic: + break; + case pfRoutePlanner: + world->getCartographer()->updateMapMetrics(builtUnit->getPos(), builtUnit->getType()->getSight()); + break; + default: + throw runtime_error("detected unsupported pathfinder type!"); + } + + command->setUnit(builtUnit); + + //play start sound + if(unit->getFactionIndex() == world->getThisFactionIndex()) { + SoundRenderer::getInstance().playFx( + bct->getStartSound(), + unit->getCurrVector(), + gameCamera->getPos()); + } + + SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] unit created for unit [%s]\n",__FILE__,__FUNCTION__,__LINE__,builtUnit->toString().c_str()); } + else { + //if there are no free cells + unit->cancelCommand(); + unit->setCurrSkill(scStop); - SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] unit created for unit [%s]\n",__FILE__,__FUNCTION__,__LINE__,builtUnit->toString().c_str()); - } - else { - //if there are no free cells - unit->cancelCommand(); - unit->setCurrSkill(scStop); + if(unit->getFactionIndex() == world->getThisFactionIndex()) { + console->addStdMessage("BuildingNoPlace"); + } - if(unit->getFactionIndex() == world->getThisFactionIndex()) { - console->addStdMessage("BuildingNoPlace"); + SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] got BuildingNoPlace\n",__FILE__,__FUNCTION__,__LINE__); } + } + break; - SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] got BuildingNoPlace\n",__FILE__,__FUNCTION__,__LINE__); - } - } - break; + case tsBlocked: + if(unit->getPath()->isBlocked()) { + unit->cancelCommand(); - case tsBlocked: - if(unit->getPath()->isBlocked()) { - unit->cancelCommand(); - - SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] got tsBlocked\n",__FILE__,__FUNCTION__,__LINE__); + SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] got tsBlocked\n",__FILE__,__FUNCTION__,__LINE__); + } + break; } - break; - } - + } if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); } else { SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsArrived unit = %s\n",__FILE__,__FUNCTION__,__LINE__,unit->toString().c_str()); - //if building - Unit *builtUnit = map->getCell(unit->getTargetPos())->getUnit(fLand); - if(builtUnit == NULL) { - builtUnit = map->getCell(unit->getTargetPos())->getUnitWithEmptyCellMap(fLand); - } - - if(builtUnit != NULL) { - SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] builtUnit = %s\n",__FILE__,__FUNCTION__,__LINE__,builtUnit->toString().c_str()); - } - - SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] builtUnit = [%p]\n",__FILE__,__FUNCTION__,__LINE__,builtUnit); - - //if unit is killed while building then u==NULL; - if(builtUnit != NULL && builtUnit != command->getUnit()) { - SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] builtUnit is not the command's unit!\n",__FILE__,__FUNCTION__,__LINE__); - unit->setCurrSkill(scStop); - } - else if(builtUnit == NULL || builtUnit->isBuilt()) { - SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] builtUnit is NULL or ALREADY built\n",__FILE__,__FUNCTION__,__LINE__); - - unit->finishCommand(); - unit->setCurrSkill(scStop); - - } - else if(builtUnit == NULL || builtUnit->repair()) { - SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); - - //building finished - unit->finishCommand(); - unit->setCurrSkill(scStop); - - builtUnit->born(); - scriptManager->onUnitCreated(builtUnit); - if(unit->getFactionIndex() == world->getThisFactionIndex()) { - SoundRenderer::getInstance().playFx( - bct->getBuiltSound(), - unit->getCurrVector(), - gameCamera->getPos()); + if(frameIndex < 0) { + //if building + Unit *builtUnit = map->getCell(unit->getTargetPos())->getUnit(fLand); + if(builtUnit == NULL) { + builtUnit = map->getCell(unit->getTargetPos())->getUnitWithEmptyCellMap(fLand); } - } + if(builtUnit != NULL) { + SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] builtUnit = %s\n",__FILE__,__FUNCTION__,__LINE__,builtUnit->toString().c_str()); + } + + SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] builtUnit = [%p]\n",__FILE__,__FUNCTION__,__LINE__,builtUnit); + + //if unit is killed while building then u==NULL; + if(builtUnit != NULL && builtUnit != command->getUnit()) { + SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] builtUnit is not the command's unit!\n",__FILE__,__FUNCTION__,__LINE__); + unit->setCurrSkill(scStop); + } + else if(builtUnit == NULL || builtUnit->isBuilt()) { + SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] builtUnit is NULL or ALREADY built\n",__FILE__,__FUNCTION__,__LINE__); + + unit->finishCommand(); + unit->setCurrSkill(scStop); + + } + else if(builtUnit == NULL || builtUnit->repair()) { + SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + //building finished + unit->finishCommand(); + unit->setCurrSkill(scStop); + + builtUnit->born(); + scriptManager->onUnitCreated(builtUnit); + if(unit->getFactionIndex() == world->getThisFactionIndex()) { + SoundRenderer::getInstance().playFx( + bct->getBuiltSound(), + unit->getCurrVector(), + gameCamera->getPos()); + } + } + } if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); } @@ -722,7 +753,7 @@ void UnitUpdater::updateBuild(Unit *unit) { // ==================== updateHarvest ==================== -void UnitUpdater::updateHarvest(Unit *unit) { +void UnitUpdater::updateHarvest(Unit *unit, int frameIndex) { Chrono chrono; chrono.start(); @@ -766,34 +797,40 @@ void UnitUpdater::updateHarvest(Unit *unit) { if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - if (canHarvestDestPos == true) { - unit->setLastHarvestResourceTarget(NULL); + if (canHarvestDestPos == true ) { + if(frameIndex < 0) { + unit->setLastHarvestResourceTarget(NULL); + } canHarvestDestPos = (map->getSurfaceCell(Map::toSurfCoords(targetPos)) != NULL && map->getSurfaceCell(Map::toSurfCoords(targetPos))->getResource() != NULL && map->getSurfaceCell(Map::toSurfCoords(targetPos))->getResource()->getType() != NULL); + if(canHarvestDestPos == true) { - //if it finds resources it starts harvesting - unit->setCurrSkill(hct->getHarvestSkillType()); - unit->setTargetPos(targetPos); - command->setPos(targetPos); - unit->setLoadCount(0); - unit->getFaction()->addResourceTargetToCache(targetPos); + if(frameIndex < 0) { + //if it finds resources it starts harvesting + unit->setCurrSkill(hct->getHarvestSkillType()); + unit->setTargetPos(targetPos); + command->setPos(targetPos); + unit->setLoadCount(0); + unit->getFaction()->addResourceTargetToCache(targetPos); - switch(this->game->getGameSettings()->getPathFinderType()) { - case pfBasic: - unit->setLoadType(r->getType()); - break; - case pfRoutePlanner: - unit->setLoadType(r->getType()); - break; - default: - throw runtime_error("detected unsupported pathfinder type!"); + switch(this->game->getGameSettings()->getPathFinderType()) { + case pfBasic: + unit->setLoadType(r->getType()); + break; + case pfRoutePlanner: + unit->setLoadType(r->getType()); + break; + default: + throw runtime_error("detected unsupported pathfinder type!"); + } } - if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); } } if(canHarvestDestPos == false) { - unit->setLastHarvestResourceTarget(&targetPos); + if(frameIndex < 0) { + unit->setLastHarvestResourceTarget(&targetPos); + } if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); @@ -809,14 +846,14 @@ void UnitUpdater::updateHarvest(Unit *unit) { TravelState tsValue = tsImpossible; switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: - tsValue = pathFinder->findPath(unit, command->getPos(), &wasStuck); - if (tsValue == tsMoving) { + tsValue = pathFinder->findPath(unit, command->getPos(), &wasStuck, frameIndex); + if (tsValue == tsMoving && frameIndex < 0) { unit->setCurrSkill(hct->getMoveSkillType()); } break; case pfRoutePlanner: tsValue = routePlanner->findPathToResource(unit, command->getPos(), r->getType()); - if (tsValue == tsMoving) { + if (tsValue == tsMoving && frameIndex < 0) { unit->setCurrSkill(hct->getMoveSkillType()); } break; @@ -848,26 +885,30 @@ void UnitUpdater::updateHarvest(Unit *unit) { } if (canHarvestDestPos == true) { - unit->setLastHarvestResourceTarget(NULL); + if(frameIndex < 0) { + unit->setLastHarvestResourceTarget(NULL); + } canHarvestDestPos = (map->getSurfaceCell(Map::toSurfCoords(targetPos)) != NULL && map->getSurfaceCell(Map::toSurfCoords(targetPos))->getResource() != NULL && map->getSurfaceCell(Map::toSurfCoords(targetPos))->getResource()->getType() != NULL); if(canHarvestDestPos == true) { - //if it finds resources it starts harvesting - unit->setCurrSkill(hct->getHarvestSkillType()); - unit->setTargetPos(targetPos); - command->setPos(targetPos); - unit->setLoadCount(0); - unit->getFaction()->addResourceTargetToCache(targetPos); + if(frameIndex < 0) { + //if it finds resources it starts harvesting + unit->setCurrSkill(hct->getHarvestSkillType()); + unit->setTargetPos(targetPos); + command->setPos(targetPos); + unit->setLoadCount(0); + unit->getFaction()->addResourceTargetToCache(targetPos); - switch(this->game->getGameSettings()->getPathFinderType()) { - case pfBasic: - unit->setLoadType(r->getType()); - break; - case pfRoutePlanner: - unit->setLoadType(r->getType()); - break; - default: - throw runtime_error("detected unsupported pathfinder type!"); + switch(this->game->getGameSettings()->getPathFinderType()) { + case pfBasic: + unit->setLoadType(r->getType()); + break; + case pfRoutePlanner: + unit->setLoadType(r->getType()); + break; + default: + throw runtime_error("detected unsupported pathfinder type!"); + } } } @@ -875,7 +916,9 @@ void UnitUpdater::updateHarvest(Unit *unit) { } if(canHarvestDestPos == false) { - unit->setLastHarvestResourceTarget(&targetPos); + if(frameIndex < 0) { + unit->setLastHarvestResourceTarget(&targetPos); + } if(targetPos.x >= 0) { //if not continue walking @@ -891,15 +934,15 @@ void UnitUpdater::updateHarvest(Unit *unit) { TravelState tsValue = tsImpossible; switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: - tsValue = pathFinder->findPath(unit, targetPos, &wasStuck); - if (tsValue == tsMoving) { + tsValue = pathFinder->findPath(unit, targetPos, &wasStuck, frameIndex); + if (tsValue == tsMoving && frameIndex < 0) { unit->setCurrSkill(hct->getMoveSkillType()); command->setPos(targetPos); } break; case pfRoutePlanner: tsValue = routePlanner->findPathToResource(unit, targetPos, r->getType()); - if (tsValue == tsMoving) { + if (tsValue == tsMoving && frameIndex < 0) { unit->setCurrSkill(hct->getMoveSkillType()); command->setPos(targetPos); } @@ -911,7 +954,7 @@ void UnitUpdater::updateHarvest(Unit *unit) { if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - if(wasStuck == true) { + if(wasStuck == true && frameIndex < 0) { //if can't harvest, search for another resource unit->setCurrSkill(scStop); if(searchForResource(unit, hct) == false) { @@ -923,25 +966,24 @@ void UnitUpdater::updateHarvest(Unit *unit) { } } else { - //if can't harvest, search for another resource - unit->setCurrSkill(scStop); - if(searchForResource(unit, hct) == false) { - unit->finishCommand(); + if(frameIndex < 0) { + //if can't harvest, search for another resource + unit->setCurrSkill(scStop); + if(searchForResource(unit, hct) == false) { + unit->finishCommand(); + } } - if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); } if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); } else { - if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); //if loaded, return to store Unit *store= world->nearestStore(unit->getPos(), unit->getFaction()->getIndex(), unit->getLoadType()); - if(store!=NULL) { - + if(store != NULL) { if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true) { char szBuf[4096]=""; sprintf(szBuf,"[updateHarvest #3] unit->getPos() [%s] store->getCenteredPos() [%s]", @@ -952,7 +994,7 @@ void UnitUpdater::updateHarvest(Unit *unit) { TravelState tsValue = tsImpossible; switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: - tsValue = pathFinder->findPath(unit, store->getCenteredPos()); + tsValue = pathFinder->findPath(unit, store->getCenteredPos(), NULL, frameIndex); break; case pfRoutePlanner: tsValue = routePlanner->findPathToStore(unit, store); @@ -963,101 +1005,106 @@ void UnitUpdater::updateHarvest(Unit *unit) { if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - switch(tsValue) { - case tsMoving: - unit->setCurrSkill(hct->getMoveLoadedSkillType()); - break; - default: - break; - } - - //world->changePosCells(unit,unit->getPos()+unit->getDest()); - if(map->isNextTo(unit->getPos(), store)) { - - //update resources - int resourceAmount= unit->getLoadCount(); - if(unit->getFaction()->getCpuControl()) - { - int resourceMultiplierIndex=game->getGameSettings()->getResourceMultiplierIndex(unit->getFaction()->getIndex()); - resourceAmount=(resourceAmount* (resourceMultiplierIndex +5))/10; + if(frameIndex < 0) { + switch(tsValue) { + case tsMoving: + unit->setCurrSkill(hct->getMoveLoadedSkillType()); + break; + default: + break; } - unit->getFaction()->incResourceAmount(unit->getLoadType(), resourceAmount); - world->getStats()->harvest(unit->getFactionIndex(), resourceAmount); - scriptManager->onResourceHarvested(); - //if next to a store unload resources - unit->getPath()->clear(); - unit->setCurrSkill(scStop); - unit->setLoadCount(0); - } + //world->changePosCells(unit,unit->getPos()+unit->getDest()); + if(map->isNextTo(unit->getPos(), store)) { + //update resources + int resourceAmount= unit->getLoadCount(); + if(unit->getFaction()->getCpuControl()) + { + int resourceMultiplierIndex=game->getGameSettings()->getResourceMultiplierIndex(unit->getFaction()->getIndex()); + resourceAmount=(resourceAmount* (resourceMultiplierIndex +5))/10; + } + unit->getFaction()->incResourceAmount(unit->getLoadType(), resourceAmount); + world->getStats()->harvest(unit->getFactionIndex(), resourceAmount); + scriptManager->onResourceHarvested(); + + //if next to a store unload resources + unit->getPath()->clear(); + unit->setCurrSkill(scStop); + unit->setLoadCount(0); + } + } if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); } else { - unit->finishCommand(); + if(frameIndex < 0) { + unit->finishCommand(); + } } } } else { - //if working - //unit->setLastHarvestResourceTarget(NULL); + if(frameIndex < 0) { + //if working + //unit->setLastHarvestResourceTarget(NULL); - if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); + if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - const Vec2i unitTargetPos = unit->getTargetPos(); - SurfaceCell *sc= map->getSurfaceCell(Map::toSurfCoords(unitTargetPos)); - Resource *r= sc->getResource(); + const Vec2i unitTargetPos = unit->getTargetPos(); + SurfaceCell *sc= map->getSurfaceCell(Map::toSurfCoords(unitTargetPos)); + Resource *r= sc->getResource(); - if (r != NULL) { - if (!hct->canHarvest(r->getType()) || r->getType() != unit->getLoadType()) { - // hct has changed to a different harvest command. - unit->setCurrSkill(hct->getStopLoadedSkillType()); // this is actually the wrong animation - unit->getPath()->clear(); + if (r != NULL) { + if (!hct->canHarvest(r->getType()) || r->getType() != unit->getLoadType()) { + // hct has changed to a different harvest command. + unit->setCurrSkill(hct->getStopLoadedSkillType()); // this is actually the wrong animation + unit->getPath()->clear(); - if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - } - else { + if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); + } + else { - // if there is a resource, continue working, until loaded - unit->update2(); + // if there is a resource, continue working, until loaded + unit->update2(); - if (unit->getProgress2() >= hct->getHitsPerUnit()) { - if (unit->getLoadCount() < hct->getMaxLoad()) { - unit->setProgress2(0); - unit->setLoadCount(unit->getLoadCount() + 1); + if (unit->getProgress2() >= hct->getHitsPerUnit()) { + if (unit->getLoadCount() < hct->getMaxLoad()) { + unit->setProgress2(0); + unit->setLoadCount(unit->getLoadCount() + 1); - //if resource exausted, then delete it and stop - if (r->decAmount(1)) { - const ResourceType *rt = r->getType(); - sc->deleteResource(); - unit->getFaction()->removeResourceTargetFromCache(unitTargetPos); + //if resource exausted, then delete it and stop + if (r->decAmount(1)) { + const ResourceType *rt = r->getType(); + sc->deleteResource(); + unit->getFaction()->removeResourceTargetFromCache(unitTargetPos); - switch(this->game->getGameSettings()->getPathFinderType()) { - case pfBasic: - break; - case pfRoutePlanner: - world->getCartographer()->onResourceDepleted(Map::toSurfCoords(unit->getTargetPos()), rt); - break; - default: - throw runtime_error("detected unsupported pathfinder type!"); + switch(this->game->getGameSettings()->getPathFinderType()) { + case pfBasic: + break; + case pfRoutePlanner: + world->getCartographer()->onResourceDepleted(Map::toSurfCoords(unit->getTargetPos()), rt); + break; + default: + throw runtime_error("detected unsupported pathfinder type!"); + } + + unit->setCurrSkill(hct->getStopLoadedSkillType()); } + } + if (unit->getLoadCount() >= hct->getMaxLoad()) { unit->setCurrSkill(hct->getStopLoadedSkillType()); + unit->getPath()->clear(); } } - if (unit->getLoadCount() >= hct->getMaxLoad()) { - unit->setCurrSkill(hct->getStopLoadedSkillType()); - unit->getPath()->clear(); - } + if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); } - - if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); } - } - else { - //if there is no resource, just stop - unit->setCurrSkill(hct->getStopLoadedSkillType()); + else { + //if there is no resource, just stop + unit->setCurrSkill(hct->getStopLoadedSkillType()); + } } } @@ -1181,7 +1228,13 @@ Unit * UnitUpdater::findPeerUnitBuilder(Unit *unit) { // ==================== updateRepair ==================== -void UnitUpdater::updateRepair(Unit *unit) { +void UnitUpdater::updateRepair(Unit *unit, int frameIndex) { + // Nothing to do + if(frameIndex >= 0) { + clearUnitPrecache(unit); + return; + } + Chrono chrono; chrono.start(); @@ -1281,8 +1334,8 @@ void UnitUpdater::updateRepair(Unit *unit) { SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); delete command; - unit->setCurrSkill(scStop); - unit->finishCommand(); + unit->setCurrSkill(scStop); + unit->finishCommand(); } } else { @@ -1296,8 +1349,7 @@ void UnitUpdater::updateRepair(Unit *unit) { // were or are about to be blocked peerUnitBuilder->getPath()->clear(); peerUnitBuilder->setRetryCurrCommandCount(1); - updateUnitCommand(unit); - //updateUnitCommand(peerUnitBuilder); + updateUnitCommand(unit,-1); } return; } @@ -1340,7 +1392,7 @@ void UnitUpdater::updateRepair(Unit *unit) { SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); unit->setTarget(repaired); - unit->setCurrSkill(rct->getRepairSkillType()); + unit->setCurrSkill(rct->getRepairSkillType()); } else { SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); @@ -1358,7 +1410,7 @@ void UnitUpdater::updateRepair(Unit *unit) { case pfBasic: SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); - ts = pathFinder->findPath(unit, repairPos); + ts = pathFinder->findPath(unit, repairPos, NULL, frameIndex); break; case pfRoutePlanner: SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); @@ -1394,7 +1446,7 @@ void UnitUpdater::updateRepair(Unit *unit) { unit->setRetryCurrCommandCount(0); unit->getPath()->clear(); - updateUnitCommand(unit); + updateUnitCommand(unit,-1); } else { unit->finishCommand(); @@ -1409,16 +1461,15 @@ void UnitUpdater::updateRepair(Unit *unit) { else { SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] about to call [scStop]\n",__FILE__,__FUNCTION__,__LINE__); - unit->setCurrSkill(scStop); - unit->finishCommand(); - + unit->setCurrSkill(scStop); + unit->finishCommand(); if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); } } else { SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); - //if repairing + //if repairing if(repaired != NULL) { SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); @@ -1434,8 +1485,8 @@ void UnitUpdater::updateRepair(Unit *unit) { peerUnitBuilder == NULL) { SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] about to call [scStop]\n",__FILE__,__FUNCTION__,__LINE__); - unit->setCurrSkill(scStop); - unit->finishCommand(); + unit->setCurrSkill(scStop); + unit->finishCommand(); if(repaired != NULL && repaired->isBuilt() == false) { SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); @@ -1445,15 +1496,19 @@ void UnitUpdater::updateRepair(Unit *unit) { } if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - } + } } if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); } - // ==================== updateProduce ==================== -void UnitUpdater::updateProduce(Unit *unit) { +void UnitUpdater::updateProduce(Unit *unit, int frameIndex) { + // Nothing to do + if(frameIndex >= 0) { + clearUnitPrecache(unit); + return; + } Chrono chrono; chrono.start(); @@ -1461,7 +1516,7 @@ void UnitUpdater::updateProduce(Unit *unit) { const ProduceCommandType *pct= static_cast(command->getCommandType()); Unit *produced; - if(unit->getCurrSkill()->getClass()!=scProduce){ + if(unit->getCurrSkill()->getClass() != scProduce) { //if not producing unit->setCurrSkill(pct->getProduceSkillType()); } @@ -1520,7 +1575,13 @@ void UnitUpdater::updateProduce(Unit *unit) { // ==================== updateUpgrade ==================== -void UnitUpdater::updateUpgrade(Unit *unit) { +void UnitUpdater::updateUpgrade(Unit *unit, int frameIndex) { + // Nothing to do + if(frameIndex >= 0) { + clearUnitPrecache(unit); + return; + } + Chrono chrono; chrono.start(); @@ -1547,7 +1608,13 @@ void UnitUpdater::updateUpgrade(Unit *unit) { // ==================== updateMorph ==================== -void UnitUpdater::updateMorph(Unit *unit){ +void UnitUpdater::updateMorph(Unit *unit, int frameIndex) { + // Nothing to do + if(frameIndex >= 0) { + clearUnitPrecache(unit); + return; + } + Chrono chrono; chrono.start(); @@ -2003,11 +2070,10 @@ ParticleDamager::ParticleDamager(Unit *attacker, UnitUpdater *unitUpdater, const this->unitUpdater= unitUpdater; } -void ParticleDamager::update(ParticleSystem *particleSystem){ +void ParticleDamager::update(ParticleSystem *particleSystem) { Unit *attacker= attackerRef.getUnit(); - if(attacker!=NULL){ - + if(attacker != NULL) { unitUpdater->hit(attacker, ast, targetPos, targetField); //play sound diff --git a/source/glest_game/world/unit_updater.h b/source/glest_game/world/unit_updater.h index 10245ccf..c79895e0 100644 --- a/source/glest_game/world/unit_updater.h +++ b/source/glest_game/world/unit_updater.h @@ -100,17 +100,17 @@ public: void updateUnit(Unit *unit); //update commands - void updateUnitCommand(Unit *unit); - void updateStop(Unit *unit); - void updateMove(Unit *unit); - void updateAttack(Unit *unit); - void updateAttackStopped(Unit *unit); - void updateBuild(Unit *unit); - void updateHarvest(Unit *unit); - void updateRepair(Unit *unit); - void updateProduce(Unit *unit); - void updateUpgrade(Unit *unit); - void updateMorph(Unit *unit); + void updateUnitCommand(Unit *unit, int frameIndex); + void updateStop(Unit *unit, int frameIndex); + void updateMove(Unit *unit, int frameIndex); + void updateAttack(Unit *unit, int frameIndex); + void updateAttackStopped(Unit *unit, int frameIndex); + void updateBuild(Unit *unit, int frameIndex); + void updateHarvest(Unit *unit, int frameIndex); + void updateRepair(Unit *unit, int frameIndex); + void updateProduce(Unit *unit, int frameIndex); + void updateUpgrade(Unit *unit, int frameIndex); + void updateMorph(Unit *unit, int frameIndex); private: //attack @@ -133,6 +133,7 @@ private: const CommandType *commandType, int originalValue,int newValue); + void clearUnitPrecache(Unit *unit); }; // ===================================================== diff --git a/source/glest_game/world/world.cpp b/source/glest_game/world/world.cpp index a892baed..19f352a3 100644 --- a/source/glest_game/world/world.cpp +++ b/source/glest_game/world/world.cpp @@ -271,8 +271,44 @@ Checksum World::loadScenario(const string &path, Checksum *checksum) { void World::updateAllFactionUnits() { scriptManager->onTimerTriggerEvent(); - //units + + // Signal the faction threads to do any pre-processing int factionCount = getFactionCount(); + for(int i = 0; i < factionCount; ++i) { + Faction *faction = getFaction(i); + if(faction == NULL) { + throw runtime_error("faction == NULL"); + } + faction->signalWorkerThread(frameCount); + } + + bool workThreadsFinished = false; + Chrono chrono; + chrono.start(); + + for(;chrono.getMillis() < 10000;) { + workThreadsFinished = true; + for(int i = 0; i < factionCount; ++i) { + Faction *faction = getFaction(i); + if(faction == NULL) { + throw runtime_error("faction == NULL"); + } + if(faction->isWorkerThreadSignalCompleted(frameCount) == false) { + workThreadsFinished = false; + break; + } + } + if(workThreadsFinished == false) { + sleep(0); + } + else { + break; + } + } + + if(SystemFlags::VERBOSE_MODE_ENABLED && chrono.getMillis() >= 10) printf("In [%s::%s Line: %d] *** Faction thread preprocessing took [%lld] msecs for %d factions for frameCount = %d.\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis(),factionCount,frameCount); + + //units for(int i = 0; i < factionCount; ++i) { Faction *faction = getFaction(i); if(faction == NULL) { @@ -290,6 +326,8 @@ void World::updateAllFactionUnits() { unitUpdater.updateUnit(unit); } } + + if(SystemFlags::VERBOSE_MODE_ENABLED && chrono.getMillis() >= 20) printf("In [%s::%s Line: %d] *** Faction MAIN thread processing took [%lld] msecs for %d factions for frameCount = %d.\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis(),factionCount,frameCount); } void World::underTakeDeadFactionUnits() { diff --git a/source/glest_game/world/world.h b/source/glest_game/world/world.h index dfde2730..3324c34e 100644 --- a/source/glest_game/world/world.h +++ b/source/glest_game/world/world.h @@ -231,6 +231,8 @@ public: void exploreCells(const Vec2i &newPos, int sightRange, int teamIndex); bool showWorldForPlayer(int factionIndex) const; + UnitUpdater * getUnitUpdater() { return &unitUpdater; } + private: void initCells(bool fogOfWar);