📄 unithandler.cpp
字号:
#include "UnitHandler.h"
#include "MetalMaker.h"
CR_BIND(CUnitHandler, (NULL));
CR_REG_METADATA(CUnitHandler, (
CR_MEMBER(IdleUnits),
CR_MEMBER(BuildTasks),
CR_MEMBER(TaskPlans),
CR_MEMBER(AllUnitsByCat),
CR_MEMBER(AllUnitsByType),
CR_MEMBER(Factories),
CR_MEMBER(NukeSilos),
CR_MEMBER(MetalExtractors),
CR_MEMBER(Limbo),
CR_MEMBER(BuilderTrackers),
CR_MEMBER(metalMaker),
CR_MEMBER(ai),
CR_MEMBER(taskPlanCounter),
CR_RESERVED(16)
));
CUnitHandler::CUnitHandler(AIClasses* ai) {
this->ai = ai;
taskPlanCounter = 1;
IdleUnits.resize(LASTCATEGORY);
BuildTasks.resize(LASTCATEGORY);
TaskPlans.resize(LASTCATEGORY);
AllUnitsByCat.resize(LASTCATEGORY);
if (ai) {
AllUnitsByType.resize(ai->cb->GetNumUnitDefs() + 1);
metalMaker = new CMetalMaker(ai);
}
}
CUnitHandler::~CUnitHandler() {
for (list<BuilderTracker*>::iterator i = BuilderTrackers.begin(); i != BuilderTrackers.end(); i++) {
delete *i;
}
}
void CUnitHandler::IdleUnitUpdate(int frame) {
list<integer2> limboremoveunits;
for (list<integer2>::iterator i = Limbo.begin(); i != Limbo.end(); i++) {
if (i->y > 0) {
i->y--;
}
else {
if (ai->cb->GetUnitDef(i->x) == NULL) {
// ignore dead unit
} else {
IdleUnits[ai->ut->GetCategory(i->x)].push_back(i->x);
}
limboremoveunits.push_back(*i);
}
}
if (limboremoveunits.size()) {
for (list<integer2>::iterator i = limboremoveunits.begin(); i != limboremoveunits.end(); i++) {
Limbo.remove(*i);
}
}
// make sure that all the builders are in action (hack?)
if (frame % 15 == 0) {
for (list<BuilderTracker*>::iterator i = BuilderTrackers.begin(); i != BuilderTrackers.end(); i++) {
// the new test
if ((*i)->idleStartFrame != -2) {
// the brand new builders must be filtered still
bool ans = VerifyOrder(*i);
const CCommandQueue* mycommands = ai->cb->GetCurrentUnitCommands((*i)->builderID);
Command c;
if (mycommands->size() > 0)
c = mycommands->front();
// two sec delay is ok
if (((*i)->commandOrderPushFrame + LAG_ACCEPTANCE) < frame) {
if (!ans) {
char text[512];
float3 pos = ai->cb->GetUnitPos((*i)->builderID);
sprintf(text, "builder %i VerifyOrder failed ", (*i)->builderID);
ClearOrder(*i, false);
if (!mycommands->empty())
DecodeOrder(*i, true);
else
IdleUnitAdd((*i)->builderID, frame);
}
}
}
}
}
}
void CUnitHandler::UnitMoveFailed(int unit) {
unit = unit;
}
// called when unit nanoframe first created
// (CEconomyTracker deals with UnitFinished())
void CUnitHandler::UnitCreated(int unit) {
int category = ai->ut->GetCategory(unit);
const UnitDef* newUnitDef = ai->cb->GetUnitDef(unit);
if (category != -1) {
AllUnitsByCat[category].push_back(unit);
AllUnitsByType[newUnitDef->id].push_back(unit);
if (category == CAT_FACTORY) {
FactoryAdd(unit);
}
BuildTaskCreate(unit);
if (category == CAT_BUILDER) {
// add the new builder
BuilderTracker* builderTracker = new BuilderTracker;
builderTracker->builderID = unit;
builderTracker->buildTaskId = 0;
builderTracker->taskPlanId = 0;
builderTracker->factoryId = 0;
builderTracker->stuckCount = 0;
builderTracker->customOrderId = 0;
// under construction
builderTracker->commandOrderPushFrame = -2;
builderTracker->categoryMaker = -1;
// wait for the first idle call, as this unit might be under construction
builderTracker->idleStartFrame = -2;
BuilderTrackers.push_back(builderTracker);
}
if (category == CAT_MMAKER) {
MMakerAdd(unit);
}
if (category == CAT_MEX) {
MetalExtractorAdd(unit);
}
if (category == CAT_NUKE) {
NukeSiloAdd(unit);
}
}
}
void CUnitHandler::UnitDestroyed(int unit) {
int category = ai->ut->GetCategory(unit);
const UnitDef* unitDef = ai->cb->GetUnitDef(unit);
if (category != -1) {
AllUnitsByType[unitDef->id].remove(unit);
AllUnitsByCat[category].remove(unit);
IdleUnitRemove(unit);
BuildTaskRemove(unit);
if (category == CAT_DEFENCE) {
ai->dm->RemoveDefense(ai->cb->GetUnitPos(unit), unitDef);
}
if (category == CAT_MMAKER) {
MMakerRemove(unit);
}
if (category == CAT_FACTORY) {
FactoryRemove(unit);
}
if (category == CAT_BUILDER) {
// remove the builder
for (list<BuilderTracker*>::iterator i = BuilderTrackers.begin(); i != BuilderTrackers.end(); i++) {
if ((*i)->builderID == unit) {
if ((*i)->buildTaskId)
BuildTaskRemove(*i);
if ((*i)->taskPlanId)
TaskPlanRemove(*i);
if ((*i)->factoryId)
FactoryBuilderRemove(*i);
BuilderTracker* builderTracker = *i;
BuilderTrackers.erase(i);
delete builderTracker;
break;
}
}
}
if (category == CAT_MEX) {
MetalExtractorRemove(unit);
}
if (category == CAT_NUKE) {
NukeSiloRemove(unit);
}
}
}
void CUnitHandler::IdleUnitAdd(int unit, int frame) {
int category = ai->ut->GetCategory(unit);
if (category != -1) {
const CCommandQueue* mycommands = ai->cb->GetCurrentUnitCommands(unit);
if (mycommands->empty()) {
if (category == CAT_BUILDER) {
BuilderTracker* builderTracker = GetBuilderTracker(unit);
// add clear here
ClearOrder(builderTracker, true);
if (builderTracker->idleStartFrame == -2) {
// it was in the idle list already?
IdleUnitRemove(builderTracker->builderID);
}
builderTracker->idleStartFrame = -2;
if (builderTracker->commandOrderPushFrame == -2) {
// make sure that if the unit was just built
// it will have some time to leave the factory
builderTracker->commandOrderPushFrame = frame + 30 * 3;
}
}
integer2 myunit(unit, LIMBOTIME);
Limbo.remove(myunit);
Limbo.push_back(myunit);
}
else {
// the unit has orders still
if (category == CAT_BUILDER) {
if (false) {
// KLOOTNOTE: somehow we are now reaching this branch
// on initialization when USE_CREG is not defined,
// mycommands->size() returns garbage?
BuilderTracker* builderTracker = GetBuilderTracker(unit);
DecodeOrder(builderTracker, true);
}
}
}
}
}
bool CUnitHandler::VerifyOrder(BuilderTracker* builderTracker) {
// if it's without orders then try to find the lost command (TODO)
const CCommandQueue* mycommands = ai->cb->GetCurrentUnitCommands(builderTracker->builderID);
bool commandFound = false;
bool hit = false;
if (mycommands->size() > 0) {
// it has orders
const Command* c = &mycommands->front();
if (mycommands->size() == 2) {
// it might have a reclaim order, or terrain change order
// take command nr. 2
c = &mycommands->back();
}
if (builderTracker->buildTaskId != 0) {
hit = true;
// test that this builder is on repair on this unit
BuildTask* buildTask = GetBuildTask(builderTracker->buildTaskId);
if (c->id == CMD_REPAIR && c->params[0] == builderTracker->buildTaskId
|| (c->id == -buildTask->def->id && c->params[0] == buildTask->pos.x && c->params[2] == buildTask->pos.z))
commandFound = true;
else
return false;
}
if (builderTracker->taskPlanId != 0) {
assert(!hit);
hit = true;
TaskPlan* taskPlan = GetTaskPlan(builderTracker->taskPlanId);
if (c->id == -taskPlan->def->id && c->params[0] == taskPlan->pos.x && c->params[2] == taskPlan->pos.z)
commandFound = true;
else
return false;
}
if (builderTracker->factoryId != 0) {
assert(!hit);
hit = true;
if (c->id == CMD_GUARD && c->params[0] == builderTracker->factoryId)
commandFound = true;
else
return false;
}
if (builderTracker->customOrderId != 0) {
assert(!hit);
hit = true;
// CMD_MOVE is for human control stuff, CMD_REPAIR is for repairs of just made stuff
// CMD_GUARD... ?
if (c->id == CMD_RECLAIM || c->id == CMD_MOVE || c->id == CMD_REPAIR)
commandFound = true;
else {
return false;
}
}
if (hit && commandFound) {
// it's on the right job
return true;
}
}
else {
if (builderTracker->idleStartFrame == -2) {
return true;
}
}
return false;
}
// use this only if the unit does not have any orders at the moment
void CUnitHandler::ClearOrder(BuilderTracker* builderTracker, bool reportError) {
bool hit = false;
const CCommandQueue* mycommands = ai->cb->GetCurrentUnitCommands(builderTracker->builderID);
assert(mycommands->empty() || !reportError);
if (builderTracker->buildTaskId != 0) {
// why is this builder idle?
hit = true;
BuildTask* buildTask = GetBuildTask(builderTracker->buildTaskId);
char text[512];
sprintf(text, "builder %i: was idle, but it is on buildTaskId: %i (stuck?)", builderTracker->builderID, builderTracker->buildTaskId);
if (buildTask->builderTrackers.size() > 1) {
BuildTaskRemove(builderTracker);
} else {
// only builder of this thing, and now idle
BuildTaskRemove(builderTracker);
}
}
if (builderTracker->taskPlanId != 0) {
assert(!hit);
hit = true;
// why is this builder idle?
TaskPlan* taskPlan = GetTaskPlan(builderTracker->taskPlanId);
char text[512];
sprintf(text, "builder %i: was idle, but it is on taskPlanId: %s (masking this spot)", builderTracker->builderID, taskPlan->def->humanName.c_str());
ai->dm->MaskBadBuildSpot(taskPlan->pos);
// TODO: fix this, remove all builders from this plan
if (reportError) {
list<BuilderTracker*> builderTrackers = taskPlan->builderTrackers;
for (list<BuilderTracker*>::iterator i = builderTrackers.begin(); i != builderTrackers.end(); i++) {
TaskPlanRemove(*i);
ai->MyUnits[(*i)->builderID]->Stop();
}
} else {
TaskPlanRemove(builderTracker);
}
}
if (builderTracker->factoryId != 0) {
assert(!hit);
hit = true;
// why is this builder idle?
char text[512];
sprintf(text, "builder %i: was idle, but it is on factoryId: %i (removing the builder from the job)", builderTracker->builderID, builderTracker->factoryId);
FactoryBuilderRemove(builderTracker);
}
if (builderTracker->customOrderId != 0) {
assert(!hit);
hit = true;
// why is this builder idle?
// no tracking of custom orders yet
// char text[512];
// sprintf(text, "builder %i: was idle, but it is on customOrderId: %i (removing the builder from the job)", unit, builderTracker->customOrderId);
builderTracker->customOrderId = 0;
}
assert(builderTracker->buildTaskId == 0);
assert(builderTracker->taskPlanId == 0);
assert(builderTracker->factoryId == 0);
assert(builderTracker->customOrderId == 0);
}
void CUnitHandler::DecodeOrder(BuilderTracker* builderTracker, bool reportError) {
// take a look and see what it's doing
const CCommandQueue* mycommands = ai->cb->GetCurrentUnitCommands(builderTracker->builderID);
if (mycommands->size() > 0) {
// builder has orders
const Command* c = &mycommands->front();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -