⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 economytracker.cpp

📁 这是整套横扫千军3D版游戏的源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#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 + -