- 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 "ai_rule.h"
#include "unit_type.h" #include "unit_type.h"
#include "unit.h" #include "unit.h"
#include "map.h"
#include "leak_dumper.h" #include "leak_dumper.h"
using namespace Shared::Graphics; 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 AiRuleWorkerHarvest(this));
aiRules.push_back(new AiRuleRefreshHarvester(this)); aiRules.push_back(new AiRuleRefreshHarvester(this));
aiRules.push_back(new AiRuleScoutPatrol(this)); aiRules.push_back(new AiRuleScoutPatrol(this));
aiRules.push_back(new AiRuleUnBlock(this));
aiRules.push_back(new AiRuleReturnBase(this)); aiRules.push_back(new AiRuleReturnBase(this));
aiRules.push_back(new AiRuleMassiveAttack(this)); aiRules.push_back(new AiRuleMassiveAttack(this));
aiRules.push_back(new AiRuleAddTasks(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 }}//end namespace

View File

@ -145,6 +145,8 @@ private:
Positions expansionPositions; Positions expansionPositions;
RandomGen random; RandomGen random;
bool getAdjacentUnits(std::map<float, std::map<int, const Unit *> > &signalAdjacentUnits, const Unit *unit);
public: public:
int minWarriors; int minWarriors;
~Ai(); ~Ai();
@ -183,6 +185,8 @@ public:
void massiveAttack(const Vec2i &pos, Field field, bool ultraAttack= false); void massiveAttack(const Vec2i &pos, Field field, bool ultraAttack= false);
void returnBase(int unitIndex); void returnBase(int unitIndex);
void harvest(int unitIndex); void harvest(int unitIndex);
bool haveBlockedUnits();
void unblockUnits();
}; };
}}//end namespace }}//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); assert(this->gameSettings != NULL);
if(unit == NULL) { if(unit == NULL) {
@ -172,7 +172,9 @@ CommandResult AiInterface::giveCommand(Unit *unit, const CommandType *commandTyp
else { else {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); 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__); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
return result; return result;
@ -613,5 +615,9 @@ const Unit *AiInterface::getFirstOnSightEnemyUnit(Vec2i &pos, Field &field, int
return NULL; return NULL;
} }
Map * AiInterface::getMap() {
Map *map= world->getMap();
return map;
}
}}//end namespace }}//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, const UnitType* unitType);
CommandResult giveCommand(int unitIndex, const CommandType *commandType, const Vec2i &pos); CommandResult giveCommand(int unitIndex, const CommandType *commandType, const Vec2i &pos);
CommandResult giveCommand(int unitIndex, const CommandType *commandType, Unit *u= NULL); 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 //get data
const ControlType getControlType(); const ControlType getControlType();
@ -94,6 +94,7 @@ public:
bool checkCosts(const ProducibleType *pt); bool checkCosts(const ProducibleType *pt);
bool isFreeCells(const Vec2i &pos, int size, Field field); bool isFreeCells(const Vec2i &pos, int size, Field field);
const Unit *getFirstOnSightEnemyUnit(Vec2i &pos, Field &field, int radius); const Unit *getFirstOnSightEnemyUnit(Vec2i &pos, Field &field, int radius);
Map * getMap();
private: private:
string getLogFilename() const {return "ai"+intToStr(factionIndex)+".log";} string getLogFilename() const {return "ai"+intToStr(factionIndex)+".log";}

View File

@ -1156,4 +1156,23 @@ void AiRuleExpand::execute(){
ai->addPriorityTask(new BuildTask(storeType, expandPos)); 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 }}//end namespace

View File

@ -310,6 +310,21 @@ public:
virtual void execute(); 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 }}//end namespace
#endif #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()); 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; int whileLoopCount = 0;
while(nodeLimitReached == false) { while(nodeLimitReached == false) {
whileLoopCount++; 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(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) { 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; Node *lastNode= node;

View File

@ -1701,7 +1701,7 @@ void Game::render2d(){
str+= "Render FPS: " + intToStr(lastRenderFps) + "[" + intToStr(avgRenderFps) + "]\n"; str+= "Render FPS: " + intToStr(lastRenderFps) + "[" + intToStr(avgRenderFps) + "]\n";
str+= "Update FPS: " + intToStr(lastUpdateFps) + "[" + intToStr(avgUpdateFps) + "]\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+= "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"; str+= "Time: " + floatToStr(world.getTimeFlow()->getTime(),2)+"\n";
if(SystemFlags::getThreadedLoggerRunning() == true) { if(SystemFlags::getThreadedLoggerRunning() == true) {
str+= "Log buffer count: " + intToStr(SystemFlags::getLogEntryBufferCount())+"\n"; str+= "Log buffer count: " + intToStr(SystemFlags::getLogEntryBufferCount())+"\n";

View File

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