Previously, the Refinery placement check would first collect all cells
with resources inside the MaxBaseRadius, then perform a full findPos check
for each cell until one of them would not return null. The problem was
that if all of the cells returned null (for example if there wasn't enough
space between base center and resource, or if all suitable space was
otherwise occupied), it would basically check all tiles with resources
only to fail finding a suitable position and fall back to the normal
findPos check.
Since nearbyResources already performs a shuffle, I simply made the check
use the first cell from the list and use the basic findPos fallback if
that cell is null.
Closes#4717.
- Cache the shroud projection even for flat maps to avoid allocating single element arrays.
- Avoid LINQ in shroud and map projection queries to avoid enumerator allocations.
- Avoid LINQ in calculation of sync values.
- Cache enumerables in ProductionQueue.
- Cache delegate in HackyAI.
The AI code runs on only one hosts, so by having the AI use SharedRandom values, the host's random gets out of sync with the other players' and crashes the game.
Moved water checks before --waitTicks.
Use Water enum instead of multiple booleans.
Check for BaseProvider rather than BaseBuilding.
Move expensive ClosEnoughToWater check to last position for naval
production override.
Early game AI usually follows the same build order (power plant first, then refinery), which also means they all start producing them at the same tick. This adds a random factor to the production delay, so not all AIs produce on the same tick.
If not enough water space can be found inside the base perimeter, stop the AI from trying to build naval production buildings permanently until it deploys another construction yard.
If enough water is available within the base perimeter, check whether any
building that provides buildable area (for adjacency) is close enough to
water, otherwise don't even start producing this naval structure.
To prevent the AI generating lag spikes by issuing too many orders in a single tick, it is now limited in how many orders can be issued per tick. Extra orders are queued. This allows the performance hit of issuing multiple orders to be spread out over several ticks.
Randomize the initial tick used for each AI so they don't cause lag but all flooding the same tick with orders, but instead (try) and use a different tick for each AI. Order processing is expensive due to the need to sync world state, so it is best to spread out the performance cost of issuing these orders over different ticks.