FAForever / fa

Lua code for FAF
226 stars 232 forks source link

Use the internal unit statistics #6129

Open Garanas opened 5 months ago

Garanas commented 5 months ago

Description of the proposed changes

Remove the tracking of unit statistics. They are unnecessary as the engine tracks the same information.

Testing done on the proposed changes

Launch a game using 2badd4141ef4ee7a26dd6a8a8356311b25ffaffe and compare the results when you exit. You should see something like this in your logs:

INFO: 1 uel0001 0   ->  nil -- killed
INFO: 1 uel0001 1   ->  nil -- created
INFO: 1 uel0001 1   ->  1   -- still alive
INFO: 1 uea0303 0   ->  nil
INFO: 1 uea0303 8   ->  8
INFO: 1 uea0303 3   ->  3
INFO: 1 uel0401 0   ->  nil
INFO: 1 uel0401 1   ->  1
INFO: 1 uel0401 0   ->  nil
INFO: 2 ual0001 0   ->  nil
INFO: 2 ual0001 1   ->  nil
INFO: 2 ual0001 1   ->  1
INFO: 2 uel0001 1   ->  1
INFO: 2 uel0001 0   ->  nil
INFO: 2 uel0001 0   ->  nil
INFO: 2 uea0303 1   ->  1
INFO: 2 uea0303 0   ->  nil
INFO: 2 uea0303 0   ->  nil
INFO: 3 ual0001 1   ->  1
INFO: 3 ual0001 0   ->  nil
INFO: 3 ual0001 0   ->  nil
INFO: 3 xsl0001 1   ->  1
INFO: 3 xsl0001 0   ->  nil
INFO: 3 xsl0001 0   ->  nil
INFO: 3 ura0303 0   ->  nil
INFO: 3 ura0303 7   ->  7
INFO: 3 ura0303 2   ->  2
INFO: 3 xsa0303 7   ->  7
INFO: 3 xsa0303 0   ->  nil
INFO: 3 xsa0303 0   ->  nil
INFO: 3 url0402 0   ->  nil
INFO: 3 url0402 1   ->  1
INFO: 3 url0402 0   ->  nil
INFO: 3 xrl0403 0   ->  nil
INFO: 3 xrl0403 1   ->  1
INFO: 3 xrl0403 0   ->  nil
INFO: 3 xsl0401 2   ->  2
INFO: 3 xsl0401 0   ->  nil
INFO: 3 xsl0401 0   ->  nil
INFO: 4 xsl0001 0   ->  nil
INFO: 4 xsl0001 1   ->  nil
INFO: 4 xsl0001 1   ->  1
INFO: 4 ura0303 2   ->  2
INFO: 4 ura0303 0   ->  nil
INFO: 4 ura0303 0   ->  nil
INFO: 4 uea0303 2   ->  2
INFO: 4 uea0303 0   ->  nil
INFO: 4 uea0303 0   ->  nil
INFO: 4 xsa0303 0   ->  2
INFO: 4 xsa0303 6   ->  6
INFO: 4 xsa0303 6   ->  9
INFO: 4 xsl0401 0   ->  nil
INFO: 4 xsl0401 0   ->  nil
INFO: 4 xsl0401 0   ->  2

Additional context

This was introduced 8 years ago in https://github.com/FAForever/fa/commit/06690e0bf6a6e0bc8ec5d3c48ae8b96a2fa09612. The use of JSON instead of XML is fine, but it appears the introduction of this logic to track the status quo of units was not necessary.

Checklist

Garanas commented 5 months ago

@relent0r / @maudlin27 These brain functions may also be interesting to you as an AI developer. They make it trivial for you to retrieve various interesting properties. And the properties in question appear to be cached, so it's not re-computed as you go.

For example, these statistics are available:

        LOG("Units_BeingBuilt: ", repr(self.Brain:GetBlueprintStat('Units_BeingBuilt', categories.TECH3)))
        LOG("Units_History: ", repr(self.Brain:GetBlueprintStat('Units_History', categories.ALLUNITS)))
        LOG("Enemies_Killed: ", repr(self.Brain:GetBlueprintStat('Enemies_Killed', categories.ALLUNITS)))
        LOG("Enemies_Lost: ", repr(self.Brain:GetBlueprintStat('Enemies_Lost', categories.ALLUNITS)))
        LOG("Units_TotalDamageDealt: ", repr(self.Brain:GetBlueprintStat('Units_TotalDamageDealt', categories.ALLUNITS)))
        LOG("Units_TotalDamageReceive: ", repr(self.Brain:GetBlueprintStat('Units_TotalDamageReceive', categories.ALLUNITS)))

Example output:

INFO: Units_BeingBuilt:     1
INFO: Units_History:    186
INFO: Enemies_Killed:   15
INFO: Enemies_Lost:     0
INFO: Units_TotalDamageDealt:   47671
INFO: Units_TotalDamageReceive:     77500
Garanas commented 4 months ago

@relent0r I noticed that your AI makes use of the unit data that is stored in the brain. Are you aware of the engine alternatives that allow you to gather data based on categories, for example?

Garanas commented 4 months ago

@lL1l1 what are your thoughts on replacing the Lua-based statistics tracking with the engine-based statistics tracking? It feels more cohesive and reduces the Lua overhead, even if it is just a little bit

relent0r commented 4 months ago

@relent0r I noticed that your AI makes use of the unit data that is stored in the brain. Are you aware of the engine alternatives that allow you to gather data based on categories, for example?

Are we talking about the IntelManager unit stats? Just looking at the documentation (that someone was helpful enough to write). I hadn't considered replacing the onkilled callbacks. Looking at the GetArmyStat and GetBlueprintStat together. Do you know if there is a units built mass value based on category? it almost seems like there should be given there is an armystat for it called 'Units_MassValue_Built'.

Garanas commented 4 months ago

I'll have to experiment more with these two functions to fully understand them, I'll update the documentation and get back to you!

lL1l1 commented 4 months ago

I think it's fine to replace the kills/built/lost lua tracking with engine tracking. At worst, apply an __index metamethod to AIBrain.UnitStats["kills"|"built"|"lost"], so we just return the value given by the engine.

That piece of code in sim/score.lua checking unit stats through Lua is something I wrote recently (4 months ago) and is wrong because I didn't think of checking categories.blueprintId at the time. I even had to re-add the "kills" lua tracking in that PR, which makes me doubt that people used those stats if it never got brought up.

lL1l1 commented 4 months ago

The economy stats don't seem to function with getBlueprintStat. It returns 0 for everything.

Console script to print all economy stats as used by getBlueprintStat checking all units ```lua SimLua local stats = { 'Economy_TotalProduced_Energy', 'Economy_TotalConsumed_Energy', 'Economy_Income_Energy', 'Economy_Output_Energy', 'Economy_Stored_Energy', 'Economy_Reclaimed_Energy', 'Economy_MaxStorage_Energy', 'Economy_PeakStorage_Energy', 'Economy_TotalProduced_Mass', 'Economy_TotalConsumed_Mass', 'Economy_Income_Mass', 'Economy_Output_Mass', 'Economy_Stored_Mass', 'Economy_Reclaimed_Mass', 'Economy_MaxStorage_Mass', 'Economy_PeakStorage_Mass', } for i,stat in stats do LOG(stat, ArmyBrains[GetFocusArmy()]:GetBlueprintStat(stat, categories.ALLUNITS)) end ```
Garanas commented 4 months ago

At worst, apply an __index metamethod to AIBrain.UnitStats["kills"|"built"|"lost"], so we just return the value given by the engine.

This is a good suggestion, as a fallback.

relent0r commented 4 months ago

@Garanas fyi I'm starting to use these now with my AI. At the moment its just a simple use case of wanting a stat of how many units of a particular category has been built so the AI can build something once and then measure its efficiency before knowing if it should build some more.

I was hoping that the GetBlueprintStat parameters match up with the GetArmyStat parameters, but things like Enemies_MassValue_Destroyed didn't return any non zero values sadly.

Wondering if 4zot has any visibility of whats available in this function.