- added more cached information to help deal with units getting stuck while harvesting. Trying to keep them busy instead of standing around.

This commit is contained in:
Mark Vejvoda 2010-10-19 22:26:49 +00:00
parent dda594cf33
commit 913df7ec3b
8 changed files with 327 additions and 48 deletions

View File

@ -20,6 +20,7 @@
#include "unit_type.h"
#include "platform_common.h"
#include "command.h"
#include "faction.h"
#include "leak_dumper.h"
using namespace std;
@ -95,6 +96,7 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu
unit->setCurrentUnitTitle(szBuf);
}
unit->getFaction()->addCachedPath(finalPos,unit);
return tsArrived;
}
else {
@ -105,6 +107,7 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu
Vec2i pos= basicPath->pop();
if(map->canMove(unit, unit->getPos(), pos)) {
unit->setTargetPos(pos);
unit->addCurrentTargetPathTakenCell(finalPos,pos);
return tsMoving;
}
}
@ -124,13 +127,29 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu
}
}
//route cache miss
TravelState ts= aStar(unit, finalPos, false);
TravelState ts = tsImpossible;
std::vector<Vec2i> cachedPath = unit->getFaction()->findCachedPath(finalPos, unit);
if(cachedPath.size() > 0) {
path->clear();
for(int i=0; i < cachedPath.size() && i < pathFindRefresh; ++i) {
path->add(cachedPath[i]);
}
ts = tsMoving;
}
else {
//route cache miss
ts = aStar(unit, finalPos, false);
}
//post actions
switch(ts) {
case tsBlocked:
case 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
if( ts == tsBlocked && unit->getInBailOutAttempt() == false &&
@ -204,6 +223,7 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu
Vec2i pos= basicPath->pop();
if(map->canMove(unit, unit->getPos(), pos)) {
unit->setTargetPos(pos);
unit->addCurrentTargetPathTakenCell(finalPos,pos);
}
else {
unit->setCurrSkill(scStop);

View File

@ -584,6 +584,105 @@ void Faction::resetResourceAmount(const ResourceType *rt){
assert(false);
}
std::vector<Vec2i> Faction::findCachedPath(const Vec2i &target, Unit *unit) {
std::vector<Vec2i> result;
if(successfulPathFinderTargetList.find(target) == successfulPathFinderTargetList.end()) {
// Lets find the shortest and most successful path already taken by a
// similar sized unit
bool foundCachedPath = false;
std::vector<FactionPathSuccessCache> &cacheList = successfulPathFinderTargetList[target];
int unitSize = unit->getType()->getSize();
for(int i = 0; i < cacheList.size(); ++i) {
FactionPathSuccessCache &cache = cacheList[i];
if(cache.unitSize <= unitSize) {
vector<std::pair<vector<Vec2i>, int> > &pathQueue = cache.pathQueue;
for(int j = 0; j < pathQueue.size(); ++j) {
// Now start at the end of the path and see how many nodes
// until we reach a cell near the unit's current position
std::pair<vector<Vec2i>, int> &path = pathQueue[j];
for(int k = path.first.size() - 1; k >= 0; --k) {
if(world->getMap()->canMove(unit, unit->getPos(), path.first[k]) == true) {
if(foundCachedPath == false) {
for(int l = k; l < path.first.size(); ++l) {
result.push_back(path.first[l]);
}
}
else {
if(result.size() > (path.first.size() - k)) {
for(int l = k; l < path.first.size(); ++l) {
result.push_back(path.first[l]);
}
}
}
foundCachedPath = true;
break;
}
}
}
}
}
}
return result;
}
void Faction::addCachedPath(const Vec2i &target, Unit *unit) {
if(successfulPathFinderTargetList.find(target) == successfulPathFinderTargetList.end()) {
FactionPathSuccessCache cache;
cache.unitSize = unit->getType()->getSize();
cache.pathQueue.push_back(make_pair<vector<Vec2i>, int>(unit->getCurrentTargetPathTaken().second,1));
successfulPathFinderTargetList[target].push_back(cache);
}
else {
bool finishedAdd = false;
std::pair<Vec2i,std::vector<Vec2i> > currentTargetPathTaken = unit->getCurrentTargetPathTaken();
std::vector<FactionPathSuccessCache> &cacheList = successfulPathFinderTargetList[target];
int unitSize = unit->getType()->getSize();
for(int i = 0; i < cacheList.size() && finishedAdd == false; ++i) {
FactionPathSuccessCache &cache = cacheList[i];
if(cache.unitSize <= unitSize) {
vector<std::pair<vector<Vec2i>, int> > &pathQueue = cache.pathQueue;
for(int j = 0; j < pathQueue.size() && finishedAdd == false; ++j) {
// Now start at the end of the path and see how many nodes are the same
std::pair<vector<Vec2i>, int> &path = pathQueue[j];
int minPathSize = std::min(path.first.size(),currentTargetPathTaken.second.size());
int intersectIndex = -1;
for(int k = 0; k < minPathSize; ++k) {
if(path.first[path.first.size() - k - 1] != currentTargetPathTaken.second[currentTargetPathTaken.second.size() - k - 1]) {
intersectIndex = k;
break;
}
}
// New path is same or longer than old path so replace
// old path with new
if(intersectIndex + 1 == path.first.size()) {
path.first = currentTargetPathTaken.second;
path.second++;
finishedAdd = true;
}
// Old path is same or longer than new path so
// do nothing
else if(intersectIndex + 1 == currentTargetPathTaken.second.size()) {
path.second++;
finishedAdd = true;
}
}
// If new path is >= 10 cells add it
if(finishedAdd == false && currentTargetPathTaken.second.size() >= 10) {
pathQueue.push_back(make_pair<vector<Vec2i>, int>(currentTargetPathTaken.second,1));
}
}
}
}
}
std::string Faction::toString() const {
std::string result = "";

View File

@ -45,7 +45,15 @@ class World;
/// Each of the game players
// =====================================================
class Faction{
class FactionPathSuccessCache {
public:
// The unit Size for the path findings
int unitSize;
// a List of paths with their # success counts
vector<std::pair<vector<Vec2i>, int> > pathQueue;
};
class Faction {
private:
typedef vector<Resource> Resources;
typedef vector<Resource> Store;
@ -64,7 +72,6 @@ private:
World *world;
ScriptManager *scriptManager;
ControlType control;
Texture2D *texture;
@ -76,6 +83,8 @@ private:
bool thisFaction;
std::map<Vec2i, std::vector<FactionPathSuccessCache> > successfulPathFinderTargetList;
public:
Faction();
~Faction();
@ -143,6 +152,9 @@ public:
void setControlType(ControlType value) { control = value; }
std::vector<Vec2i> findCachedPath(const Vec2i &target, Unit *unit);
void addCachedPath(const Vec2i &target, Unit *unit);
std::string toString() const;
private:

View File

@ -1699,8 +1699,8 @@ void Unit::removeBadHarvestPos(const Vec2i &value) {
cleanupOldBadHarvestPos();
}
bool Unit::isBadHarvestPos(const Vec2i &value) {
cleanupOldBadHarvestPos();
bool Unit::isBadHarvestPos(const Vec2i &value, bool checkPeerUnits) const {
//cleanupOldBadHarvestPos();
bool result = false;
for(int i = 0; i < badHarvestPosList.size(); ++i) {
@ -1711,6 +1711,21 @@ bool Unit::isBadHarvestPos(const Vec2i &value) {
}
}
if(result == false && checkPeerUnits == true) {
// Check if any other units of similar type have this position tagged
// as bad?
for(int i = 0; i < this->getFaction()->getUnitCount(); ++i) {
Unit *peerUnit = this->getFaction()->getUnit(i);
if( peerUnit != NULL && peerUnit->getId() != this->getId() &&
peerUnit->getType()->getSize() <= this->getType()->getSize()) {
if(peerUnit->isBadHarvestPos(value,false) == true) {
result = true;
break;
}
}
}
}
return result;
}
@ -1718,9 +1733,9 @@ void Unit::cleanupOldBadHarvestPos() {
for(int i = badHarvestPosList.size() - 1; i >= 0; --i) {
const std::pair<Vec2i,Chrono> &item = badHarvestPosList[i];
// If this position has been is the list for longer than 120
// If this position has been is the list for longer than 240
// seconds remove it so the unit could potentially try it again
if(item.second.getMillis() >= 1200000) {
if(item.second.getMillis() >= 2400000) {
badHarvestPosList.erase(badHarvestPosList.begin() + i);
}
}
@ -1750,6 +1765,14 @@ void Unit::setLastHarvestResourceTarget(const Vec2i *pos) {
}
}
void Unit::addCurrentTargetPathTakenCell(const Vec2i &target,const Vec2i &cell) {
if(currentTargetPathTaken.first != target) {
currentTargetPathTaken.second.clear();
}
currentTargetPathTaken.first = target;
currentTargetPathTaken.second.push_back(cell);
}
std::string Unit::toString() const {
std::string result = "";

View File

@ -116,6 +116,8 @@ public:
virtual int getBlockCount() const = 0;
virtual int getQueueCount() const = 0;
virtual vector<Vec2i> getQueue() const = 0;
virtual std::string toString() const = 0;
};
@ -141,6 +143,8 @@ public:
virtual int getBlockCount() const { return blockCount; }
virtual int getQueueCount() const { return pathQueue.size(); }
virtual vector<Vec2i> getQueue() const { return pathQueue; }
virtual std::string toString() const;
};
@ -185,6 +189,14 @@ public:
virtual int getBlockCount() const { return blockCount; }
virtual int getQueueCount() const { return this->size(); }
virtual vector<Vec2i> getQueue() const {
vector<Vec2i> result;
for(list<Vec2i>::const_iterator iter = this->begin(); iter != this->end(); ++iter) {
result.push_back(*iter);
}
return result;
}
virtual std::string toString() const;
};
@ -291,6 +303,8 @@ private:
std::vector<std::pair<Vec2i,Chrono> > badHarvestPosList;
std::pair<Vec2i,Chrono> lastHarvestResourceTarget;
std::pair<Vec2i,std::vector<Vec2i> > currentTargetPathTaken;
static Game *game;
public:
@ -439,12 +453,15 @@ public:
void setBadHarvestPosList(std::vector<std::pair<Vec2i,Chrono> > value) { badHarvestPosList = value; }
void addBadHarvestPos(const Vec2i &value);
void removeBadHarvestPos(const Vec2i &value);
bool isBadHarvestPos(const Vec2i &value);
bool isBadHarvestPos(const Vec2i &value,bool checkPeerUnits=true) const;
void cleanupOldBadHarvestPos();
void setLastHarvestResourceTarget(const Vec2i *pos);
std::pair<Vec2i,Chrono> getLastHarvestResourceTarget() const { return lastHarvestResourceTarget;}
std::pair<Vec2i,std::vector<Vec2i> > getCurrentTargetPathTaken() const { return currentTargetPathTaken; }
void addCurrentTargetPathTakenCell(const Vec2i &target,const Vec2i &cell);
std::string toString() const;
private:

View File

@ -24,6 +24,8 @@
#include "game_settings.h"
#include "platform_util.h"
#include "pos_iterator.h"
#include "faction.h"
#include "command.h"
#include "leak_dumper.h"
using namespace Shared::Graphics;
@ -249,7 +251,7 @@ bool Map::isInsideSurface(const Vec2i &sPos) const{
}
//returns if there is a resource next to a unit, in "resourcePos" is stored the relative position of the resource
bool Map::isResourceNear(const Vec2i &pos, const ResourceType *rt, Vec2i &resourcePos, int size, Unit *unit) const {
bool Map::isResourceNear(const Vec2i &pos, const ResourceType *rt, Vec2i &resourcePos, int size, Unit *unit, bool fallbackToPeersHarvestingSameResource) const {
for(int i = -1; i <= size; ++i) {
for(int j = -1; j <= size; ++j) {
if(isInside(pos.x + i, pos.y + j)) {
@ -266,6 +268,29 @@ bool Map::isResourceNear(const Vec2i &pos, const ResourceType *rt, Vec2i &resour
}
}
}
if(fallbackToPeersHarvestingSameResource == true && unit != NULL) {
for(int i = 0; i < unit->getFaction()->getUnitCount(); ++i) {
Unit *peerUnit = unit->getFaction()->getUnit(i);
if( peerUnit != NULL && peerUnit->getId() != unit->getId() &&
peerUnit->getType()->getSize() <= unit->getType()->getSize()) {
if( peerUnit->getCurrSkill()->getClass() == scHarvest &&
peerUnit->getLoadType() == rt &&
peerUnit->getCurrCommand() != NULL) {
if(unit->getPos().dist(peerUnit->getCurrCommand()->getPos()) <= 30) {
if(i == 0 || (unit->getPos().dist(peerUnit->getCurrCommand()->getPos()) < unit->getPos().dist(resourcePos))) {
resourcePos = peerUnit->getCurrCommand()->getPos();
}
if(unit->getPos().dist(peerUnit->getCurrCommand()->getPos()) <= 5) {
resourcePos = peerUnit->getCurrCommand()->getPos();
return true;
}
}
}
}
}
}
return false;
}
@ -384,23 +409,26 @@ bool Map::canOccupy(const Vec2i &pos, Field field, const UnitType *ut, CardinalD
// ==================== unit placement ====================
//checks if a unit can move from between 2 cells
bool Map::canMove(const Unit *unit, const Vec2i &pos1, const Vec2i &pos2) const{
bool Map::canMove(const Unit *unit, const Vec2i &pos1, const Vec2i &pos2) const {
int size= unit->getType()->getSize();
for(int i=pos2.x; i<pos2.x+size; ++i){
for(int j=pos2.y; j<pos2.y+size; ++j){
if(isInside(i, j)){
if(getCell(i, j)->getUnit(unit->getCurrField())!=unit){
if(!isFreeCell(Vec2i(i, j), unit->getCurrField())){
for(int i=pos2.x; i<pos2.x+size; ++i) {
for(int j=pos2.y; j<pos2.y+size; ++j) {
if(isInside(i, j)) {
if(getCell(i, j)->getUnit(unit->getCurrField()) != unit) {
if(isFreeCell(Vec2i(i, j), unit->getCurrField()) == false) {
return false;
}
}
}
else{
else {
return false;
}
}
}
if(unit == NULL || unit->isBadHarvestPos(pos2) == true) {
return false;
}
return true;
}
@ -411,37 +439,47 @@ bool Map::aproxCanMove(const Unit *unit, const Vec2i &pos1, const Vec2i &pos2) c
Field field= unit->getCurrField();
//single cell units
if(size==1){
if(!isAproxFreeCell(pos2, field, teamIndex)){
if(size==1) {
if(isAproxFreeCell(pos2, field, teamIndex) == false){
return false;
}
if(pos1.x!=pos2.x && pos1.y!=pos2.y){
if(!isAproxFreeCell(Vec2i(pos1.x, pos2.y), field, teamIndex)){
if(pos1.x != pos2.x && pos1.y != pos2.y){
if(isAproxFreeCell(Vec2i(pos1.x, pos2.y), field, teamIndex) == false) {
return false;
}
if(!isAproxFreeCell(Vec2i(pos2.x, pos1.y), field, teamIndex)){
if(isAproxFreeCell(Vec2i(pos2.x, pos1.y), field, teamIndex) == false) {
return false;
}
}
if(unit == NULL || unit->isBadHarvestPos(pos2) == true) {
return false;
}
return true;
}
//multi cell units
else{
for(int i=pos2.x; i<pos2.x+size; ++i){
for(int j=pos2.y; j<pos2.y+size; ++j){
else {
for(int i=pos2.x; i<pos2.x+size; ++i) {
for(int j=pos2.y; j<pos2.y+size; ++j) {
if(isInside(i, j)){
if(getCell(i, j)->getUnit(unit->getCurrField())!=unit){
if(!isAproxFreeCell(Vec2i(i, j), field, teamIndex)){
if(getCell(i, j)->getUnit(unit->getCurrField())!=unit) {
if(isAproxFreeCell(Vec2i(i, j), field, teamIndex) == false) {
return false;
}
}
}
else{
else {
return false;
}
}
}
if(unit == NULL || unit->isBadHarvestPos(pos2) == true) {
return false;
}
return true;
}
}

View File

@ -197,7 +197,7 @@ public:
bool isInside(const Vec2i &pos) const;
bool isInsideSurface(int sx, int sy) const;
bool isInsideSurface(const Vec2i &sPos) const;
bool isResourceNear(const Vec2i &pos, const ResourceType *rt, Vec2i &resourcePos, int size, Unit *unit=NULL) const;
bool isResourceNear(const Vec2i &pos, const ResourceType *rt, Vec2i &resourcePos, int size, Unit *unit=NULL,bool fallbackToPeersHarvestingSameResource=false) const;
bool isResourceNear(const Vec2i &pos, int size, const ResourceType *rt, Vec2i &resourcePos) const;
//free cells

View File

@ -591,6 +591,8 @@ void UnitUpdater::updateHarvest(Unit *unit) {
if(r != NULL && hct->canHarvest(r->getType())) {
//if can harvest dest. pos
bool canHarvestDestPos = false;
targetPos.x = -1;
targetPos.y = -1;
switch(this->game->getGameSettings()->getPathFinderType()) {
case pfBasic:
@ -607,24 +609,27 @@ void UnitUpdater::updateHarvest(Unit *unit) {
if (canHarvestDestPos == true) {
unit->setLastHarvestResourceTarget(NULL);
//if it finds resources it starts harvesting
unit->setCurrSkill(hct->getHarvestSkillType());
unit->setTargetPos(targetPos);
command->setPos(targetPos);
unit->setLoadCount(0);
canHarvestDestPos == (map->getSurfaceCell(Map::toSurfCoords(targetPos))->getResource() != NULL);
if(canHarvestDestPos == true) {
//if it finds resources it starts harvesting
unit->setCurrSkill(hct->getHarvestSkillType());
unit->setTargetPos(targetPos);
command->setPos(targetPos);
unit->setLoadCount(0);
switch(this->game->getGameSettings()->getPathFinderType()) {
case pfBasic:
unit->setLoadType(map->getSurfaceCell(Map::toSurfCoords(unit->getTargetPos()))->getResource()->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(map->getSurfaceCell(Map::toSurfCoords(unit->getTargetPos()))->getResource()->getType());
break;
case pfRoutePlanner:
unit->setLoadType(r->getType());
break;
default:
throw runtime_error("detected unsupported pathfinder type!");
}
}
}
else {
if(canHarvestDestPos == false) {
unit->setLastHarvestResourceTarget(&targetPos);
//if not continue walking
@ -648,10 +653,75 @@ void UnitUpdater::updateHarvest(Unit *unit) {
}
if(wasStuck == true) {
//if can't harvest, search for another resource
unit->setCurrSkill(scStop);
if(searchForResource(unit, hct) == false) {
unit->finishCommand();
switch(this->game->getGameSettings()->getPathFinderType()) {
case pfBasic:
canHarvestDestPos = (unit->getPos().dist(command->getPos()) < harvestDistance &&
map->isResourceNear(unit->getPos(), r->getType(), targetPos,unit->getType()->getSize(),unit, true));
break;
case pfRoutePlanner:
canHarvestDestPos = map->isResourceNear(unit->getPos(), unit->getType()->getSize(), r->getType(), targetPos);
break;
default:
throw runtime_error("detected unsupported pathfinder type!");
}
if (canHarvestDestPos == true) {
unit->setLastHarvestResourceTarget(NULL);
canHarvestDestPos == (map->getSurfaceCell(Map::toSurfCoords(targetPos))->getResource() != NULL);
if(canHarvestDestPos == true) {
//if it finds resources it starts harvesting
unit->setCurrSkill(hct->getHarvestSkillType());
unit->setTargetPos(targetPos);
command->setPos(targetPos);
unit->setLoadCount(0);
switch(this->game->getGameSettings()->getPathFinderType()) {
case pfBasic:
unit->setLoadType(map->getSurfaceCell(Map::toSurfCoords(unit->getTargetPos()))->getResource()->getType());
break;
case pfRoutePlanner:
unit->setLoadType(r->getType());
break;
default:
throw runtime_error("detected unsupported pathfinder type!");
}
}
}
if(canHarvestDestPos == false) {
unit->setLastHarvestResourceTarget(&targetPos);
if(targetPos.x >= 0) {
//if not continue walking
wasStuck = false;
TravelState tsValue = tsImpossible;
switch(this->game->getGameSettings()->getPathFinderType()) {
case pfBasic:
tsValue = pathFinder->findPath(unit, targetPos, &wasStuck);
if (tsValue == tsMoving) {
unit->setCurrSkill(hct->getMoveSkillType());
command->setPos(targetPos);
}
break;
case pfRoutePlanner:
tsValue = routePlanner->findPathToResource(unit, targetPos, r->getType());
if (tsValue == tsMoving) {
unit->setCurrSkill(hct->getMoveSkillType());
command->setPos(targetPos);
}
break;
default:
throw runtime_error("detected unsupported pathfinder type!");
}
}
if(wasStuck == true) {
//if can't harvest, search for another resource
unit->setCurrSkill(scStop);
if(searchForResource(unit, hct) == false) {
unit->finishCommand();
}
}
}
}
}