ProtoBot
Loading...
Searching...
No Matches
BuildManager Class Reference

The BuildManagers responsibility is to be able to service the ResourceRequests passed to it and verify a unit is able to create the upgrade or combat unit. In the case of buildings more work is required to be able to find suitable locations to make sure that building can be constructed.
The class is also responsible for defining and executing the openings for each race that StarCraft has, allowing ProtoBot to have openers similar to chess at the beginning stages of a StarCraft game. More...

#include <BuildManager.h>

Public Member Functions

 BuildManager (ProtoBotCommander *commanderReference)
void onStart ()
void onFrame (std::vector< ResourceRequest > &resourceRequests)
void onUnitCreate (BWAPI::Unit)
void onUnitDestroy (BWAPI::Unit)
void onUnitMorph (BWAPI::Unit)
void onUnitComplete (BWAPI::Unit)
void onUnitDiscover (BWAPI::Unit)
BWAPI::Unitset getBuildings ()
void initBuildOrdersOnStart ()
void selectBuildOrderAgainstRace (BWAPI::Race enemyRace)
void selectRandomBuildOrder ()
void runBuildOrderOnFrame ()
bool isBuildOrderActive () const
bool checkWorkerIsConstructing (BWAPI::Unit)
bool isBuildOrderCompleted ()
bool checkUnitIsBeingWarpedIn (BWAPI::UnitType building, const BWEM::Base *nexus=nullptr)
BWAPI::Unit getUnitToBuild (BWAPI::Position)
std::vector< NexusEconomygetNexusEconomies ()

Public Attributes

ProtoBotCommandercommanderReference
BuildingPlacer buildingPlacer
std::vector< Builderbuilders
bool buildOrderCompleted = false
BWAPI::Unitset buildings

Private Member Functions

std::string buildOrderNameToString (int name) const
bool enqueueBuildOrderBuilding (BWAPI::UnitType type, int count)
bool enqueueBuildOrderUnit (BWAPI::UnitType type, int count)

Private Attributes

std::vector< BuildOrderbuildOrders
int activeBuildOrderIndex = -1
size_t activeBuildOrderStep = 0
bool buildOrderActive = false

Detailed Description

The BuildManagers responsibility is to be able to service the ResourceRequests passed to it and verify a unit is able to create the upgrade or combat unit. In the case of buildings more work is required to be able to find suitable locations to make sure that building can be constructed.
The class is also responsible for defining and executing the openings for each race that StarCraft has, allowing ProtoBot to have openers similar to chess at the beginning stages of a StarCraft game.

Definition at line 33 of file BuildManager.h.

Constructor & Destructor Documentation

◆ BuildManager()

BuildManager::BuildManager ( ProtoBotCommander * commanderReference)

Definition at line 7 of file BuildManager.cpp.

7 : commanderReference(commanderReference), buildingPlacer(this)
8{
9
10}

Member Function Documentation

◆ buildOrderNameToString()

std::string BuildManager::buildOrderNameToString ( int name) const
private

Definition at line 401 of file BuildManager.cpp.

402{
403 switch (name)
404 {
405 case 1: return "2 Gateway Dark Templar vs Terran";
406 case 2: return "2 Gateway Dark Templar vs Protoss";
407 case 3: return "2 Gateway Observer vs Zerg";
408 }
409}

◆ checkUnitIsBeingWarpedIn()

bool BuildManager::checkUnitIsBeingWarpedIn ( BWAPI::UnitType building,
const BWEM::Base * nexus = nullptr )

Definition at line 349 of file BuildManager.cpp.

