As proposed in the past in #13577.
Replace TraitContainer.All() that uses the custom AllEnumerator with
TraitContainer.ApplyToAllX() that takes an action as argument.
The AllEnumerator.Current function show up in profiling reports since it is
used each tick multiple times for multiple traits. The function is 'heavy'
because it creates TraitPair<T>'s temporary objects for each actor
trait combination.
In the past about 20k ITick trait pairs were present during an average
multi player game.
Using an Apply function that takes an action avoid the need to create
these temporary objects.
To be able to still use 'DoTimed' somewhat efficiently the measurement
was moved to inside the trait container method.
Results in a 25% performance improvement in accessing all traits of
a certain type.
Apply function could be used for other TraitContainer functions as well
for further improvements.
Test result for calling on a dummy trait on 20k actors a 1000 times:
1315 ms traitcontainer.AllEnumerator (current)
989 ms traitcontainer.Apply (this commit)
UpdateShroud shows up in profile reports as one of the most
active methods (2.3% CPU time, main mono thread).
This commit introduces `anyCellDirty` to indicate that at lease one
of the cells was marked as dirty.
Avoiding the need to traverse all projected cells of the map
to find any dirty cell.
This reduces the number of shroud updates by at least 50% during a
test game. I assume this is related to renders occurring more
often than logic ticks(?).
Also added a configurable deploy cursor and fixed Minelayer target cell validation checks, which should make for a much better experiencing when dragging over an area with blocking terrain, shroud, fog, etc.
The Stream.ReadByte method is implemented by allocating a 1 byte buffer and calling into Read(byte[], int, int). Override ReadByte in derived classes to avoid needing to allocate this small temp buffer.
Also, fix some bugs in the stream implementations. Remove Write capability from MergedStream that didn't make sense. Add guards into SegmentStream to ensure reads and writes belonged to the segment - otherwise a reader or writer could access regions of the base stream that were outside the intended segment.
- Use the count to size the capacity of the list.
- Use a char array as a buffer, so will can build each string directly rather than needing a ToArray call first.