BWAPI
|
00001 #include "TaskManager.h" 00002 00003 #include <boost/bind.hpp> 00004 00005 #include "UnitGroup.h" 00006 #include "ResourceTracker.h" 00007 #include "IdleTask.h" 00008 #include "Logger.h" 00009 00010 #include "MorphTask.h" 00011 #include "ConstructionTask.h" 00012 #include "TrainTask.h" 00013 #include "UpgradeTask.h" 00014 #include "TechTask.h" 00015 #include "UnitTracker.h" 00016 #include "BuildOrderManager.h" 00017 #include "MacroManager.h" 00018 #include "GameProgressDetection.h" 00019 00020 TaskManagerClass::TaskManagerClass() 00021 { 00022 } 00023 00024 void TaskManagerClass::update() 00025 { 00026 for each(const TaskPointer &task in mTasks) 00027 { 00028 if(task->preUpdate()) 00029 { 00030 for each(Unit unit in task->getFinishedUnits()) 00031 removeTask(unit); 00032 } 00033 } 00034 00035 // Clear previous reservations 00036 ResourceTracker::Instance().reset(); 00037 mReservedUnits.clear(); 00038 00039 for each(TaskType type in getPriorityList()) 00040 { 00041 std::map<TaskType, std::list<TaskPointer>>::iterator l = mTypeTasks.find(type); 00042 00043 if(l != mTypeTasks.end()) 00044 { 00045 for(std::list<TaskPointer>::iterator i = l->second.begin(); i != l->second.end(); ++i) 00046 { 00047 if((*i)->hasEnded()) 00048 continue; 00049 00050 (*i)->updateRequirements(boost::bind<bool>(&TaskManagerClass::updateRequirement, this, *i, _1)); 00051 } 00052 } 00053 } 00054 00055 for(std::map<TaskType, std::list<TaskPointer>>::iterator itFirst = mTypeTasks.begin(); itFirst != mTypeTasks.end(); ++itFirst) 00056 { 00057 for(std::list<TaskPointer>::iterator it = itFirst->second.begin(); it != itFirst->second.end();) 00058 { 00059 if((*it)->update()) 00060 { 00061 //TODO: shouldn't have to but don't delete if it has control of units or just assert 00062 /* 00063 int count = 0; 00064 for(std::map<BWAPI::UnitType, std::map<Unit, TaskPointer>>::iterator it2 = mUnitTasks.begin(); it2 != mUnitTasks.end(); ++it2) 00065 { 00066 for(std::map<Unit, TaskPointer>::iterator it3 = it2->second.begin(); it3 != it2->second.end(); ++it3) 00067 { 00068 if(it3->second == *it) 00069 { 00070 ++count; 00071 } 00072 } 00073 } 00074 00075 if(count > 0) 00076 { 00077 LOGMESSAGE(String_Builder() << "TaskManager : Task " << (*it)->getTaskName() << " " << (*it)->getOutputName() << " deleted while still controlling " << count << " units"); 00078 } 00079 */ 00080 00081 mTasks.erase(*it); 00082 itFirst->second.erase(it++); 00083 } 00084 else 00085 ++it; 00086 } 00087 } 00088 } 00089 00090 std::list<TaskType> TaskManagerClass::getPriorityList() 00091 { 00092 std::list<TaskType> returnList; 00093 00094 //Thing to consider for sorts these: 00095 // If I am vulnerable to counter attack / have no map control, place defense higher 00096 // If I am not behind on army size but its not safe to attack, tech 00097 // If I am not behind on army size but its safe to attack, produce 00098 // If I'm behind on army supply, produce 00099 00100 StateType currentState = GameProgressDetection::Instance().getState(); 00101 00102 returnList.push_back(TaskType::Highest); 00103 returnList.push_back(TaskType::Supply); 00104 returnList.push_back(TaskType::Worker); 00105 returnList.push_back(TaskType::RefineryManager); 00106 returnList.push_back(TaskType::MacroUrgent); 00107 returnList.push_back(TaskType::Scout); 00108 returnList.push_back(TaskType::Expansion); 00109 00110 if(currentState == StateType::TechHigh && BuildOrderManager::Instance().getOrder(Order::MacroCanTech)) 00111 { 00112 returnList.push_back(TaskType::BuildOrder); 00113 returnList.push_back(TaskType::MacroTech); 00114 returnList.push_back(TaskType::Defense); 00115 returnList.push_back(TaskType::Army); 00116 } 00117 else 00118 { 00119 returnList.push_back(TaskType::Army); 00120 returnList.push_back(TaskType::Defense); 00121 returnList.push_back(TaskType::BuildOrder); 00122 } 00123 00124 returnList.push_back(TaskType::Medium); 00125 00126 if(currentState == StateType::TechNormal && BuildOrderManager::Instance().getOrder(Order::MacroCanTech)) 00127 returnList.push_back(TaskType::MacroTech); 00128 00129 returnList.push_back(TaskType::MacroExtraProduction); 00130 00131 if(currentState == StateType::BuildArmy && BuildOrderManager::Instance().getOrder(Order::MacroCanTech)) 00132 returnList.push_back(TaskType::MacroTech); 00133 00134 returnList.push_back(TaskType::Lowest); 00135 00136 return returnList; 00137 } 00138 00139 void TaskManagerClass::onDiscover(Unit unit) 00140 { 00141 if(unit->getPlayer() != BWAPI::Broodwar->self()) 00142 return; 00143 00144 giveTask(unit); 00145 } 00146 00147 void TaskManagerClass::onMorphRenegade(Unit unit, Player previousPlayer, BWAPI::UnitType previousType) 00148 { 00149 if(previousPlayer != NULL) 00150 { 00151 if(previousPlayer == BWAPI::Broodwar->self()) 00152 { 00153 if(previousType != BWAPI::UnitTypes::None) 00154 { 00155 mUnitTasks[previousType][unit]->returnUnit(unit); 00156 if(!mUnitTasks[previousType][unit]->hasEnded()) 00157 mUnitTasks[previousType][unit]->updateRequirements(); 00158 mUnitTasks[previousType].erase(unit); 00159 } 00160 else 00161 { 00162 mUnitTasks[unit->getType()][unit]->returnUnit(unit); 00163 if(!mUnitTasks[unit->getType()][unit]->hasEnded()) 00164 mUnitTasks[unit->getType()][unit]->updateRequirements(); 00165 mUnitTasks[unit->getType()].erase(unit); 00166 } 00167 } 00168 else if(unit->getPlayer() == BWAPI::Broodwar->self()) 00169 { 00170 giveTask(unit); 00171 } 00172 } 00173 else if(previousType != BWAPI::UnitTypes::None && unit->getPlayer() == BWAPI::Broodwar->self()) 00174 { 00175 if(mUnitTasks[previousType][unit]->morph(unit, previousType)) 00176 { 00177 mUnitTasks[previousType][unit]->returnUnit(unit); 00178 if(!mUnitTasks[previousType][unit]->hasEnded()) 00179 mUnitTasks[previousType][unit]->updateRequirements(); 00180 mUnitTasks[previousType].erase(unit); 00181 00182 if(unit->accessibility() == AccessType::Full) 00183 giveTask(unit); 00184 } 00185 else 00186 { 00187 TaskPointer task = mUnitTasks[previousType][unit]; 00188 mUnitTasks[previousType].erase(unit); 00189 mUnitTasks[unit->getType()][unit] = task; 00190 } 00191 } 00192 } 00193 00194 void TaskManagerClass::onDestroy(Unit unit) 00195 { 00196 removeTask(unit); 00197 } 00198 00199 void TaskManagerClass::removeTask(Unit unit) 00200 { 00201 if(mUnitTasks[unit->getType()].find(unit) == mUnitTasks[unit->getType()].end()) 00202 return; 00203 00204 LOGMESSAGE(String_Builder() << "TaskManager : Removed Unit " << unit->getType().getName() << " from " << mUnitTasks[unit->getType()][unit]->getTaskName() << " " << mUnitTasks[unit->getType()][unit]->getOutputName()); 00205 00206 mUnitTasks[unit->getType()][unit]->returnUnit(unit); 00207 if(!mUnitTasks[unit->getType()][unit]->hasEnded()) 00208 mUnitTasks[unit->getType()][unit]->updateRequirements(); 00209 mUnitTasks[unit->getType()].erase(unit); 00210 00211 if(unit->accessibility() == AccessType::Full) 00212 giveTask(unit); 00213 } 00214 00215 void TaskManagerClass::giveTask(Unit unit) 00216 { 00217 TaskPointer bestTask; 00218 int priority = 0; 00219 00220 for each(TaskPointer task in mTasks) 00221 { 00222 if(task->waitingForUnit(unit)) 00223 { 00224 int thisPriority = task->getPriority(unit); 00225 if(thisPriority > priority) 00226 { 00227 priority = thisPriority; 00228 bestTask = task; 00229 } 00230 } 00231 } 00232 00233 if(bestTask) 00234 { 00235 LOGMESSAGE(String_Builder() << "TaskManager : Given new unit " << unit->getType().getName() << " to " << bestTask->getTaskName() << " " << bestTask->getOutputName()); 00236 mUnitTasks[unit->getType()][unit] = bestTask; 00237 bestTask->giveUnit(unit); 00238 } 00239 else 00240 { 00241 LOGMESSAGE(String_Builder() << "TaskManager : Created idle task for " << unit->getType().getName()); 00242 TaskPointer idleTask(new IdleTask(TaskType::Lowest)); 00243 mUnitTasks[unit->getType()][unit] = idleTask; 00244 mTasks.insert(idleTask); 00245 mTypeTasks[idleTask->getType()].push_back(idleTask); 00246 idleTask->giveUnit(unit); 00247 } 00248 } 00249 00250 std::map<int, int> TaskManagerClass::earliestFreeTimes(Unit unit, int priority, int lastBlockEnd, int maxTime, int blockTimeNeeded, bool allowAnyBlockLength) 00251 { 00252 std::map<int, int> suitableBlocks; 00253 00254 // test this priority against the current task to test if we can override it 00255 TaskPointer currentTask = mUnitTasks[unit->getType()][unit]; 00256 if(!currentTask) 00257 { 00258 LOGMESSAGE(String_Builder() << "TaskManager : Tried to access task for unit " << unit->getType().getName() << " that we don't control"); 00259 return suitableBlocks; 00260 } 00261 00262 if(priority <= currentTask->getPriority(unit)) 00263 { 00264 // If we can't get the end time of the task 00265 int endTime = currentTask->getEndTime(unit); 00266 int frametime = BWAPI::Broodwar->getFrameCount(); 00267 assert(endTime >= frametime); 00268 00269 // Get the end time of the current task 00270 lastBlockEnd = std::max(endTime == frametime ? endTime+1 : endTime, lastBlockEnd); 00271 } 00272 00273 // If it has no end return nothing 00274 if(lastBlockEnd == Requirement::maxTime) 00275 return suitableBlocks; 00276 00277 int currentFreeBlockStart = lastBlockEnd; 00278 int currentFreeBlockLength = 0; 00279 00280 for(std::map<int, std::pair<int, int>>::iterator i = mReservedUnits[unit].begin(); i != mReservedUnits[unit].end(); ++i) 00281 { 00282 // This is before our current time slot so we don't need to worry about it 00283 if(i->first + i->second.second < lastBlockEnd) 00284 continue; 00285 00286 // this is after our current time so we should return 00287 if(i->first > maxTime) 00288 return suitableBlocks; 00289 00290 // We can move this block if we are higher priority 00291 bool canMoveThisBlock = priority > i->second.first; 00292 00293 // How long the current block of time we have to fit in is 00294 currentFreeBlockLength += i->first - lastBlockEnd; 00295 00296 // How long will this task last 00297 lastBlockEnd = i->second.second; 00298 00299 // If it will last forever.... 00300 if(lastBlockEnd == Requirement::maxTime) 00301 { 00302 // If we can move this block, steal its time 00303 if(canMoveThisBlock) 00304 suitableBlocks[currentFreeBlockStart] = Requirement::maxTime; 00305 00306 //return as there is no more time to work with 00307 return suitableBlocks; 00308 } 00309 00310 // add the start time so we get the real end 00311 lastBlockEnd += i->first; 00312 00313 // if we cannot move this block 00314 if(!canMoveThisBlock) 00315 { 00316 // If its long enough, or we are looking we are looking for an endless slot 00317 if(currentFreeBlockLength >= blockTimeNeeded || allowAnyBlockLength) 00318 { 00319 suitableBlocks[currentFreeBlockStart] = currentFreeBlockLength; 00320 } 00321 00322 // reset the block length 00323 currentFreeBlockLength = 0; 00324 currentFreeBlockStart = lastBlockEnd; 00325 } 00326 } 00327 00328 // If we made it this far we have the rest of the time for this task 00329 suitableBlocks[lastBlockEnd] = Requirement::maxTime; 00330 00331 return suitableBlocks; 00332 } 00333 00334 void TaskManagerClass::reserveUnit(Unit unit, int time, int priority, int duration) 00335 { 00336 // TODO: change from a map to a sorted vector or sumin, should be faster at updating times 00337 mReservedUnits[unit][time] = std::pair<int, int>(priority, duration); 00338 00339 int lastTaskEndTime = 0; 00340 for(std::map<int, std::pair<int, int>>::iterator i = mReservedUnits[unit].begin(); i != mReservedUnits[unit].end();) 00341 { 00342 if(lastTaskEndTime > i->first) 00343 { 00344 std::pair<int, int> tempTask = i->second; 00345 mReservedUnits[unit].erase(i++); 00346 mReservedUnits[unit][lastTaskEndTime] = tempTask; 00347 00348 lastTaskEndTime += tempTask.second; 00349 } 00350 else 00351 { 00352 lastTaskEndTime = i->first + i->second.second; 00353 ++i; 00354 } 00355 } 00356 } 00357 00358 void TaskManagerClass::addTask(TaskPointer task) 00359 { 00360 LOGMESSAGE(String_Builder() << "TaskManager : New task added : " << task->getTaskName() << " " << task->getOutputName()); 00361 00362 mTypeTasks[task->getType()].push_back(task); 00363 mTasks.insert(task); 00364 00365 if(!task->hasEnded()) 00366 task->updateRequirements(); 00367 } 00368 00369 bool TaskManagerClass::updateRequirement(TaskPointer task, RequirementGroup requirement) 00370 { 00371 if(!requirement.empty()) 00372 { 00373 std::pair<int, int> earliestTime = requirement.earliestTime(); 00374 task->setRequiredSatisfyTime(requirement, earliestTime.first, earliestTime.second); 00375 00376 if(earliestTime.first - earliestTime.second <= BWAPI::Broodwar->getFrameCount()) 00377 { 00378 for each(Unit unit in requirement.getUnits()) 00379 { 00380 TaskPointer oldTask = mUnitTasks[unit->getType()][unit]; 00381 oldTask->returnUnit(unit); 00382 if(!oldTask->hasEnded()) 00383 oldTask->updateRequirements(); 00384 00385 mUnitTasks[unit->getType()][unit] = task; 00386 00387 LOGMESSAGE(String_Builder() << "TaskManager : Taken " << unit->getType().getName() << " from " << oldTask->getTaskName() << " " << oldTask->getOutputName()); 00388 LOGMESSAGE(String_Builder() << "TaskManager : Given " << unit->getType().getName() << " to " << task->getTaskName() << " " << task->getOutputName()); 00389 task->giveUnit(unit); 00390 } 00391 00392 return true; 00393 } 00394 else 00395 { 00396 requirement.reserve(earliestTime.first); 00397 //TODO see what can be done to make this task happen sooner 00398 } 00399 } 00400 00401 return false; 00402 } 00403 00404 TaskPointer TaskManagerClass::build(BWAPI::UnitType type, TaskType taskType, BuildingLocation position) 00405 { 00406 if(type == BWAPI::UnitTypes::None || type == BWAPI::UnitTypes::Unknown) 00407 return TaskPointer(); 00408 00409 if(type.getRace() == BWAPI::Races::Zerg && type.isBuilding() == type.whatBuilds().first.isBuilding()) 00410 { 00411 TaskPointer returnTask = TaskPointer(new MorphTask(taskType, type)); 00412 addTask(returnTask); 00413 MacroManager::Instance().onBuildTask(returnTask, type); 00414 return returnTask; 00415 } 00416 else 00417 { 00418 if(type.isBuilding()) 00419 { 00420 if(type.isAddon()) 00421 { 00422 return TaskPointer(); // NYI 00423 } 00424 else 00425 { 00426 TaskPointer returnTask = TaskPointer(new ConstructionTask(taskType, position, type)); 00427 addTask(returnTask); 00428 MacroManager::Instance().onBuildTask(returnTask, type); 00429 return returnTask; 00430 } 00431 } 00432 else 00433 { 00434 TaskPointer returnTask = TaskPointer(new TrainTask(taskType, type)); 00435 addTask(returnTask); 00436 MacroManager::Instance().onBuildTask(returnTask, type); 00437 return returnTask; 00438 } 00439 } 00440 00441 return TaskPointer(); 00442 } 00443 00444 TaskPointer TaskManagerClass::upgrade(BWAPI::UpgradeType type, int level, TaskType taskType) 00445 { 00446 TaskPointer returnTask = TaskPointer(new UpgradeTask(taskType, type, level)); 00447 addTask(returnTask); 00448 MacroManager::Instance().onUpgradeTask(returnTask, type, level); 00449 return returnTask; 00450 } 00451 00452 TaskPointer TaskManagerClass::research(BWAPI::TechType type, TaskType taskType) 00453 { 00454 TaskPointer returnTask = TaskPointer(new TechTask(taskType, type)); 00455 addTask(returnTask); 00456 MacroManager::Instance().onTechTask(returnTask, type); 00457 return returnTask; 00458 }