350{
351 if (nexus == nullptr)
352 {
353 for (const BWAPI::Unit building : buildings)
354 {
355 if (unit == building->getType() && !building->isCompleted())
356 {
357 return true;
358 }
359 }
360 }
361 else
362 {
363 for (const BWAPI::Unit building : buildings)
364 {
365 if (building->getType() != BWAPI::UnitTypes::Protoss_Assimilator) continue;
366
367 if (unit == building->getType() && !building->isCompleted())
368 {
369 for (BWEM::Geyser* geyer : nexus->Geysers())
370 {
371 if (building->getPosition() == geyer->Pos()) return true;
372 }
373
374 //if (nexusPosition != BWAPI::Positions::Invalid) std::cout << "Nexus at " << nexusPosition << " already has assimilator requested: " << "(Approx. distance " << nexusPosition.getApproxDistance(building->getPosition()) << ")\n";
375 }
376 }
377 }
378
379 return false;
380}

◆ checkWorkerIsConstructing()

bool BuildManager::checkWorkerIsConstructing ( BWAPI::Unit unit)

Definition at line 329 of file BuildManager.cpp.

330{
331 for (Builder& builder : builders)
332 {
333 if (builder.getUnitReference()->getID() == unit->getID()) return true;
334 }
335
336 return false;
337}

◆ enqueueBuildOrderBuilding()

bool BuildManager::enqueueBuildOrderBuilding ( BWAPI::UnitType type,
int count )
private

Definition at line 440 of file BuildManager.cpp.

441{
442 for (int i = 0; i < count; i++)
443 {
444 /*ResourceRequest req;
445 req.type = ResourceRequest::Type::Building;
446 req.unit = type;
447 req.fromBuildOrder = true;
448 resourceRequests.push_back(req);*/
449
450 commanderReference->requestBuilding(type, true);
451 }
452 return true;
453}

◆ enqueueBuildOrderUnit()

bool BuildManager::enqueueBuildOrderUnit ( BWAPI::UnitType type,
int count )
private

Definition at line 455 of file BuildManager.cpp.

456{
457 if (!commanderReference)
458 return false;
459
460 const BWAPI::UnitType trainerType = type.whatBuilds().first;
461 if (trainerType == BWAPI::UnitTypes::None)
462 return false;
463
464 int requestsIssued = 0;
465 for (BWAPI::Unit building : buildings)
466 {
467 if (!building || building->getType() != trainerType)
468 continue;
469 if (!building->isCompleted() || !building->isPowered() || building->isTraining())
470 continue;
471 if (!building->canTrain(type) || commanderReference->alreadySentRequest(building->getID()))
472 continue;
473
474 commanderReference->requestUnit(type, building, true);
475 requestsIssued++;
476
477 if (requestsIssued >= count)
478 return true;
479 }
480
481 return false;
482}

◆ getBuildings()

BWAPI::Unitset BuildManager::getBuildings ( )

Definition at line 339 of file BuildManager.cpp.

340{
341 return buildings;
342}

◆ getNexusEconomies()

std::vector< NexusEconomy > BuildManager::getNexusEconomies ( )

Definition at line 387 of file BuildManager.cpp.

388{
389 return commanderReference->getNexusEconomies();
390}

◆ getUnitToBuild()

BWAPI::Unit BuildManager::getUnitToBuild ( BWAPI::Position position)

Definition at line 382 of file BuildManager.cpp.

383{
384 return commanderReference->getUnitToBuild(position);
385}

◆ initBuildOrdersOnStart()

void BuildManager::initBuildOrdersOnStart ( )

Definition at line 411 of file BuildManager.cpp.

412{
413 buildOrders = BuildOrders::createAll();
414}

◆ isBuildOrderActive()

bool BuildManager::isBuildOrderActive ( ) const

Definition at line 396 of file BuildManager.cpp.

397{
398 return buildOrderActive && !buildOrderCompleted && activeBuildOrderIndex >= 0 && activeBuildOrderIndex < (int)buildOrders.size();
399}

◆ isBuildOrderCompleted()

bool BuildManager::isBuildOrderCompleted ( )

Definition at line 344 of file BuildManager.cpp.

345{
346 return buildOrderCompleted;
347}

