[Refactoring]: Visibility calculation improvements #4506
Labels
code-maintenance
Adding/editing javadocs, unit tests, formatting.
performance
A performance or quality of life improvement
Describe the problem
There's a lot of things that are suboptimal about our visibility calculations.
On the one hand there's a lot of noise and unnecessary complexity in the code that could be improved. E.g.:
AreaTree
is split up across several types despite being quite straightforward, and its logic is mutually recursive between those types.AreaMeta
can't decide whether to be represented as an AWTArea
or a JTSLinearRing
.FogUtil
as a bunch ofstatic
methods.There's also a lot of performance being left on the table when topology stops being trivial. E.g.:
AreaTree
involves an expensive brute force approach to finding parent-child relationships between islands and oceans. This is enough to cause noticeable delay when rebuilding topology trees.Geometry
(includingLineString
andLinearRing
) when it's not necessary.Geometry
is expensive to use due to its generallity, but we don't need that generality and so can avoid the overhead.The improvement you'd like to see
AreaTree
will use a structure that clearly shows it is a basic n-ary tree with values (AreaMeta
) at each node. A single node type will suffice, and algorithms forAreaTree
will be defined onAreaTree
rather than its node type.AreaMeta
will also be simplified to represent its region solely as a ring ofCoordinate
(avoiding both AWTArea
and JTSGeometry
), and will directly use algorithms that can operate on that representation.The visibility sweep algorithm will be encapsulated in its own class. It will maintain appropriate data structures (sorted open walls especially) and use logic that reflects real-world situations. E.g., that we can have lots of runs of the algorithm in short proximity ("expose last path"), and that we tend to see very few endpoint duplications, a small number of open walls at any given point, and lots of far away walls completely hiding behind nearer walls (for complex topology). The algorithm will also avoid expensive operations (e.g., line intersection calculations) where cheap and precise alternatives exist.
Expected Benefits
The code will be easier to follow (if still quite specialized), and performance will get a boost for complex topologies.
Additional Context
Here is a campaign that I use to test various edge cases and performance. The map "Performance: 80x80 Cave" is a good example of some of the problems with the current implementation, even if it might not itself be typical:
![image](https://private-user-images.githubusercontent.com/7492219/286730916-2b3711c8-eabb-4892-888c-637c745d14ef.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzk1ODg2MTUsIm5iZiI6MTczOTU4ODMxNSwicGF0aCI6Ii83NDkyMjE5LzI4NjczMDkxNi0yYjM3MTFjOC1lYWJiLTQ4OTItODg4Yy02MzdjNzQ1ZDE0ZWYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIxNSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMTVUMDI1ODM1WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MmZmNjM0OWE3ZjZhZTU4NzgyM2ZmZmU5MzZlNWRkODk0NmZhMjk3ZGM1YzNkZjQ2YWU0OGE0YTc1N2JkMWE5YyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.c4PBFdbumc7Q_kmFx66RAc1uLrcjygZqishH0CrPsJg)
With auto-expose FOW, complex geometry, and a long path to expose along, the map consistently gives timings that look like this:
Sorry about the structure of the timers, I didn't make it clear what exactly belongs to what The gist of it is that ~15s of the 30s total runtime is spent calculating visibility polygons, leaving another ~15s spent in the other parts of the exposure code (constraining lit areas to visible areas, unioning exposed
Area
at each step, etc). I don't know what to do about the latter 15s yet, but the first 15s can be reduced significantly (about 10x) by implementing the suggested improvements.The text was updated successfully, but these errors were encountered: