- added more things to try to improve pathfinding (especially for the AI)

AI players should now detect when units are blocked (surrounded by other units from same faction) and tell the other units to move out of the way
This commit is contained in:
Mark Vejvoda 2011-02-25 16:32:27 +00:00
parent c4795eb6cb
commit 9de151d975
9 changed files with 259 additions and 5 deletions

View File

@ -14,6 +14,7 @@
#include "ai_rule.h"
#include "unit_type.h"
#include "unit.h"
#include "map.h"
#include "leak_dumper.h"
using namespace Shared::Graphics;
@ -122,6 +123,7 @@ void Ai::init(AiInterface *aiInterface, int useStartLocation) {
aiRules.push_back(new AiRuleWorkerHarvest(this));
aiRules.push_back(new AiRuleRefreshHarvester(this));
aiRules.push_back(new AiRuleScoutPatrol(this));
aiRules.push_back(new AiRuleUnBlock(this));
aiRules.push_back(new AiRuleReturnBase(this));
aiRules.push_back(new AiRuleMassiveAttack(this));
aiRules.push_back(new AiRuleAddTasks(this));
@ -525,4 +527,152 @@ void Ai::harvest(int unitIndex) {
}
}
bool Ai::haveBlockedUnits() {
int unitCount = aiInterface->getMyUnitCount();
Map *map = aiInterface->getMap();
//If there is no close store
for(int j=0; j < unitCount; ++j) {
const Unit *u= aiInterface->getMyUnit(j);
const UnitType *ut= u->getType();
// If this building is a store
if(u->isAlive() && ut->isMobile() && u->getPath() != NULL && (u->getPath()->isBlocked() || u->getPath()->getBlockCount())) {
Vec2i unitPos = u->getPos();
//printf("#1 AI found blocked unit [%d - %s]\n",u->getId(),u->getFullName().c_str());
int failureCount = 0;
int cellCount = 0;
for(int i = -1; i <= 1; ++i) {
for(int j = -1; j <= 1; ++j) {
Vec2i pos = unitPos + Vec2i(i, j);
if(map->isInside(pos) && map->isInsideSurface(map->toSurfCoords(pos))) {
if(pos != unitPos) {
bool canUnitMoveToCell = map->aproxCanMove(u, unitPos, pos);
if(canUnitMoveToCell == false) {
failureCount++;
}
cellCount++;
}
}
}
}
bool unitImmediatelyBlocked = (failureCount == cellCount);
//printf("#1 unitImmediatelyBlocked = %d, failureCount = %d, cellCount = %d\n",unitImmediatelyBlocked,failureCount,cellCount);
if(unitImmediatelyBlocked) {
//printf("#1 AI unit IS BLOCKED [%d - %s]\n",u->getId(),u->getFullName().c_str());
return true;
}
}
}
return false;
}
bool Ai::getAdjacentUnits(std::map<float, std::map<int, const Unit *> > &signalAdjacentUnits, const Unit *unit) {
bool result = false;
Map *map = aiInterface->getMap();
Vec2i unitPos = unit->getPos();
for(int i = -1; i <= 1; ++i) {
for(int j = -1; j <= 1; ++j) {
Vec2i pos = unitPos + Vec2i(i, j);
if(map->isInside(pos) && map->isInsideSurface(map->toSurfCoords(pos))) {
if(pos != unitPos) {
Unit *adjacentUnit = map->getCell(pos)->getUnit(unit->getCurrField());
if(adjacentUnit != NULL && adjacentUnit->getFactionIndex() == unit->getFactionIndex()) {
if(adjacentUnit->getType()->isMobile() && adjacentUnit->getPath() != NULL) {
//signalAdjacentUnits.push_back(adjacentUnit);
float dist = unitPos.dist(adjacentUnit->getPos());
std::map<float, std::map<int, const Unit *> >::iterator iterFind1 = signalAdjacentUnits.find(dist);
if(iterFind1 == signalAdjacentUnits.end()) {
signalAdjacentUnits[dist][adjacentUnit->getId()] = adjacentUnit;
getAdjacentUnits(signalAdjacentUnits, adjacentUnit);
result = true;
}
else {
std::map<int, const Unit *>::iterator iterFind2 = iterFind1->second.find(adjacentUnit->getId());
if(iterFind2 == iterFind1->second.end()) {
signalAdjacentUnits[dist][adjacentUnit->getId()] = adjacentUnit;
getAdjacentUnits(signalAdjacentUnits, adjacentUnit);
result = true;
}
}
}
}
}
}
}
}
return result;
}
void Ai::unblockUnits() {
int unitCount = aiInterface->getMyUnitCount();
Map *map = aiInterface->getMap();
// Find blocked units and move surrounding units out of the way
std::map<float, std::map<int, const Unit *> > signalAdjacentUnits;
for(int idx=0; idx < unitCount; ++idx) {
const Unit *u= aiInterface->getMyUnit(idx);
const UnitType *ut= u->getType();
// If this building is a store
if(u->isAlive() && ut->isMobile() && u->getPath() != NULL && (u->getPath()->isBlocked() || u->getPath()->getBlockCount())) {
Vec2i unitPos = u->getPos();
//printf("#2 AI found blocked unit [%d - %s]\n",u->getId(),u->getFullName().c_str());
int failureCount = 0;
int cellCount = 0;
for(int i = -1; i <= 1; ++i) {
for(int j = -1; j <= 1; ++j) {
Vec2i pos = unitPos + Vec2i(i, j);
if(map->isInside(pos) && map->isInsideSurface(map->toSurfCoords(pos))) {
if(pos != unitPos) {
bool canUnitMoveToCell = map->aproxCanMove(u, unitPos, pos);
if(canUnitMoveToCell == false) {
failureCount++;
getAdjacentUnits(signalAdjacentUnits, u);
}
cellCount++;
}
}
}
}
//bool unitImmediatelyBlocked = (failureCount == cellCount);
//printf("#2 unitImmediatelyBlocked = %d, failureCount = %d, cellCount = %d, signalAdjacentUnits.size() = %d\n",unitImmediatelyBlocked,failureCount,cellCount,signalAdjacentUnits.size());
}
}
if(signalAdjacentUnits.size() > 0) {
//printf("#2 AI units ARE BLOCKED about to unblock\n");
for(std::map<float, std::map<int, const Unit *> >::reverse_iterator iterMap = signalAdjacentUnits.rbegin();
iterMap != signalAdjacentUnits.rend(); iterMap++) {
for(std::map<int, const Unit *>::iterator iterMap2 = iterMap->second.begin();
iterMap2 != iterMap->second.end(); iterMap2++) {
int idx = iterMap2->first;
const Unit *adjacentUnit = iterMap2->second;
for(int moveAttempt = 1; moveAttempt <= villageRadius; ++moveAttempt) {
Vec2i pos= Vec2i(
random.randRange(-villageRadius*2, villageRadius*2), random.randRange(-villageRadius*2, villageRadius*2)) +
adjacentUnit->getPos();
bool canUnitMoveToCell = map->aproxCanMove(adjacentUnit, adjacentUnit->getPos(), pos);
if(canUnitMoveToCell == true) {
const CommandType *ct = adjacentUnit->getType()->getFirstCtOfClass(ccMove);
CommandResult r = aiInterface->giveCommand(adjacentUnit,ct, pos);
}
}
}
}
}
}
}}//end namespace

View File

@ -145,6 +145,8 @@ private:
Positions expansionPositions;
RandomGen random;
bool getAdjacentUnits(std::map<float, std::map<int, const Unit *> > &signalAdjacentUnits, const Unit *unit);
public:
int minWarriors;
~Ai();
@ -183,6 +185,8 @@ public:
void massiveAttack(const Vec2i &pos, Field field, bool ultraAttack= false);
void returnBase(int unitIndex);
void harvest(int unitIndex);
bool haveBlockedUnits();
void unblockUnits();
};
}}//end namespace

View File

@ -132,7 +132,7 @@ CommandResult AiInterface::giveCommand(int unitIndex, CommandClass commandClass,
}
}
CommandResult AiInterface::giveCommand(Unit *unit, const CommandType *commandType, const Vec2i &pos) {
CommandResult AiInterface::giveCommand(const Unit *unit, const CommandType *commandType, const Vec2i &pos) {
assert(this->gameSettings != NULL);
if(unit == NULL) {
@ -172,7 +172,9 @@ CommandResult AiInterface::giveCommand(Unit *unit, const CommandType *commandTyp
else {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
CommandResult result = unit->giveCommand(new Command(commandType, pos));
Faction *faction = world->getFaction(unit->getFactionIndex());
Unit *unitToCommand = faction->findUnit(unit->getId());
CommandResult result = unitToCommand->giveCommand(new Command(commandType, pos));
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
return result;
@ -613,5 +615,9 @@ const Unit *AiInterface::getFirstOnSightEnemyUnit(Vec2i &pos, Field &field, int
return NULL;
}
Map * AiInterface::getMap() {
Map *map= world->getMap();
return map;
}
}}//end namespace

View File

@ -68,7 +68,7 @@ public:
CommandResult giveCommand(int unitIndex, const CommandType *commandType, const Vec2i &pos, const UnitType* unitType);
CommandResult giveCommand(int unitIndex, const CommandType *commandType, const Vec2i &pos);
CommandResult giveCommand(int unitIndex, const CommandType *commandType, Unit *u= NULL);
CommandResult giveCommand(Unit *unit, const CommandType *commandType, const Vec2i &pos);
CommandResult giveCommand(const Unit *unit, const CommandType *commandType, const Vec2i &pos);
//get data
const ControlType getControlType();
@ -94,6 +94,7 @@ public:
bool checkCosts(const ProducibleType *pt);
bool isFreeCells(const Vec2i &pos, int size, Field field);
const Unit *getFirstOnSightEnemyUnit(Vec2i &pos, Field &field, int radius);
Map * getMap();
private:
string getLogFilename() const {return "ai"+intToStr(factionIndex)+".log";}

View File

@ -1156,4 +1156,23 @@ void AiRuleExpand::execute(){
ai->addPriorityTask(new BuildTask(storeType, expandPos));
}
// ========================================
// class AiRuleUnBlock
// ========================================
AiRuleUnBlock::AiRuleUnBlock(Ai *ai):
AiRule(ai)
{
}
bool AiRuleUnBlock::test() {
return ai->haveBlockedUnits();
}
void AiRuleUnBlock::execute(){
ai->unblockUnits();
}
}}//end namespace

View File

@ -310,6 +310,21 @@ public:
virtual void execute();
};
// =====================================================
// class AiRuleUnBlock
// =====================================================
class AiRuleUnBlock: public AiRule{
public:
AiRuleUnBlock(Ai *ai);
virtual int getTestInterval() const {return 3000;}
virtual string getName() const {return "Blocked Units => Move surrounding units";}
virtual bool test();
virtual void execute();
};
}}//end namespace
#endif

View File

@ -526,6 +526,63 @@ 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());
// First check if unit currently blocked
if(inBailout == false && unitPos != finalPos) {
int failureCount = 0;
int cellCount = 0;
for(int i = -1; i <= 1; ++i) {
for(int j = -1; j <= 1; ++j) {
Vec2i pos = unitPos + Vec2i(i, j);
if(pos != unitPos) {
bool canUnitMoveToCell = map->aproxCanMove(unit, unitPos, pos);
if(canUnitMoveToCell == false) {
failureCount++;
}
cellCount++;
}
}
}
nodeLimitReached = (failureCount == cellCount);
pathFound = !nodeLimitReached;
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 1) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] **Check if dest blocked, distance for unit [%d - %s] from [%s] to [%s] is %.2f took msecs: %lld nodeLimitReached = %d, failureCount = %d\n",__FILE__,__FUNCTION__,__LINE__,unit->getId(),unit->getFullName().c_str(), unitPos.getString().c_str(), finalPos.getString().c_str(), dist,(long long int)chrono.getMillis(),nodeLimitReached,failureCount);
if(showConsoleDebugInfo && nodeLimitReached) {
//if(showConsoleDebugInfo) {
printf("**Check if src blocked [%d - %d], unit [%d - %s] from [%s] to [%s] distance %.2f took msecs: %lld nodeLimitReached = %d, failureCount = %d [%d]\n",
nodeLimitReached, inBailout, unit->getId(),unit->getFullName().c_str(), unitPos.getString().c_str(), finalPos.getString().c_str(), dist,(long long int)chrono.getMillis(),nodeLimitReached,failureCount,cellCount);
}
if(nodeLimitReached == false) {
// First check if final destination blocked
failureCount = 0;
cellCount = 0;
for(int i = -1; i <= 1; ++i) {
for(int j = -1; j <= 1; ++j) {
Vec2i pos = finalPos + Vec2i(i, j);
if(pos != finalPos) {
bool canUnitMoveToCell = map->aproxCanMove(unit, pos, finalPos);
if(canUnitMoveToCell == false) {
failureCount++;
}
cellCount++;
}
}
}
nodeLimitReached = (failureCount == cellCount);
pathFound = !nodeLimitReached;
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 1) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] **Check if dest blocked, distance for unit [%d - %s] from [%s] to [%s] is %.2f took msecs: %lld nodeLimitReached = %d, failureCount = %d\n",__FILE__,__FUNCTION__,__LINE__,unit->getId(),unit->getFullName().c_str(), unitPos.getString().c_str(), finalPos.getString().c_str(), dist,(long long int)chrono.getMillis(),nodeLimitReached,failureCount);
if(showConsoleDebugInfo && nodeLimitReached) {
//if(showConsoleDebugInfo) {
printf("**Check if dest blocked [%d - %d], unit [%d - %s] from [%s] to [%s] distance %.2f took msecs: %lld nodeLimitReached = %d, failureCount = %d [%d]\n",
nodeLimitReached, inBailout, unit->getId(),unit->getFullName().c_str(), unitPos.getString().c_str(), finalPos.getString().c_str(), dist,(long long int)chrono.getMillis(),nodeLimitReached,failureCount,cellCount);
}
}
}
//
int whileLoopCount = 0;
while(nodeLimitReached == false) {
whileLoopCount++;
@ -614,7 +671,7 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos, bool inBailout
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 1) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld nodeLimitReached = %d whileLoopCount = %d nodePoolCount = %d\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis(),nodeLimitReached,whileLoopCount,nodePoolCount);
if(showConsoleDebugInfo && chrono.getMillis() > 2) {
printf("Distance for unit [%d - %s] to destination is %.2f took msecs: %lld nodeLimitReached = %d whileLoopCount = %d nodePoolCount = %d\n",unit->getId(),unit->getFullName().c_str(), dist,(long long int)chrono.getMillis(),nodeLimitReached,whileLoopCount,nodePoolCount);
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);
}
Node *lastNode= node;

View File

@ -1701,7 +1701,7 @@ void Game::render2d(){
str+= "Render FPS: " + intToStr(lastRenderFps) + "[" + intToStr(avgRenderFps) + "]\n";
str+= "Update FPS: " + intToStr(lastUpdateFps) + "[" + intToStr(avgUpdateFps) + "]\n";
str+= "GameCamera pos: " + floatToStr(gameCamera.getPos().x)+","+floatToStr(gameCamera.getPos().y)+","+floatToStr(gameCamera.getPos().z)+"\n";
str+= "Cached surfacedata: " + intToStr(renderer.getCachedSurfaceDataSize());
str+= "Cached surfacedata: " + intToStr(renderer.getCachedSurfaceDataSize())+"\n";
str+= "Time: " + floatToStr(world.getTimeFlow()->getTime(),2)+"\n";
if(SystemFlags::getThreadedLoggerRunning() == true) {
str+= "Log buffer count: " + intToStr(SystemFlags::getLogEntryBufferCount())+"\n";

View File

@ -889,6 +889,8 @@ void MenuStateConnectedGame::update() {
string file = Map::getMapPath(gameSettings->getMap(),"",false);
checksum.addFile(file);
int32 mapCRC = checksum.getSum();
// Test data synch
//mapCRC++;
safeMutexFTPProgress.ReleaseLock();
bool dataSynchMismatch = ((mapCRC != 0 && mapCRC != gameSettings->getMapCRC()) ||