archive by month
Skip to content

fix for the drone dance bug

Here’s how I rewrote WorkerManager::handleGasWorkers() to solve the drone dance bug whose cause Arrak located. It’s a deadly bug and not fixed in any released Steamhammer version, so if you’re running a fork you probably want this.

First, a pseudocode version to show the structure. The “resource depot” is the command center, nexus, or hatchery. If the resource depot is lost, we need to stop mining from the refinery because the enemy army is likely still around and will kill all our workers 3 at a time as we send them over. (Code elsewhere handles the case where the refinery is destroyed.)

if collecting gas
  for each refinery
    if its resource depot still exists
      add workers to the refinery
    else
      remove workers from the refinery
else
  remove workers from all refineries

Then the actual code. The pseudocode is good, but bugs may lurk in the details. It is new code and poorly tested, especially removing workers from a refinery whose depot is lost. Let me know if you find any remaining bugs.

// Move gas workers on or off gas as necessary.
// NOTE A worker inside a refinery does not accept orders.
void WorkerManager::handleGasWorkers() 
{
	if (_collectGas)
	{
		// Gather gas where possible. Check each refinery.
		for (const auto refinery : BWAPI::Broodwar->self()->getUnits())
		{
			if (refinery->getType().isRefinery() && refinery->isCompleted())
			{
				if (refineryHasDepot(refinery))
				{
					// This is a good refinery. Gather from it.
					// If too few workers are assigned, add more.
					int numAssigned = workerData.getNumAssignedWorkers(refinery);
					for (int i = 0; i < (Config::Macro::WorkersPerRefinery - numAssigned); ++i)
					{
						BWAPI::Unit gasWorker = getGasWorker(refinery);
						if (gasWorker)
						{
							workerData.setWorkerJob(gasWorker, WorkerData::Gas, refinery);
						}
						else
						{
							return;    // won't find any more, either for this refinery or others
						}
					}
				}
				else
				{
					// The refinery has no depot to return gas to. Remove any gas workers.
					std::set gasWorkers;
					workerData.getGasWorkers(gasWorkers);
					for (const auto gasWorker : gasWorkers)
					{
						if (refinery == workerData.getWorkerResource(gasWorker) &&
							gasWorker->getOrder() != BWAPI::Orders::HarvestGas)  // not inside the refinery
						{
							workerData.setWorkerJob(gasWorker, WorkerData::Idle, nullptr);
						}
					}
				}
			}
		}
	}
	else
	{
		// Don't gather gas: If workers are assigned to gas anywhere, take them off.
		std::set gasWorkers;
		workerData.getGasWorkers(gasWorkers);
		for (const auto gasWorker : gasWorkers)
		{
			if (gasWorker->getOrder() != BWAPI::Orders::HarvestGas)    // not inside the refinery
			{
				workerData.setWorkerJob(gasWorker, WorkerData::Idle, nullptr);
				// An idle worker carrying gas will become a ReturnCargo worker,
				// so gas will not be lost needlessly.
			}
		}
	}
}

Trackbacks

No Trackbacks

Comments

MicroDK on :

Your code seems to be right... :D

Add Comment

E-Mail addresses will not be displayed and will only be used for E-Mail notifications.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

Form options

Submitted comments will be subject to moderation before being displayed.