◆ onFrame()

void BuildManager::onFrame ( std::vector< ResourceRequest > & resourceRequests)

Definition at line 46 of file BuildManager.cpp.

47{
48 runBuildOrderOnFrame();
49
50 buildingPlacer.drawPoweredTiles();
51
52 //Have to have loop that can check if a building can create a unit and is powered.
53 //Might also need to have some data that shows what each building is doing but might be too complictaed for this approach.
54 for (ResourceRequest& request : resourceRequests)
55 {
56 if (request.state != ResourceRequest::State::Approved_InProgress)
57 {
58 continue;
59 }
60
61 switch (request.type)
62 {
63 case ResourceRequest::Type::Unit:
64 {
65 if (request.requestedBuilding->canTrain(request.unit) &&
66 !request.requestedBuilding->isTraining() &&
67 request.requestedBuilding->isCompleted() &&
68 request.requestedBuilding->isPowered())
69 {
70 if (request.requestedBuilding->train(request.unit))
71 {
72 request.state = ResourceRequest::State::Accepted_Completed;
73 request.frameRequestServiced = BWAPI::Broodwar->getFrameCount();
74 }
75 else
76 {
77 std::cout << "Failed to train unit for whatever reason\n";
78 }
79 }
80
81 break;
82 }
83 case ResourceRequest::Type::Building:
84 {
85 //Should change this to consider distance measure but is fine for now.
86 if (request.isCheese)
87 {
88 request.state = ResourceRequest::State::Approved_BeingBuilt;
89 }
90 else
91 {
92 if (request.placementPos == BWAPI::Positions::Invalid) request.placementInfo = buildingPlacer.getPositionToBuild(request.unit, request.base);
93
94 if (request.placementInfo.position == BWAPI::Positions::Invalid && request.gotPositionToBuild == false)
95 {
96 const PlacementInfo::PlacementFlag flag_info = request.placementInfo.flag;
97
98 switch (flag_info)
99 {
100 case PlacementInfo::NO_POWER:
101 //should create a new pylon request by inserting a pylon in the front of the queue.
102 //std::cout << "FAILED: NO POWER\n";
103 break;
104 case PlacementInfo::NO_BLOCKS:
105 //Wait for a bit and kill the request if no blocks are added
106 //std::cout << "FAILED: NO BLOCKS\n";
107 break;
108 case PlacementInfo::NO_GYSERS:
109 //Shouldnt happen but okay
110 //std::cout << "FAILED: NO GYSERS\n";
111 break;
112 case PlacementInfo::NO_PLACEMENTS:
113 //Wait for a bit and kill the request if no placements are added.
114 //std::cout << "FAILED: NO PLACEMENTS\n";
115 break;
116 case PlacementInfo::NO_EXPANSIONS:
117 //kill the expansion request.
118 //std::cout << "FAILED: NO EXPANSION\n";
119 break;
120 }
121
122 request.attempts++;
123 }
124 else
125 {
126 request.placementPos = request.placementInfo.position;
127 request.tileToPlace = request.placementInfo.topLeft;
128
129 const BWAPI::Unit workerAvalible = getUnitToBuild(request.placementPos);
130
131 if (workerAvalible == nullptr) continue;
132
133 Path pathToLocation;
134 if (request.unit.isResourceDepot())
135 {
136 //std::cout << "Trying to build Nexus\n";
137 pathToLocation = AStar::GeneratePath(workerAvalible->getPosition(), workerAvalible->getType(), request.placementPos);
138 }
139 else if (request.unit.isRefinery())
140 {
141 //std::cout << "Trying to build assimlator\n";
142 pathToLocation = AStar::GeneratePath(workerAvalible->getPosition(), workerAvalible->getType(), request.placementPos, true);
143 }
144 else
145 {
146 //std::cout << "Trying to build regular building\n";
147 pathToLocation = AStar::GeneratePath(workerAvalible->getPosition(), workerAvalible->getType(), request.placementPos);
148 }
149
150 Builder temp = Builder(workerAvalible, request.unit, request.placementPos, pathToLocation);
151 builders.push_back(temp);
152
153 request.state = ResourceRequest::State::Approved_BeingBuilt;
154 request.frameRequestServiced = BWAPI::Broodwar->getFrameCount();
155
156 BWEB::Map::addUsed(request.placementInfo.topLeft, request.unit);
157 }
158 }
159 break;
160 }
161 case ResourceRequest::Type::Upgrade:
162 {
163 if (request.requestedBuilding->canUpgrade(request.upgrade) &&
164 !request.requestedBuilding->isUpgrading() &&
165 request.requestedBuilding->isCompleted() &&
166 request.requestedBuilding->isPowered())
167 {
168 if (request.requestedBuilding->upgrade(request.upgrade))
169 {
170 request.state = ResourceRequest::State::Accepted_Completed;
171 request.frameRequestServiced = BWAPI::Broodwar->getFrameCount();
172 }
173 else
174 {
175 std::cout << "Failed to upgrade for whatever reason\n";
176 }
177 }
178 break;
179 }
180 case ResourceRequest::Type::Tech:
181 {
182 if (request.requestedBuilding->canResearch(request.upgrade) &&
183 !request.requestedBuilding->isResearching() &&
184 request.requestedBuilding->isCompleted() &&
185 request.requestedBuilding->isPowered())
186 {
187 if (request.requestedBuilding->upgrade(request.upgrade))
188 {
189 request.state = ResourceRequest::State::Accepted_Completed;
190 request.frameRequestServiced = BWAPI::Broodwar->getFrameCount();
191 }
192 else
193 {
194 std::cout << "Failed to research tech for whatever reason\n";
195 }
196 }
197 break;
198 }
199 }
200 }
201
202 for (Builder& builder : builders)
203 {
204 builder.onFrame();
205 }
206}
static Path GeneratePath(BWAPI::Position _start, BWAPI::UnitType unitType, BWAPI::Position _end, bool isInteractableEndpoint=false)
Generates path from start to end using A* pathfinding algorithm.

◆ onStart()

void BuildManager::onStart ( )

Definition at line 25 of file BuildManager.cpp.

26{
27 //std::cout << "Builder Manager Initialized" << "\n";
28
29 // Reset per-game state
30 buildOrders.clear();
31 activeBuildOrderIndex = -1;
32 activeBuildOrderStep = 0;
33 //Make false at the start of a game.
34 buildOrderActive = false;
35 buildOrderCompleted = false;
36
37 buildingPlacer.onStart();
38 builders.clear();
39 buildings.clear();
40
41 initBuildOrdersOnStart();
42 selectRandomBuildOrder();
43}

◆ onUnitComplete()

void BuildManager::onUnitComplete ( BWAPI::Unit unit)

Definition at line 318 of file BuildManager.cpp.

319{
320 buildingPlacer.onUnitComplete(unit);
321}

◆ onUnitCreate()

void BuildManager::onUnitCreate ( BWAPI::Unit unit)

Definition at line 208 of file BuildManager.cpp.

209{
210 buildingPlacer.onUnitCreate(unit);
211
212 if (unit->getPlayer() != BWAPI::Broodwar->self()) return;
213
214 //std::cout << unit->getType() << " placed down at tile position " << unit->getTilePosition() << "\n";
215
216 //Remove worker once a building is being warped in.
217 for (std::vector<Builder>::iterator it = builders.begin(); it != builders.end(); ++it)
218 {
219 if (BWAPI::Position(unit->getTilePosition()) == it->requestedPositionToBuild && unit->getType() == it->buildingToConstruct)
220 {
221 //std::cout << "Builder placed down " << unit->getType() << ", removing from builders\n";
222 it = builders.erase(it);
223 break;
224 }
225 }
226
227 if (unit->getType().isBuilding() && !unit->isCompleted()) buildings.insert(unit);
228}

