Skip to content

Commit

Permalink
Make FactoryCAI capable of guard, reclaim and repair.
Browse files Browse the repository at this point in the history
  • Loading branch information
saurtron committed Jan 10, 2025
1 parent 6cde9cd commit b3acf9a
Show file tree
Hide file tree
Showing 16 changed files with 1,338 additions and 251 deletions.
1 change: 1 addition & 0 deletions rts/Sim/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ add_library(engineSim STATIC
"${CMAKE_CURRENT_SOURCE_DIR}/Units/CommandAI/CommandDescription.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Units/CommandAI/FactoryCAI.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Units/CommandAI/MobileCAI.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Units/CommandAI/BuilderCaches.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Units/Scripts/CobEngine.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Units/Scripts/CobFile.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Units/Scripts/CobFileHandler.cpp"
Expand Down
3 changes: 2 additions & 1 deletion rts/Sim/Features/FeatureHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "Sim/Ecs/Registry.h"
#include "Sim/Misc/QuadField.h"
#include "Sim/Units/CommandAI/BuilderCAI.h"
#include "Sim/Units/CommandAI/BuilderCaches.h"
#include "System/creg/STL_Set.h"
#include "System/EventHandler.h"
#include "System/TimeProfiler.h"
Expand Down Expand Up @@ -209,7 +210,7 @@ void CFeatureHandler::Update()
bool CFeatureHandler::TryFreeFeatureID(int id)
{
RECOIL_DETAILED_TRACY_ZONE;
if (CBuilderCAI::IsFeatureBeingReclaimed(id)) {
if (CBuilderCaches::IsFeatureBeingReclaimed(id)) {
// postpone putting this ID back into the free pool
// (this gives area-reclaimers time to choose a new
// target with a different ID)
Expand Down
205 changes: 31 additions & 174 deletions rts/Sim/Units/CommandAI/BuilderCAI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "Sim/Units/UnitTypes/Builder.h"
#include "Sim/Units/UnitTypes/Building.h"
#include "Sim/Units/UnitTypes/Factory.h"
#include "Sim/Units/CommandAI/BuilderCaches.h"
#include "System/SpringMath.h"
#include "System/StringUtil.h"
#include "System/EventHandler.h"
Expand Down Expand Up @@ -55,14 +56,6 @@ CR_REG_METADATA(CBuilderCAI , (
CR_PREALLOC(GetPreallocContainer)
))

// not adding to members, should repopulate itself
spring::unordered_set<int> CBuilderCAI::reclaimers;
spring::unordered_set<int> CBuilderCAI::featureReclaimers;
spring::unordered_set<int> CBuilderCAI::resurrecters;

std::vector<int> CBuilderCAI::removees;


static std::string GetUnitDefBuildOptionToolTip(const UnitDef* ud, bool disabled) {
RECOIL_DETAILED_TRACY_ZONE;
std::string tooltip;
Expand Down Expand Up @@ -222,20 +215,12 @@ CBuilderCAI::CBuilderCAI(CUnit* owner):
CBuilderCAI::~CBuilderCAI()
{
RECOIL_DETAILED_TRACY_ZONE;
RemoveUnitFromReclaimers(owner);
RemoveUnitFromFeatureReclaimers(owner);
RemoveUnitFromResurrecters(owner);
CBuilderCaches::RemoveUnitFromReclaimers(owner);
CBuilderCaches::RemoveUnitFromFeatureReclaimers(owner);
CBuilderCaches::RemoveUnitFromResurrecters(owner);
unitHandler.RemoveBuilderCAI(this);
}

void CBuilderCAI::InitStatic()
{
RECOIL_DETAILED_TRACY_ZONE;
spring::clear_unordered_set(reclaimers);
spring::clear_unordered_set(featureReclaimers);
spring::clear_unordered_set(resurrecters);
}

void CBuilderCAI::PostLoad()
{
RECOIL_DETAILED_TRACY_ZONE;
Expand Down Expand Up @@ -779,7 +764,7 @@ void CBuilderCAI::ExecuteRepair(Command& c)
canRepairUnit &= ((unit->beingBuilt) || (unit->unitDef->repairable && (unit->health < unit->maxHealth)));
canRepairUnit &= ((unit != owner) || owner->unitDef->canSelfRepair);
canRepairUnit &= (!unit->soloBuilder || (unit->soloBuilder == owner));
canRepairUnit &= (!c.IsInternalOrder() || (c.GetOpts() & CONTROL_KEY) || !IsUnitBeingReclaimed(unit, owner));
canRepairUnit &= (!c.IsInternalOrder() || (c.GetOpts() & CONTROL_KEY) || !CBuilderCaches::IsUnitBeingReclaimed(unit, owner));
canRepairUnit &= (UpdateTargetLostTimer(unit->id) != 0);

if (canRepairUnit) {
Expand Down Expand Up @@ -950,7 +935,7 @@ void CBuilderCAI::ExecuteGuard(Command& c)
}
}

if (!(c.GetOpts() & CONTROL_KEY) && IsUnitBeingReclaimed(guardee, owner))
if (!(c.GetOpts() & CONTROL_KEY) && CBuilderCaches::IsUnitBeingReclaimed(guardee, owner))
return;

const float3 pos = guardee->pos;
Expand Down Expand Up @@ -1025,8 +1010,8 @@ void CBuilderCAI::ExecuteReclaim(Command& c)
const int rid = FindReclaimTarget(pos, radius, c.GetOpts(), recopt, curdist);
if ((rid > 0) && (rid != uid)) {
StopMoveAndFinishCommand();
RemoveUnitFromReclaimers(owner);
RemoveUnitFromFeatureReclaimers(owner);
CBuilderCaches::RemoveUnitFromReclaimers(owner);
CBuilderCaches::RemoveUnitFromFeatureReclaimers(owner);
return;
}
}
Expand All @@ -1036,21 +1021,21 @@ void CBuilderCAI::ExecuteReclaim(Command& c)
CFeature* feature = featureHandler.GetFeature(uid - unitHandler.MaxUnits());

if (feature != nullptr) {
bool featureBeingResurrected = IsFeatureBeingResurrected(feature->id, owner);
bool featureBeingResurrected = CBuilderCaches::IsFeatureBeingResurrected(feature->id, owner);
featureBeingResurrected &= c.IsInternalOrder();

if (featureBeingResurrected || !ReclaimObject(feature)) {
StopMoveAndFinishCommand();
RemoveUnitFromFeatureReclaimers(owner);
CBuilderCaches::RemoveUnitFromFeatureReclaimers(owner);
} else {
AddUnitToFeatureReclaimers(owner);
CBuilderCaches::AddUnitToFeatureReclaimers(owner);
}
} else {
StopMoveAndFinishCommand();
RemoveUnitFromFeatureReclaimers(owner);
CBuilderCaches::RemoveUnitFromFeatureReclaimers(owner);
}

RemoveUnitFromReclaimers(owner);
CBuilderCaches::RemoveUnitFromReclaimers(owner);
} else { // reclaim unit
CUnit* unit = unitHandler.GetUnit(uid);

Expand All @@ -1068,8 +1053,8 @@ void CBuilderCAI::ExecuteReclaim(Command& c)

if (outOfReclaimRange || busyAlliedBuilder) {
StopMoveAndFinishCommand();
RemoveUnitFromReclaimers(owner);
RemoveUnitFromFeatureReclaimers(owner);
CBuilderCaches::RemoveUnitFromReclaimers(owner);
CBuilderCaches::RemoveUnitFromFeatureReclaimers(owner);
return;
}
}
Expand All @@ -1078,14 +1063,14 @@ void CBuilderCAI::ExecuteReclaim(Command& c)
if (!ReclaimObject(unit)) {
StopMoveAndFinishCommand();
} else {
AddUnitToReclaimers(owner);
CBuilderCaches::AddUnitToReclaimers(owner);
}
} else {
RemoveUnitFromReclaimers(owner);
CBuilderCaches::RemoveUnitFromReclaimers(owner);
StopMoveAndFinishCommand();
}

RemoveUnitFromFeatureReclaimers(owner);
CBuilderCaches::RemoveUnitFromFeatureReclaimers(owner);
}
} else if (c.GetNumParams() == 4) {
// area reclaim
Expand All @@ -1095,8 +1080,8 @@ void CBuilderCAI::ExecuteReclaim(Command& c)
const bool recEnemyOnly = (c.GetOpts() & META_KEY) && (c.GetOpts() & CONTROL_KEY);
const bool recSpecial = !!(c.GetOpts() & CONTROL_KEY);

RemoveUnitFromReclaimers(owner);
RemoveUnitFromFeatureReclaimers(owner);
CBuilderCaches::RemoveUnitFromReclaimers(owner);
CBuilderCaches::RemoveUnitFromFeatureReclaimers(owner);
ownerBuilder->StopBuild();

ReclaimOption recopt = REC_NORESCHECK;
Expand All @@ -1115,8 +1100,8 @@ void CBuilderCAI::ExecuteReclaim(Command& c)

} else {
// wrong number of parameters
RemoveUnitFromReclaimers(owner);
RemoveUnitFromFeatureReclaimers(owner);
CBuilderCaches::RemoveUnitFromReclaimers(owner);
CBuilderCaches::RemoveUnitFromFeatureReclaimers(owner);
StopMoveAndFinishCommand();
}
}
Expand Down Expand Up @@ -1147,16 +1132,16 @@ void CBuilderCAI::ExecuteResurrect(Command& c)
CFeature* feature = featureHandler.GetFeature(id - unitHandler.MaxUnits());

if (feature && feature->udef != nullptr) {
if ((c.IsInternalOrder() && !(c.GetOpts() & CONTROL_KEY) && IsFeatureBeingReclaimed(feature->id, owner)) ||
if ((c.IsInternalOrder() && !(c.GetOpts() & CONTROL_KEY) && CBuilderCaches::IsFeatureBeingReclaimed(feature->id, owner)) ||
!ResurrectObject(feature)) {
RemoveUnitFromResurrecters(owner);
CBuilderCaches::RemoveUnitFromResurrecters(owner);
StopMoveAndFinishCommand();
}
else {
AddUnitToResurrecters(owner);
CBuilderCaches::AddUnitToResurrecters(owner);
}
} else {
RemoveUnitFromResurrecters(owner);
CBuilderCaches::RemoveUnitFromResurrecters(owner);

if (ownerBuilder->lastResurrected && unitHandler.GetUnitUnsafe(ownerBuilder->lastResurrected) != nullptr && owner->unitDef->canRepair) {
// resurrection finished, start repair (by overwriting the current order)
Expand All @@ -1171,7 +1156,7 @@ void CBuilderCAI::ExecuteResurrect(Command& c)
StopMoveAndFinishCommand();
}
} else { // resurrect unit
RemoveUnitFromResurrecters(owner);
CBuilderCaches::RemoveUnitFromResurrecters(owner);
StopMoveAndFinishCommand();
}
} else if (c.GetNumParams() == 4) {
Expand All @@ -1190,7 +1175,7 @@ void CBuilderCAI::ExecuteResurrect(Command& c)

} else {
// wrong number of parameters
RemoveUnitFromResurrecters(owner);
CBuilderCaches::RemoveUnitFromResurrecters(owner);
StopMoveAndFinishCommand();
}
}
Expand Down Expand Up @@ -1386,134 +1371,6 @@ int CBuilderCAI::GetDefaultCmd(const CUnit* pointed, const CFeature* feature)
}


void CBuilderCAI::AddUnitToReclaimers(CUnit* unit) { reclaimers.insert(unit->id); }
void CBuilderCAI::RemoveUnitFromReclaimers(CUnit* unit) { reclaimers.erase(unit->id); }

void CBuilderCAI::AddUnitToFeatureReclaimers(CUnit* unit) { featureReclaimers.insert(unit->id); }
void CBuilderCAI::RemoveUnitFromFeatureReclaimers(CUnit* unit) { featureReclaimers.erase(unit->id); }

void CBuilderCAI::AddUnitToResurrecters(CUnit* unit) { resurrecters.insert(unit->id); }
void CBuilderCAI::RemoveUnitFromResurrecters(CUnit* unit) { resurrecters.erase(unit->id); }


/**
* Checks if a unit is being reclaimed by a friendly con.
*
* We assume that there will not be a lot of reclaimers, because performance
* would suck if there were. Ideally, reclaimers should be assigned on a
* per-unit basis, but this requires tracking of deaths, which albeit
* already done, is not exactly simple to follow.
*
* TODO easy: store reclaiming units per allyteam
* TODO harder: update reclaimers as they start/finish reclaims and/or die
*/
bool CBuilderCAI::IsUnitBeingReclaimed(const CUnit* unit, const CUnit* friendUnit)
{
bool retval = false;

removees.clear();
removees.reserve(reclaimers.size());

for (auto it = reclaimers.begin(); it != reclaimers.end(); ++it) {
const CUnit* u = unitHandler.GetUnit(*it);
const CCommandAI* cai = u->commandAI;
const CCommandQueue& cq = cai->commandQue;

if (cq.empty()) {
removees.push_back(u->id);
continue;
}
const Command& c = cq.front();
if (c.GetID() != CMD_RECLAIM || (c.GetNumParams() != 1 && c.GetNumParams() != 5)) {
removees.push_back(u->id);
continue;
}
const int cmdUnitId = (int)c.GetParam(0);
if (cmdUnitId == unit->id && (friendUnit == nullptr || teamHandler.Ally(friendUnit->allyteam, u->allyteam))) {
retval = true;
break;
}
}

for (auto it = removees.begin(); it != removees.end(); ++it)
RemoveUnitFromReclaimers(unitHandler.GetUnit(*it));

return retval;
}


