1.8.8 Check if a player is looking at the head of another player

Discussion in 'Spigot Plugin Development' started by ZBLL, Jun 26, 2021.

Thread Status:
Not open for further replies.
  1. I want to check if a player is looking at the head of another player (from a reasonable range). I managed to make a code that checks if a player is looking at another player, not their head (I totally didn't take it from Stackoverflow), but it's not working as well.
    Code (Java):

    protected Entity getNearestEntity(Player player, int range) {
        ArrayList<Entity> entities = (ArrayList<Entity>) player.getNearbyEntities(range, range, range);
        ArrayList<Block> sightBlocks = (ArrayList<Block>) player.getLineOfSight((Set<Material>)null, range);
        ArrayList<Location> sight = new ArrayList<>();
        for (int i = 0; i < sightBlocks.size(); i++) {
            sight.add(sightBlocks.get(i).getLocation());
        }
        for (int i = 0; i < sight.size(); i++) {
            for (int k = 0; k < entities.size(); k++) {
                if (Math.abs(entities.get(k).getLocation().getX() - sight.get(i).getX()) < 1.3) {
                    if (Math.abs(entities.get(k).getLocation().getY() - sight.get(i).getZ()) < 1.5) {
                        return entities.get(k);
                    }
                }
            }
        } /* I have (almost) no idea what this code does. I hate using the code that I don't understand but that's the only way here */
        return null;
    }

    @EventHandler
    public void onMove(PlayerMoveEvent e){
        if (e.getPlayer() != null) {
            Entity ent = getNearestEntity(e.getPlayer(),7);
            if (!(ent instanceof Player)) return;

            /* some stuff */

            ((Player) ent).addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 200, 200, true, false));
        }
    }
     
    What I am trying to implement is a Medusa Gorgona. But right now there are 2 major flaws: it's checking when Medusa is looking at the player's head, not vice versa (I think I just need to add another getNearestEntity, but for ent). The second flaw is, both players need to be moving and that's sometimes not a thing. Lastly, this code doesn't even work. I didn't debug it yet, I think I am going to do it like tomorrow since I am coding another thing right now. But maybe there's something you can just spot at the first glance? Thanks in advance.
     
  2. Code (Text):
                    if (Math.abs(entities.get(k).getLocation().getY() - sight.get(i).getZ()) < 1.5) {
                        return entities.get(k);
                    }
    Maybe 'y' - 'z' is the problem
     
  3. Maybe first actually try your code and then ask here lmao. Try to debug it. If it works, why won't you instead of checking for player's location check for player's location + 1. (head)
     
    • Funny Funny x 1
  4. Use the ray-box intersection algorithm instead of using Entity#getLineOfSight(Entity). Define an AABB at the target player's head. Then, by defining a ray from the observer player, you can test if the ray intersects the box.

    If it does intersect, then you can use Bukkit's block iterator to loop through blocks along the ray and test if they are occluding the line-of-sight. (There's a method to get whether the block is opaque, but I forgot.) You'll need to do more ray-box intersection tests with the blocks' bounding boxes.
    ------
    Also, you'll need to check every tick, unfortunately. This isn't going to work if you're only triggering the code on PlayerMoveEvent of the observer player. You can probably optimize this by periodically checking which players are in range and putting them in some sort of map or other data structure.

    Just my two cents on this topic.
     
    • Useful Useful x 2
  5. It doesn't work and I clearly stated it.
    =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

    bro...
     
  6. You should have done it before posting this thread..
     
    • Winner Winner x 1
  7. Oh, thanks! So once again, I set the AABB to the target's head and test if the ray intersects the box.... How do I set the AABB to the target's head? There are only 2 constructors for AABB and they don't seem to help.
    Code (Java):

    /**
    * Creates a new instance from a minimum point and a maximum point.
    */

    public AABB(Vec3D min, Vec3D max) {
    this.min = min;
    this.max = max;
    }
    /**
    * Create a new AABB from a given block.
    * @param block - the block.
    */

    public AABB(Location block) {
    this(Vec3D.fromLocation(block), Vec3D.fromLocation(block).add(Vec3D.UNIT_MAX));
    }
     
    Then, I have to check if the ray intersects the box.. I think it's public Vec3D intersectsRay(Ray3D ray, float minDist, float maxDist) {} and I possibly can figure that out. Alright.
     
  8. The parameters min and max define the minimum and maximum bounds of the box. The player's head is about half the size of a block, so a good min could be <-0.25, -0.25, -0.25> and a good max could be <0.25, 0.25, 0.25>. Then you could add the player's location to those vectors to "move" the box to their location, and then add roughly 1.5 to the Y coordinates to shift it a little upwards towards the head of the player.
     
    • Winner Winner x 1
  9. So I've initialized the AABB:
    AABB aabb = new AABB(new AABB.Vec3D(-0.25, -0.25, -0.25), new AABB.Vec3D(0.25, 0.25, 0.25));
    And how do I add the location? There's no add() method for AABB. There is for Vec3D, but you can't use it for AABB nor cast them. There's, actually, no way to get the x/y/z by the AABB itself. There are methods for Vec3D but not for AABB. What am I doing wrong?
     
  10. I suppose you could implement an add() or translate() in AABB

    Code (Text):
    public void translate(Vec3D vec) {
        this.min = this.min.add(vec);
        this.max = this.max.add(vec);
    }
    Once you have the AABB initialized, just do AABB#translate(Vec3D.fromLocation(player.getLocation()).add(new Vec3D(0, 1.5, 0)));
     
    • Winner Winner x 1
  11. Now my code looks like:
    Code (Java):

    AABB aabb = new AABB(new AABB.Vec3D(-0.25, -0.25, -0.25), new AABB.Vec3D(0.25, 0.25, 0.25));
    aabb.translate(AABB.Vec3D.fromLocation(e.getPlayer().getLocation()).add(new AABB.Vec3D(0, 1.5, 0)));
     
    My next goal is to
    I don't see where to go from this:
    Code (Java):

    new BukkitRunnable() {
        @Override
        public void run() {
            for (Player p : Bukkit.getOnlinePlayers()) {
                AABB aabb = new AABB(new AABB.Vec3D(-0.25, -0.25, -0.25), new AABB.Vec3D(0.25, 0.25, 0.25));
                aabb.translate(AABB.Vec3D.fromLocation(p.getLocation()).add(new AABB.Vec3D(0, 1.5, 0)));

                /* */

                AABB.Ray3D ray = new AABB.Ray3D(p.getLocation());
                ray.getPointAtDistance(8); /* i am assuming it will check 8 blocks to the player, but now what? */
                aabb.intersectsRay(ray, 0, 8); /* this method also looks interesting */


            }
        }
    }.runTaskTimerAsynchronously(instance, 0L, 1L);
     
     
  12. Now, wait. To put context into this, I thought the AABB was supposed to represent Medusa's head. I'm not sure why you're defining an AABB for every player in the server.

    ray.getPointAtDistance(8) is useless.
    aabb.intersectsRay(ray, 0, 8) is what you want to do, yes.
     
    • Winner Winner x 1
  13. I'm doing checks to see if the player is wearing a medusa helmet, that's why I check for every player. If they don't wear one I just continue to the loop.
    Alright. So if it intersects (returns true), that means that Medusa is looking at somebody, right? But is that necessarily their head? Plus I need to know if the other player is also looking at medusa, which means I need to:
    1) Get the player that the ray is intersecting
    2) Check if that player's ray is also intersecting Medusa
    Weird stuff
     
  14. Yeah, that's right. And the AABB is supposed to serve as a rough bounds for the player's head.

    If you need to know whether the other player is looking at Medusa, then you'll need to run the check the other way. If you need some condition where both Medusa AND the player have to be looking at each other, then you could optimize this by first checking which player Medusa is looking at, and then you can check whether that player is looking at Medusa.

    Also, if this is supposed to be a fast-action minigame, you'll probably want to look into implementing some sort of lag compensation, as you'll have difficulty triggering the code if either players are moving across each others' screens with considerable latency. But this is a topic for another thread.
     
    • Winner Winner x 1
  15. Islandscout, thanks a lot for helping me. I think I am going to drop this idea for a while. I don't think I have enough experience to write and understand this code and its idea. Maybe some time later I will get back and code it. Thanks once again! Closing the thread.
     
Thread Status:
Not open for further replies.