=========== Ray Tracing =========== .. javadoc-import:: com.flowpowered.math.vector.Vector3d org.spongepowered.api.block.BlockType org.spongepowered.api.entity.Entity org.spongepowered.api.entity.living.player.Player org.spongepowered.api.world.Location org.spongepowered.api.world.extent.Extent org.spongepowered.api.util.blockray.BlockRay org.spongepowered.api.util.blockray.BlockRayHit org.spongepowered.api.util.blockray.BlockRay.BlockRayBuilder Generically, ray tracing is a method of determining the path of a particle through a coordinate system. In SpongeAPI, this is implemented with the :javadoc:`BlockRay` class to discover blocks in the path of an arbitrary line in space. A common use case could be to find the block that a :javadoc:`Player` is looking at. You can specify the origin of the ray using the ``BlockRay#from`` method, passing in either a :javadoc:`Location`, an :javadoc:`Extent` and a ``Vector3d``, or an :javadoc:`Entity`. The method will return a :javadoc:`BlockRay.BlockRayBuilder`. .. tip:: If you specify the origin of the ray to be an ``Entity``, the default direction will be the direction in which the ``Entity`` is pointing. To specify the end point, you can use the :javadoc:`BlockRay.BlockRayBuilder#to(Vector3d)` method, which will set both the direction and ending location. Alternatively, you can specify a direction using :javadoc:`BlockRay.BlockRayBuilder#direction(Vector3d)` and also a block limit using :javadoc:`BlockRay.BlockRayBuilder#blockLimit(int)`. .. note:: The default block limit is 1000 blocks as a safeguard to prevent infinite iteration. To disable the block limit, use a negative value with ``BlockRayBuilder#blockLimit(int)``. Filtering ========= Filters determine what blocks are accepted by the ``BlockRay``. To add a filter, use the ``BlockRayBuilder#filter`` method, passing in one or many ``Predicate>``\ s (where ``E`` extends ``Extent``). For convenience, ``BlockRay`` contains the following methods for common filter use cases: * ``allFilter``: returns a filter accepting all blocks * ``onlyAirFilter``: returns a filter accepting only air * ``blockTypeFilter(BlockType)``: returns a filter accepting only the specified :javadoc:`BlockType` * ``maxDistanceFilter(Vector3d, double)``: returns a filter that stops at certain distance from the given ``Vector3d`` * ``continueAfterFilter(Predicate>, int)``: returns a filter that continues past the given filter by the specified number of blocks. Of course, you can also write your own ``Predicate>`` filter. Finally, use :javadoc:`BlockRay.BlockRayBuilder#build()` to finish building the ``BlockRay``. An example usage of ``BlockRayBuilder`` to get the first non-air block a ``Player`` is looking at is provided below. .. code-block:: java import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.util.blockray.BlockRay; import org.spongepowered.api.world.World; Player player; BlockRay blockRay = BlockRay.from(player) .filter(BlockRay.continueAfterFilter(BlockRay.onlyAirFilter(), 1)).build(); Using BlockRay ============== Since ``BlockRay`` implements ``Iterator``, you can use such methods as ``hasNext`` and ``next`` (but not ``remove``) to iterate through the :javadoc:`BlockRayHit`\ s generated by the ``BlockRay``. Additionally, you can use the :javadoc:`BlockRay#reset()` method to reset the iterator to the starting location. Rather than iterating through the ``BlockRayHit``\ s, you can also use the :javadoc:`BlockRay#end()` method to trace the block ray to the end of its path to get the last block accepted by the filter (or none if the block limit was reached). Using BlockRayHit ================= ``BlockRayHit`` contains information about each block intersected by the ray. It contains the location of the block, the direction of the ray, the coordinates of the *intersection* of the ray and the block, and other similar data. The following code uses the ``BlockRay`` from the previous example to print out the location of the first non-air block in front of the player. .. code-block:: java import org.spongepowered.api.util.blockray.BlockRayHit; import java.util.Optional; BlockRay blockRay; Optional> hitOpt = blockRay.end(); if (hitOpt.isPresent()) { BlockRayHit hit = hitOpt.get(); System.out.println("Found " + hit.getLocation().getBlockType() + " block at " + hit.getLocation() + " with intersection at " + hit.getPosition()); }