◆ onUnitDestroy()

void BuildManager::onUnitDestroy ( BWAPI::Unit unit)

Definition at line 231 of file BuildManager.cpp.

232{
233 buildingPlacer.onUnitDestroy(unit);
234
235 if (unit->getPlayer() != BWAPI::Broodwar->self())
236 return;
237
238 for (std::vector<Builder>::iterator it = builders.begin(); it != builders.end();)
239 {
240 if (it->getUnitReference()->getID() == unit->getID())
241 {
242 //std::cout << "Builder has died\n";
243
244 const BWAPI::Unit unitAvalible = getUnitToBuild(it->requestedPositionToBuild);
245
246 if (unitAvalible != nullptr)
247 {
248 Path pathToLocation;
249 if (it->buildingToConstruct.isResourceDepot())
250 {
251 //std::cout << "Trying to build Nexus\n";
252 pathToLocation = AStar::GeneratePath(unitAvalible->getPosition(), unitAvalible->getType(), it->requestedPositionToBuild);
253 }
254 else if (it->buildingToConstruct.isRefinery())
255 {
256 //std::cout << "Trying to build assimlator\n";
257 pathToLocation = AStar::GeneratePath(unitAvalible->getPosition(), unitAvalible->getType(), it->requestedPositionToBuild, true);
258 }
259 else
260 {
261 //std::cout << "Trying to build regular building\n";
262 pathToLocation = AStar::GeneratePath(unitAvalible->getPosition(), unitAvalible->getType(), it->requestedPositionToBuild);
263 }
264
265 it->setUnitReference(unitAvalible);
266 it->updatePath(pathToLocation);
267 //std::cout << "Replacement found and updated path\n";
268 }
269 else
270 {
271 //std::cout << "Replacement could not be found\n";
272 }
273
274 break;
275 }
276
277 it++;
278 }
279
280 BWAPI::UnitType unitType = unit->getType();
281
282 if (!unitType.isBuilding()) return;
283
284 //Check if a building has been killed
285 for (const BWAPI::Unit building : buildings)
286 {
287 if (building == unit)
288 {
289 buildings.erase(unit);
290 return;
291 }
292 }
293}

◆ onUnitDiscover()

void BuildManager::onUnitDiscover ( BWAPI::Unit unit)

Definition at line 323 of file BuildManager.cpp.

324{
325 buildingPlacer.onUnitDiscover(unit);
326}

◆ onUnitMorph()

void BuildManager::onUnitMorph ( BWAPI::Unit unit)

Definition at line 295 of file BuildManager.cpp.

296{
297 buildingPlacer.onUnitMorph(unit);
298
299 //std::cout << "Created " << unit->getType() << " (On Morph)\n";
300
301 if (unit->getType() == BWAPI::UnitTypes::Protoss_Assimilator && unit->getPlayer() == BWAPI::Broodwar->self())
302 {
303 for (std::vector<Builder>::iterator it = builders.begin(); it != builders.end(); ++it)
304 {
305 if (unit->getType() == it->buildingToConstruct && BWAPI::Position(unit->getTilePosition()) == it->requestedPositionToBuild)
306 {
307 //std::cout << "Assimilator built at location: " << BWAPI::Position(unit->getTilePosition()) << "\n";
308 //std::cout << "Builder assigned to place at location: " << it->requestedPositionToBuild << "\n";
309 it = builders.erase(it);
310 break;
311 }
312 }
313
314 buildings.insert(unit);
315 }
316}

◆ runBuildOrderOnFrame()

void BuildManager::runBuildOrderOnFrame ( )

Definition at line 484 of file BuildManager.cpp.

