-
-
Notifications
You must be signed in to change notification settings - Fork 19
Raycasting
Raycasting is at the core of any anti-esp or anti-xray. It is therefore unsurprising that it is a target of heavy optimisation. Some examples of raycasting algorithms from other projects are this one from PlayerCulling and this one from RayTraceAntiXray. In the name of optimisation, these methods are both almost completely impossible to understand without deep analysis.
RaycastedAntiESP's raycast implementation appears primitive in comparison. It is less than half the length, and uses objects instead of primitive fields. At first glance this gives the impression that RaycastedAntiESP's must be much slower, but the opposite is true. In benchmarking, RaycastedAntiESP can consistently raycast about twice as fast1 as either of the other linked implementations.
How is this possible? Firstly, looks can be deceiving. Just because the source code of RaycastedAntiESP's algorithm appears to allocate about 5 objects per raycast doesn't mean this actually occurs. All objects used are consistently scalarised by the JVM2. This means we get the much easier-to-read (and maintain) syntax of object-oriented programming, with all the same speed of primitives as the other two implementations.
Both of the other implementations linked use 3D DDA voxel traversal algorithms. This is generally considered the best sort of traversal algorithm for voxel-based scenarios such as Minecraft worlds. However, RaycastedAntiESP uses a "naive" ray-stepping algorithm. This significantly reduces the number of calculations needed per step, providing most of the speed increase. While DDA algorithms are more technically correct since ray-stepping can sample blocks several times or miss blocks entirely, for a situation such as RaycastedAntiESP this does not matter. The risk with a ray-stepping algorithm is rays passing through solid blocks and treating them as air, which causes entities to be incorrectly marked as visible. However, RaycastedAntiESP already expects rays to pass through a few blocks before stopping (the max-occluding-count config option), so this is not a meaningful downside. Repeatedly sampling the same block just causes an additional memory access, which while a source of inefficiency is more than cancelled out by the reduction in calculations needed to find the next block.
1: Performance was tested by using RaycastedAntiESP as a base, just modifying the raycast algorithm. This eliminates other differences between the plugins as a factor affecting the results. RaycastedAntiESP's algorithm had a median of approximately 215ns/raycast while PlayerCulling's took approximately 380ns/raycast, and RayTraceAntiXray's took about 420ns/raycast. Note that this doesn't mean that their algorithms are "bad", they are still highly optimised for their purpose. To be fair to the other implementations, the same OcclusionChunkView caching used by RaycastedAntiESP's algorithm was hacked into the other algorithms too. These numbers should not be taken as fair representations of how the other plugins would perform in comparison to RaycastedAntiESP, only as a comparison of how their voxel traversal algorithms would perform in RaycastedAntiESP.
2: This is not guaranteed by the JVM spec, which is why many opt not to rely on it, but I believe that the improved maintainability justifies the unproven risk of a JVM failing to optimise the raycasting method.