bool CBuilderCAI::IsFeatureBeingReclaimed(int featureId, const CUnit* friendUnit)
{
RECOIL_DETAILED_TRACY_ZONE;
bool retval = false;

removees.clear();
removees.reserve(featureReclaimers.size());

for (auto it = featureReclaimers.begin(); it != featureReclaimers.end(); ++it) {
const CUnit* u = unitHandler.GetUnit(*it);
const CCommandAI* cai = u->commandAI;
const CCommandQueue& cq = cai->commandQue;

if (cq.empty()) {
removees.push_back(u->id);
continue;
}
const Command& c = cq.front();
if (c.GetID() != CMD_RECLAIM || (c.GetNumParams() != 1 && c.GetNumParams() != 5)) {
removees.push_back(u->id);
continue;
}
const int cmdFeatureId = (int)c.GetParam(0);
if ((cmdFeatureId - unitHandler.MaxUnits()) == featureId && (friendUnit == nullptr || teamHandler.Ally(friendUnit->allyteam, u->allyteam))) {
retval = true;
break;
}
}

for (auto it = removees.begin(); it != removees.end(); ++it)
RemoveUnitFromFeatureReclaimers(unitHandler.GetUnit(*it));

return retval;
}


bool CBuilderCAI::IsFeatureBeingResurrected(int featureId, const CUnit* friendUnit)
{
RECOIL_DETAILED_TRACY_ZONE;
bool retval = false;

removees.clear();
removees.reserve(resurrecters.size());

for (auto it = resurrecters.begin(); it != resurrecters.end(); ++it) {
const CUnit* u = unitHandler.GetUnit(*it);
const CCommandAI* cai = u->commandAI;
const CCommandQueue& cq = cai->commandQue;

if (cq.empty()) {
removees.push_back(u->id);
continue;
}
const Command& c = cq.front();
if (c.GetID() != CMD_RESURRECT || c.GetNumParams() != 1) {
removees.push_back(u->id);
continue;
}
const int cmdFeatureId = (int)c.GetParam(0);
if ((cmdFeatureId - unitHandler.MaxUnits()) == featureId && (friendUnit == nullptr || teamHandler.Ally(friendUnit->allyteam, u->allyteam))) {
retval = true;
break;
}
}

for (auto it = removees.begin(); it != removees.end(); ++it)
RemoveUnitFromResurrecters(unitHandler.GetUnit(*it));

return retval;
}


bool CBuilderCAI::ReclaimObject(CSolidObject* object) {
RECOIL_DETAILED_TRACY_ZONE;
if (MoveInBuildRange(object)) {
Expand Down Expand Up @@ -1610,7 +1467,7 @@ int CBuilderCAI::FindReclaimTarget(const float3& pos, float radius, unsigned cha
if (!owner->unitDef->canmove && !IsInBuildRange(f))
continue;

if (IsFeatureBeingResurrected(f->id, owner))
if (CBuilderCaches::IsFeatureBeingResurrected(f->id, owner))
continue;

metal |= (recSpecial && !metal && f->defResources.metal > 0.0f);
Expand Down Expand Up @@ -1681,7 +1538,7 @@ bool CBuilderCAI::FindResurrectableFeatureAndResurrect(
if (owner->immobile && !IsInBuildRange(f))
continue;

if (!(options & CONTROL_KEY) && IsFeatureBeingReclaimed(f->id, owner))
if (!(options & CONTROL_KEY) && CBuilderCaches::IsFeatureBeingReclaimed(f->id, owner))
continue;

bestDist = dist;
Expand Down Expand Up @@ -1812,7 +1669,7 @@ bool CBuilderCAI::FindRepairTargetAndRepair(
continue;

// don't repair stuff that's being reclaimed
if (!(options & CONTROL_KEY) && IsUnitBeingReclaimed(unit, owner))
if (!(options & CONTROL_KEY) && CBuilderCaches::IsUnitBeingReclaimed(unit, owner))
continue;

stationary |= (!stationary && !unit->IsMoving());
Expand Down
Loading

0 comments on commit b3acf9a

Please sign in to comment.