[Advanced] Obtaining entities a player is looking at, and nearby entities

Discussion in 'Resources' started by wacossusca34, Jun 25, 2014.

Thread Status:
Not open for further replies.
  1. Offline

    wacossusca34

    I'm going to be posting a lot of code form my closed source projects that I've used over and over again that could improve on things like anti-cheat plugins and entity searches.

    Determining whether an entity is looking at an entity's bounding box:

    I have noticed this 'simple' issue has gone unsolved for a long time. Unlike blocks though, entities don't have an easy method to determine whether something is looking at them or not if we are taking bounding boxes into consideration.

    This is pretty complicated. If you want a better explanation, reply to this thread. Here is the code:

    https://gist.github.com/wacossusca34/e59936d475266eae402a

    It's pretty fast, and can be used for anti-cheat plugins if you want to see if a player damaged another entity without looking at it. It can also be used with a list of entities in an area to get the entities a player is looking at - which means you can implement 'hitscan' detection on entities.

    It works by taking the corners of the entity's bounding box and converting them into theta and phi on the spherical coordinate system, where the 'eye' variable is the origin. Angles are then sorted and compared to produce a Range object (which is really just a replacement for Pair<K, V>) for determining whether a player's yaw and pitch falls under that range.

    This method also does not take blocks into consideration, if you didn't figure that out from the code. You could combine it with blocks pretty easily, though.

    EDIT: I've recently discovered that the bounding boxes for horses at -1700000 age used for holograms are invalid. If you're going to use this code in conjunction with holograms when iterating through entities, make sure to omit hologram entities.

    Determining whether a point can see another point:

    This method takes blocks into consideration! So if these two points have blocks between them, it will not work. It's used in monster AI to see if a mob can see a target's eye:

    Code:java
    1. return ((CraftWorld) loc1.getWorld()).getHandle().a(Vec3D.a(loc1.getX(), loc1.getY(), loc1.getZ()), Vec3D.a(loc2.getX(), loc2.getY(), loc2.getZ())) == null;


    You can't do fancy things like hit detection with this, though. It's only really good for determining if you can see an entity or not for finding targets or something.

    I found this code from another forums post a long time ago, and I've used it a lot since, so it's worth re-posting.

    Getting entities in an area:

    Unless you actually need to do something to every entity in the entire world, there are better ways for getting entities in an area than World.getLivingEntities(). Parsing though the entire list of living entities for a world just to effect entities in an area is expensive and redundant.

    Use this instead: https://gist.github.com/wacossusca34/e1fac61e20b76276d848

    This grabs entities from required chunks inside of the radius and then compares distances between the origin and the entities in select chunks.

    I will update this guide with code for determining all the entities a player (or any entity) is looking at once I optimize it a bit more .

    Getting all entities a player is looking at:

    Using the code from the first Gist I posted, you can use this to obtain living entities returned from this:

    Code:java
    1.  
    2. public static List<LivingEntity> getEntitiesInLine(Location origin, double length, LivingEntity... ignore) {
    3. ArrayList<Chunk> chunks = new ArrayList<>();
    4.  
    5. BlockIterator iterator = new BlockIterator(origin, 0, (int) Math.ceil(length));
    6. while (iterator.hasNext()) {
    7. Chunk chunk = iterator.next().getChunk();
    8. if (!chunks.contains(chunk))
    9. chunks.add(chunk);
    10. }
    11.  
    12. ArrayList<LivingEntity> entities = new ArrayList<>();
    13.  
    14. for (Chunk chunk : chunks) {
    15. for (Entity e : chunk.getEntities()) {
    16. if (e instanceof LivingEntity && (ignore.length == 0 || !Arrays.asList(ignore).contains(e)))
    17. entities.add((LivingEntity) e);
    18. }
    19. }
    20.  
    21. return entities;
    22. }


    Now you have a list of entities to parse through and use the isLookingAt(Entity entity, Location eye) method from my previous code. With this, you get all the entities a player is looking at - make a getEntitiesLookingAt(Location eye, double distance, LivingEntity... ignore) method from this

    TIP: If you only need one type of entity (ie. Player entities), then only use Player entities to improve performance.

    However, you probably don't want them looking through walls, so do something like this:

    Code:java
    1.  
    2. ArrayList<LivingEntity> list = getEntitiesLookingAt(eyeLocation, 75, player);
    3.  
    4. // Iterate through blocks
    5. BlockIterator iterator = new BlockIterator(player, 75);
    6. Block block = null;
    7. while (iterator.hasNext()) {
    8. block = iterator.next();
    9.  
    10. // find solid block
    11. if (block.getType() != Material.AIR && !canWalkThrough(block.getType())) {
    12.  
    13. // Get hit block
    14. Location hit = block.getLocation().add(0.5, 0.5, 0.5);
    15. double distanceFromBlock = hit.distanceSquared(from);
    16. // remove entities behind block
    17. for (LivingEntity entity : list.toArray(new LivingEntity[list.size()])) {
    18. if (from.distanceSquared(entity.getLocation()) > distanceFromBlock)
    19. list.remove(entity);
    20. }
    21.  
    22. break;
    23. }
    24. }


    Where getEntitiesLookingAt is a method that retrieves all visible entities (previous code), and canWalkThrough is a method that returns true when given a block that is non-solid in the first argument.

    TIP: Don't have a distance beyond 75. Entities will not render beyond that range, unless using a modified client.

    There. You have a reliable way of getting all the entities a player is looking at, without using slow code or unreliable searches.
     
Thread Status:
Not open for further replies.

Share This Page