485{
486 if (!isBuildOrderActive())
487 return;
488
489 BuildOrder& bo = buildOrders[activeBuildOrderIndex];
490 const int supply = BWAPI::Broodwar->self()->supplyUsed() / 2;
491
492 // Issue steps in order; at most 1 step per frame to avoid spikes
493 if (activeBuildOrderStep >= bo.steps.size())
494 {
495 buildOrderCompleted = true;
496 buildOrderActive = false;
497 //std::cout << "Build Order Completed: " << buildOrderNameToString(bo.name) << "\n";
498 return;
499 }
500
501 BuildOrderStep& step = bo.steps[activeBuildOrderStep];
502
503 bool triggerMet = false;
504 if (step.trigger.type == BuildTriggerType::Immediately) triggerMet = true;
505 if (step.trigger.type == BuildTriggerType::AtSupply && supply >= step.trigger.value) triggerMet = true;
506
507 if (!triggerMet)
508 return;
509
510
511bool issued = false;
512
513switch (step.type)
514{
515 case BuildStepType::ScoutWorker:
516 if (commanderReference) { commanderReference->getUnitToScout(); issued = true; }
517 break;
518 case BuildStepType::Train:
519 issued = enqueueBuildOrderUnit(step.unit, step.count);
520 break;
521 case BuildStepType::Build:
522 default:
523 issued = enqueueBuildOrderBuilding(step.unit, step.count);
524 break;
525}
526
527if (issued)
528 activeBuildOrderStep++;
529}

◆ selectBuildOrderAgainstRace()

void BuildManager::selectBuildOrderAgainstRace ( BWAPI::Race enemyRace)

Definition at line 416 of file BuildManager.cpp.

417{
418 std::vector<int> candidates;
419 for (int i = 0; i < (int)buildOrders.size(); i++)
420 {
421 if (buildOrders[i].vsRace == enemyRace)
422 candidates.push_back(i);
423 }
424
425 activeBuildOrderIndex = candidates[0];
426 //activeBuildOrderIndex = 0;
427 activeBuildOrderStep = 0;
428 buildOrderActive = true;
429 buildOrderCompleted = false;
430
431 std::cout << "Selected Build Order: " << buildOrderNameToString(buildOrders[activeBuildOrderIndex].name) << "\n";
432}

◆ selectRandomBuildOrder()

void BuildManager::selectRandomBuildOrder ( )

Definition at line 434 of file BuildManager.cpp.

435{
436 const BWAPI::Race enemyRace = (BWAPI::Broodwar->enemy()->getRace() != BWAPI::Races::Unknown ? BWAPI::Broodwar->enemy()->getRace() : BWAPI::Races::Unknown);
437 selectBuildOrderAgainstRace(enemyRace);
438}

Member Data Documentation

◆ activeBuildOrderIndex

int BuildManager::activeBuildOrderIndex = -1
private

Definition at line 77 of file BuildManager.h.

◆ activeBuildOrderStep

size_t BuildManager::activeBuildOrderStep = 0
private

Definition at line 78 of file BuildManager.h.

◆ builders

std::vector<Builder> BuildManager::builders

Definition at line 39 of file BuildManager.h.

◆ buildingPlacer

BuildingPlacer BuildManager::buildingPlacer

Definition at line 37 of file BuildManager.h.

◆ buildings

BWAPI::Unitset BuildManager::buildings

Definition at line 43 of file BuildManager.h.

◆ buildOrderActive

bool BuildManager::buildOrderActive = false
private

Definition at line 79 of file BuildManager.h.

◆ buildOrderCompleted

bool BuildManager::buildOrderCompleted = false

Definition at line 41 of file BuildManager.h.

◆ buildOrders

std::vector<BuildOrder> BuildManager::buildOrders
private

Definition at line 76 of file BuildManager.h.

◆ commanderReference

ProtoBotCommander* BuildManager::commanderReference

Definition at line 36 of file BuildManager.h.


The documentation for this class was generated from the following files: