Currently this plugin is capable of showing T1 tank and dog count of both Soviet and Allied forces.
You may add more statistics to this program by finding and appending offsets.
With the framework, you only need to find offsets of the last few steps. The offsets can be classified into two groups: the offsets of a new unit class and the offset of a new unit.
Unit class offsets can be extracted from mod dlls like Phobos. YRPP has provided a good reverse engineering reference as well:
// extracted from HoueClass.h
// Used for: Counting objects currently owned and on the map
// altered on each object's loss or gain
// AITriggerType condition uses this
// original PrereqOverride check uses this
// original Prerequisite check uses this
// AuxBuilding check uses this
CounterClass OwnedBuildingTypes1;
CounterClass OwnedUnitTypes1;
CounterClass OwnedInfantryTypes1;
CounterClass OwnedAircraftTypes1
// also extracted from HouseClass.h
// I don't want to talk about these
// read the code <_<
// Count owned now
int CountOwnedNow(TechnoTypeClass const* pItem) const;
int CountOwnedNow(BuildingTypeClass const* const pItem) const {
return this->OwnedBuildingTypes.GetItemCount(pItem->ArrayIndex);
}
int CountOwnedNow(AircraftTypeClass const* const pItem) const {
return this->OwnedAircraftTypes.GetItemCount(pItem->ArrayIndex);
}
int CountOwnedNow(InfantryTypeClass const* const pItem) const {
return this->OwnedInfantryTypes.GetItemCount(pItem->ArrayIndex);
}
int CountOwnedNow(UnitTypeClass const* const pItem) const {
return this->OwnedUnitTypes.GetItemCount(pItem->ArrayIndex);
}
From this header, we know that whatever built is classified into four groups: building, unit, infantry and aircraft. Also, the unit count may be collected by calling CountOwnedNow()
.
// extracted from YRPP ArrayClasses.h
int GetItemCount(int index) {
return this->EnsureItem(index) ? this->Items[index] : 0;
}
From this implementation, we know that GetItemCount()
actually returns value from its Items
array which we will emulate in our plugin. Further, by inference and practice, I have found the following information:
Currently the offset of unit and infantry class are included in the source code. If you want to count more than tanks and infantries, you need to find the offset of corresponding class.
I will take the infantry class as an example. From the source code of Phobos
, we can find calls to CountOwnedAndPresent()
. As a result, the function implementation of CountOwnedAndPresent()
must have be in the Phobos dll. With decompiler (IDA Pro
here) and a Phobos
dll with debug symbol, you can peek into the function and IDA Pro
will tell you the offset:
But wait, you encoded the offset as 0x557c
, not 0x5578
, right?
The additional offset of 4
is introduced by the offset of Items
from the Infantry class:
We do not really care about the base address of the infantry counter class. Rather, we care more about its Items
array.
As soon as we get the Items
array base address, we can get the address of the so-called itemArrayBase
by writing some code following what has been presented. The first problem is solved here.
The second problem is how can we find the offset of different units.
I used Cheat Engine(CE)
for the finding process. The process is:
A game process (single player mode is strongly recommended here for simplicity and making anti-cheat mechanism happy) is launched. You build some units, search the game memory for their count with CE
; build more units, search again; destroy some, search again... Finally you will be greeted by few (no more than 2) results. You subtract the address with the itemArrayBase
and get the offset of this unit. Note that if there are multiple address, you are recommended to try the address that produces a smaller offset. If the offset is set correctly, when you relaunch the game with a new offset added, it should function well, counting the new unit. If not, you may take the other offset and retry.