📄 economytracker.cpp
字号:
#include "EconomyTracker.h"
CR_BIND(BuildingTracker, )
CR_REG_METADATA(BuildingTracker, (
CR_MEMBER(unitUnderConstruction),
CR_MEMBER(category),
CR_MEMBER(hpLastFrame),
CR_MEMBER(damage),
CR_MEMBER(hpSomeTimeAgo),
CR_MEMBER(damageSomeTimeAgo),
CR_MEMBER(startedRealBuildingFrame),
CR_MEMBER(etaFrame),
CR_MEMBER(maxTotalBuildPower),
CR_MEMBER(assignedTotalBuildPower),
CR_MEMBER(energyUsage),
CR_MEMBER(metalUsage),
CR_MEMBER(buildTask),
CR_MEMBER(factory),
CR_MEMBER(economyUnitTracker),
CR_RESERVED(16)
));
CR_BIND(EconomyUnitTracker, )
CR_REG_METADATA(EconomyUnitTracker, (
CR_MEMBER(economyUnitId),
CR_MEMBER(createFrame),
CR_MEMBER(buildingTracker),
CR_MEMBER(alive),
CR_MEMBER(dieFrame),
CR_MEMBER(category),
CR_MEMBER(totalEnergyMake),
CR_MEMBER(totalMetalMake),
CR_MEMBER(totalEnergyUsage),
CR_MEMBER(totalMetalUsage),
CR_MEMBER(lastUpdateEnergyMake),
CR_MEMBER(lastUpdateMetalMake),
CR_MEMBER(lastUpdateEnergyUsage),
CR_MEMBER(lastUpdateMetalUsage),
CR_MEMBER(dynamicChangingUsage),
CR_MEMBER(nonEconomicUnit),
CR_MEMBER(estimateEnergyChangeFromDefWhileOn),
CR_MEMBER(estimateMetalChangeFromDefWhileOn),
CR_MEMBER(estimateEnergyChangeFromDefWhileOff),
CR_MEMBER(estimateMetalChangeFromDefWhileOff),
CR_RESERVED(16),
CR_POSTLOAD(PostLoad)
));
CR_BIND(CEconomyTracker, (NULL));
CR_REG_METADATA(CEconomyTracker, (
CR_MEMBER(allTheBuildingTrackers),
CR_MEMBER(deadEconomyUnitTrackers),
CR_MEMBER(newEconomyUnitTrackers),
CR_MEMBER(activeEconomyUnitTrackers),
CR_MEMBER(underConstructionEconomyUnitTrackers),
CR_MEMBER(ai),
CR_MEMBER(trackerOff),
CR_MEMBER(constructionEnergy),
CR_MEMBER(constructionMetal),
CR_MEMBER(constructionEnergySum),
CR_MEMBER(constructionMetalSum),
CR_RESERVED(16)
));
CEconomyTracker::CEconomyTracker(AIClasses* ai) {
this->ai = ai;
allTheBuildingTrackers.resize(LASTCATEGORY);
if (ai) {
oldEnergy = ai->cb->GetEnergy();
oldMetal = ai->cb->GetMetal();
}
constructionEnergySum = 0;
constructionMetalSum = 0;
constructionEnergy = 0;
constructionMetal = 0;
for (int i = 0; i < LASTCATEGORY; i++) {
allTheBuildingTrackers[i].clear();
}
trackerOff = true;
}
CEconomyTracker::~CEconomyTracker() {
for (list<EconomyUnitTracker*>::iterator i = deadEconomyUnitTrackers.begin(); i != deadEconomyUnitTrackers.end(); i++) {
delete *i;
}
for (list<EconomyUnitTracker*>::iterator i = newEconomyUnitTrackers.begin(); i != newEconomyUnitTrackers.end(); i++) {
delete *i;
}
for (list<EconomyUnitTracker*>::iterator i = activeEconomyUnitTrackers.begin(); i != activeEconomyUnitTrackers.end(); i++) {
delete *i;
}
for (list<EconomyUnitTracker*>::iterator i = underConstructionEconomyUnitTrackers.begin(); i != underConstructionEconomyUnitTrackers.end(); i++) {
delete *i;
}
}
void CEconomyTracker::frameUpdate(int frame) {
if (trackerOff) {
return;
}
/*
// iterate over all the BuildTasks
for (int category = 0; category < LASTCATEGORY; category++) {
for (list<BuildTask>::iterator i = ai->uh->BuildTasks[category]->begin(); i != ai->uh->BuildTasks[category]->end(); i++) {
BuildTask bt = *i;
updateUnitUnderConstruction(&bt);
}
}
*/
for (int category = 0; category < LASTCATEGORY; category++) {
for (list<BuildingTracker>::iterator i = allTheBuildingTrackers[category].begin(); i != allTheBuildingTrackers[category].end(); i++) {
BuildingTracker* bt = &(*i);
updateUnitUnderConstruction(bt);
}
}
constructionEnergySum += constructionEnergy;
constructionMetalSum += constructionMetal;
// move the new EconomyUnitTrackers
list<EconomyUnitTracker*> removeList;
for (list<EconomyUnitTracker*>::iterator i = newEconomyUnitTrackers.begin(); i != newEconomyUnitTrackers.end(); i++) {
EconomyUnitTracker* bt = *i;
assert(frame - bt->createFrame <= 16);
if (frame - bt->createFrame == 16) {
// move it to the active list
assert(bt->alive);
activeEconomyUnitTrackers.push_back(bt);
removeList.push_back(bt);
}
}
// remove them from newEconomyUnitTrackers
for (list<EconomyUnitTracker*>::iterator i = removeList.begin(); i != removeList.end(); i++) {
newEconomyUnitTrackers.remove(*i);
}
// update the units in activeEconomyUnitTrackers, add their production/usage to total
float energyProduction = 0.0f;
float metalProduction = 0.0f;
// these are exclusive of what is used by builders
float energyUsage = 0.0f;
float metalUsage = 0.0f;
if (frame % 16 == 0) {
for (list<EconomyUnitTracker*>::iterator i = activeEconomyUnitTrackers.begin(); i != activeEconomyUnitTrackers.end(); i++) {
EconomyUnitTracker* bt = *i;
assert(bt->alive);
// if the unit is a builder then we track its resource usage already
// if it's using more than its weapon fire or upkeep
UnitResourceInfo resourceInfo;
bool isAlive = ai->cb->GetUnitResourceInfo(bt->economyUnitId, &resourceInfo);
assert(isAlive);
// add the change from last update
bt->totalEnergyMake += bt->lastUpdateEnergyMake = resourceInfo.energyMake - bt->lastUpdateEnergyMake;
bt->totalMetalMake += bt->lastUpdateMetalMake = resourceInfo.metalMake - bt->lastUpdateMetalMake;
bt->totalEnergyUsage += bt->lastUpdateEnergyUsage = resourceInfo.energyUse - bt->lastUpdateEnergyUsage;
bt->totalMetalUsage += bt->lastUpdateMetalUsage = resourceInfo.metalUse - bt->lastUpdateMetalUsage;
energyProduction += bt->lastUpdateEnergyMake;
metalProduction += bt->lastUpdateMetalMake;
if (!bt->unitDef->builder) {
energyUsage += bt->lastUpdateEnergyUsage;
metalUsage += bt->lastUpdateMetalUsage;
}
}
}
float energy = ai->cb->GetEnergy();
float metal = ai->cb->GetMetal();
// float deltaEnergy = energy - oldEnergy + constructionEnergy;
// float deltaMetal = metal - oldMetal + constructionMetal;
if (frame % 16 == 0) {
makePrediction(frame + 320 + 160);
}
oldEnergy = energy;
oldMetal = metal;
constructionEnergy = 0;
constructionMetal = 0;
}
TotalEconomyState CEconomyTracker::makePrediction(int targetFrame) {
int frame = ai->cb->GetCurrentFrame();
// find current state and make copy
TotalEconomyState state;
state.frame = frame;
state.madeInFrame = frame;
state.energyMake = ai->cb->GetEnergyIncome();
state.energyStored = ai->cb->GetEnergy();
state.energyUsage = ai->cb->GetEnergyUsage();
state.energyStorageSize = ai->cb->GetEnergyStorage();
state.metalMake = ai->cb->GetMetalIncome();
state.metalStored = ai->cb->GetMetal();
state.metalUsage = ai->cb->GetMetalUsage();
state.metalStorageSize = ai->cb->GetMetalStorage();
TotalEconomyState state2 = state;
// HACK: just iterate over all the non-dead EconomyUnitTrackers and
// add the usage from the BuildingTrackers too, until the stuff they
// make hits their ETA
for (int preFrame = frame; preFrame <= targetFrame; preFrame += 16) {
// do the BuildingTrackers
float constructionEnergy = 0;
float constructionMetal = 0;
for (int category = 0; category < LASTCATEGORY; category++ ) {
for (list<BuildingTracker>::iterator i = allTheBuildingTrackers[category].begin(); i != allTheBuildingTrackers[category].end(); i++) {
BuildingTracker* bt = &*i;
// using the "semi-useless" GetCurrentFrame() stats only
if (bt->etaFrame >= preFrame) {
// Its not done yet
constructionEnergy += bt->energyUsage;
constructionMetal += bt->metalUsage;
}
}
}
float unitEnergy = 0;
float unitMetal = 0;
// do the EconomyUnitTrackers in activeEconomyUnitTrackers, it needs no changes (metalmakers == bad)
for (list<EconomyUnitTracker*>::iterator i = activeEconomyUnitTrackers.begin(); i != activeEconomyUnitTrackers.end(); i++) {
EconomyUnitTracker* eut = *i;
// we guess it's on ATM
unitEnergy += eut->estimateEnergyChangeFromDefWhileOn;
unitMetal += eut->estimateMetalChangeFromDefWhileOn;
}
// do the EconomyUnitTrackers in newEconomyUnitTrackers, it needs no changes (metalmakers == bad)
for (list<EconomyUnitTracker*>::iterator i = newEconomyUnitTrackers.begin(); i != newEconomyUnitTrackers.end(); i++) {
EconomyUnitTracker* eut = *i;
// we guess it's on ATM
unitEnergy += eut->estimateEnergyChangeFromDefWhileOn;
unitMetal += eut->estimateMetalChangeFromDefWhileOn;
}
// do the EconomyUnitTrackers in newEconomyUnitTrackers, it needs to test the ETA first (metalmakers == bad, nanostall == bad)
for (list<EconomyUnitTracker*>::iterator i = underConstructionEconomyUnitTrackers.begin(); i != underConstructionEconomyUnitTrackers.end(); i++) {
EconomyUnitTracker* eut = *i;
if (eut->createFrame +16 < preFrame) {
// we guess it's on ATM
unitEnergy += eut->estimateEnergyChangeFromDefWhileOn;
unitMetal += eut->estimateMetalChangeFromDefWhileOn;
}
}
// make the new bank balance
state.energyMake = unitEnergy;
state.energyStored += unitEnergy - constructionEnergy;
state.energyUsage = constructionEnergy; // HACK
state.metalMake = unitMetal;
state.metalStored += unitMetal - constructionMetal;
state.metalUsage = constructionMetal; // HACK
bool staling = false;
if (state.energyStored <= 0) {
staling = true;
state.energyStored = 0;
}
if (state.metalStored <= 0) {
staling = true;
state.metalStored = 0;
}
if (state.energyStored > ai->cb->GetEnergyStorage()) {
state.energyStored = ai->cb->GetEnergyStorage();
}
if (state.metalStored > ai->cb->GetMetalStorage()) {
state.metalStored = ai->cb->GetMetalStorage();
}
if (staling) {
// must turn stuff off (metalmakers), and cut back on construction (and fix the global ETA)
// int timeToStall = (preFrame - frame) / 30;
}
state.frame = preFrame;
}
{
// try #2: add all the activeEconomyUnitTrackers in one go at the start
float unitEnergy = 0;
float unitMetal = 0;
// do the EconomyUnitTrackers in activeEconomyUnitTrackers, it needs no changes (metalmakers == bad)
for (list<EconomyUnitTracker*>::iterator i = activeEconomyUnitTrackers.begin(); i != activeEconomyUnitTrackers.end(); i++) {
EconomyUnitTracker* eut = *i;
// we guess it's on ATM
unitEnergy += eut->estimateEnergyChangeFromDefWhileOn;
unitMetal += eut->estimateMetalChangeFromDefWhileOn;
}
state2.energyMake = unitEnergy;
state2.metalMake = unitMetal;
// make a copy of the EconomyUnitTracker lists
list<EconomyUnitTracker*> allFutureEconomyUnitTrackers;
for (list<EconomyUnitTracker*>::iterator i = newEconomyUnitTrackers.begin(); i != newEconomyUnitTrackers.end(); i++) {
EconomyUnitTracker* eut = *i;
allFutureEconomyUnitTrackers.push_back(eut);
}
for (list<EconomyUnitTracker*>::iterator i = underConstructionEconomyUnitTrackers.begin(); i != underConstructionEconomyUnitTrackers.end(); i++) {
EconomyUnitTracker* eut = *i;
allFutureEconomyUnitTrackers.push_back(eut);
}
// run the new prediction loop
for (int preFrame = frame; preFrame <= targetFrame; preFrame += 16) {
// do the EconomyUnitTrackers in newEconomyUnitTrackers, it needs to test the ETA first (metalmakers == bad, nanostall == bad)
unitEnergy = 0;
unitMetal = 0;
for (list<EconomyUnitTracker*>::iterator i = allFutureEconomyUnitTrackers.begin(); i != allFutureEconomyUnitTrackers.end(); i++) {
EconomyUnitTracker* eut = *i;
if (eut->createFrame +16 < preFrame && eut->createFrame + 32 >= preFrame) {
// we guess it's on ATM
unitEnergy += eut->estimateEnergyChangeFromDefWhileOn;
unitMetal += eut->estimateMetalChangeFromDefWhileOn;
// update the storage change
state2.energyStorageSize += eut->unitDef->energyStorage;
state2.metalStorageSize += eut->unitDef->metalStorage;
}
}
// add in the new production
state2.energyMake += unitEnergy;
state2.metalMake += unitMetal;
// do the BuildingTrackers
float constructionEnergy = 0;
float constructionMetal = 0;
for (int category = 0; category < LASTCATEGORY; category++) {
for (list<BuildingTracker>::iterator i = allTheBuildingTrackers[category].begin(); i != allTheBuildingTrackers[category].end(); i++) {
BuildingTracker* bt = &*i;
// HACK: using the "semi-useless" GetCurrentFrame() stats only
if (bt->etaFrame >= preFrame) {
// it's not done yet
constructionEnergy += bt->energyUsage;
constructionMetal += bt->metalUsage;
}
}
}
// make the new bank balance:
state2.energyStored += state2.energyMake - constructionEnergy;
state2.energyUsage = constructionEnergy;
state2.metalStored += state2.metalMake - constructionMetal;
state2.metalUsage = constructionMetal;
bool staling = false;
if (state2.energyStored <= 0) {
staling = true;
state2.energyStored = 0;
}
if (state2.metalStored <= 0) {
staling = true;
state2.metalStored = 0;
}
if (state2.energyStored > state2.energyStorageSize) {
state2.energyStored = state2.energyStorageSize;
}
if (state2.metalStored > state2.metalStorageSize) {
state2.metalStored = state2.metalStorageSize;
}
}
}
/*
sprintf(c,"1 %is: e: %i, %3.1f, m: %i, %3.1f",
time, (int)state.energyStored, (state.energyMake - state.energyUsage) * 2, (int) state.metalStored, (state.metalMake - state.metalUsage) * 2);
sprintf(c,"2 %is: e: %i, %3.1f, m: %i, %3.1f",
time, (int)state2.energyStored, (state2.energyMake - state2.energyUsage) * 2, (int) state2.metalStored, (state2.metalMake - state2.metalUsage) * 2);
*/
return state;
}
void CEconomyTracker::updateUnitUnderConstruction(BuildingTracker* bt) {
// find out how much resources have been used on this unit
// just using its HP wont work (it might be damaged), so must
// sum up what the builders spend
// find the builders that work on this unit, and sum up their spending
int unitUnderConstruction = bt->unitUnderConstruction;
const UnitDef* unitDef = ai->cb->GetUnitDef(unitUnderConstruction);
assert(unitDef != NULL);
int frame = ai->cb->GetCurrentFrame();
bt->economyUnitTracker->buildingTracker = bt;
// make the builder list
list<int> * builderList;
if (bt->buildTask) {
bool found = false;
for (list<BuildTask>::iterator i = ai->uh->BuildTasks[bt->category].begin(); i != ai->uh->BuildTasks[bt->category].end(); i++) {
if (i->id == unitUnderConstruction) {
builderList = &i->builders;
found = true;
break;
}
}
assert(found);
} else {
bool found = false;
for (list<Factory>::iterator i = ai->uh->Factories.begin(); i != ai->uh->Factories.end(); i++) {
if (i->id == bt->factory) {
builderList = &i->supportbuilders;
found = true;
break;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -