Disable walking into a region?

Discussion in 'Spigot Plugin Development' started by Realm, Jan 12, 2018.

  1. So, Im attempting to create a plugin wherein it disables players moving through 'detectors'.
    Detectors are just cuboids.
    My issue is that I don't know how to do this...

    This is my current code:

    Code (Text):
    public final class DetectorWalkThroughListener implements Listener {

        @EventHandler
        public void onDetectorWalkThrough(DetectorWalkThroughEvent e) {
            ItemStack[] contents = e.getPlayer().getInventory().getContents();
            List<Material> prohibited = Arrays.asList(
                    Material.DIAMOND_SWORD,
                    Material.GOLD_SWORD,
                    Material.IRON_SWORD,
                    Material.STONE_SWORD,
                    Material.WOOD_SWORD,
                    Material.BOW,
                    Material.DIAMOND_AXE,
                    Material.GOLD_AXE,
                    Material.IRON_AXE,
                    Material.STONE_AXE,
                    Material.WOOD_AXE
            );

            itemStack:
            for (ItemStack i : contents) {
                if (i == null || i.getType() == Material.AIR) continue;
                for (Material material : prohibited) {
                    if (i.getType() != material) continue;
                    e.getPlayer().setVelocity(getCenter(e.getTo()).toVector().subtract(e.getPlayer().getLocation().toVector()).normalize().multiply(-3));
                    break itemStack;
                }

            }

        }

        private Location getCenter(Location loc) {
            return new Location(loc.getWorld(),
                    getRelativeCoord(loc.getBlockX()),
                    getRelativeCoord(loc.getBlockY()),
                    getRelativeCoord(loc.getBlockZ()));
        }

        private double getRelativeCoord(int i) {
            double d = i;
            d = d < 0 ? d - .5 : d + .5;
            return d;
        }

    }
     
    This fires according to this code:

    Code (Text):
    public final class PlayerMoveListener implements Listener {

        @EventHandler
        public void onPlayerMove(PlayerMoveEvent e) {
            if ((e.getFrom().getBlockX() == e.getTo().getBlockX())
                    && (e.getFrom().getBlockZ() == e.getTo().getBlockZ())
                    && (e.getFrom().getBlockY() == e.getTo().getBlockY())) return;

            for (Detector detector : DetectorAPI.getDetectors()) {
                if (!detector.check(e.getPlayer())) continue;
                Bukkit.getPluginManager().callEvent(new DetectorWalkThroughEvent(detector, e));
            }
        }

    }
     
    However, players just get stuck and glitch inside the detector cuboid itself, bouncing back and forth off the edge of the detector, because the event is fired whenever they move entire blocks.

    I just want players to be knocked back from this area, and I cant seem to make that happen...
    Ive also tried:

    Code (Text):
    player.setVelocity(player.getLocation().getDirection().multiply(-3));
     
    However, that just knocks players back according to the direction the player is looking, meaning that the player can look backwards and get through the detector, which is undesirable.
    I've also read this post, but still am stuck ;.;
     
  2. I don't really know why you have
    Code (Java):
    if (i == null || i.getType() == Material.AIR) continue;
    If the item stack is null, it's null and just won't be there. and I was not aware that you could have an air block as a dropped item (pretty sure you can't)

    but anyways what you want to do is pretty simple this is sudo code but I am sure you will figure it out

    Code (Java):
    Material[] prohibited  ={
                Material.DIAMOND_SWORD,
                Material.GOLD_SWORD,
                Material.IRON_SWORD,
                Material.STONE_SWORD,
                Material.WOOD_SWORD,
                Material.BOW,
                Material.DIAMOND_AXE,
                Material.GOLD_AXE,
                Material.IRON_AXE,
                Material.STONE_AXE,
                Material.WOOD_AXE
        };
        @EventHandler
        public void onPlayerMove(PlayerMoveEvent e) {
         
            // you might need a loop around this to run through all of
            // you detector locations, not sure how you do this.
            if (e.getTo() is a location of one of your detectors) {
                // loop through all the items the players has including
                // their quick bar, not just the contents
                for (ItemStack itemStack : e.getPlayer().getInventory()) {
                    // loop to see if it is one of the prohibted ones
                    for (Material prohibitedMaterial : prohibited) {
                        // If it is cancel the PlayerMoveEvent. This will
                        // stop the player from moving into that location.
                        if (itemStack.getData().equals(prohibitedMaterial)) {
                            e.setCancelled(true);
                        }
                    }
                }
           
    EDIT:
    I dunno how you determine what a detector is but you might want to set something that makes this stop checking if they have already entered, and one that will make it check again once they have left. Like a boolean beenChecked = true; once they pass your test and get in, and beenChecked = !true; when they leave. You will have to associate the value with a specific player, like in a HashMap<Player, Boolean>
     
    #2 ForbiddenSoul, Jan 12, 2018
    Last edited: Jan 12, 2018
    • Optimistic Optimistic x 1
  3. Empty items in your inventory, considering its an array with a fixed size of 36, looping through its contents will return null if no item is present in that spot. Also, considering Material.AIR is an enum I can use, I will use it, because other developers for example may set an item to type AIR and why loop on that if it's not necessary? Also, I wish to launch the player backwards, not just cancel the event. Also, looping through their contents also loops through their hot bar. Just FYI.
     
    #3 Realm, Jan 12, 2018
    Last edited: Jan 12, 2018
  4. I assume you have a getter for the PlayerMoveEvent in your DetectorWalkThroughEvent like DetectorWalkThroughEvent#getPlayerMoveEvent().

    I am not sure if it works but try this before you push back the player: e.getPlayerMoveEvent().setTo(e.getPlayerMoveEvent().getFrom());
     
  5. Alright makes sense. The code I gave you just stops them from walking in and bounces them a little bit. you can always use something like this.

    get the players moving to direction / the location of your detector. Then subtract the direction they came from/ where they currently are. that will give you a vector pointing away from your safe area. Then you normalize that vector so it basically snaps to north, east, south, west. then you can set the players velocity equal to that vector times like lets say 10. They might not move because of the friction on the ground though, so you might need to teleport them 0.25 units up if they don't.

    EDIT I change it from direction to just location should work better I think. Not tested either but should work

    Something like:
    Code (Java):
    e.getPlayer().setVelocity(e.getTo().toVector().subtract(e.getFrom().toVector()).normalize().multiply(10));
    that will account for them walking in backwards and stuff too.
     
    #5 ForbiddenSoul, Jan 12, 2018
    Last edited: Jan 12, 2018
  6. Thanks for trying, but that code doesnt work either. That just launches them through the detector, not away from it.
    If I change multiply value to negative, say -3, it just bounces me inbetween the detector and sometimes glitches me through it. Ehh
     
  7. Use Player#setVelocity(Player#getVelocity().multiply(-2)); that will spring them back in the direction they came from, which is what you want, yes?
     
  8. just reverse what you are subtracting then
    instead of
    Code (Java):
    e.getPlayer().setVelocity(e.getTo().toVector().subtract(e.getFrom().toVector()).normalize().multiply(10));
    do the reverse
    Code (Java):
    e.getPlayer().setVelocity(e.getFrom().toVector().subtract(e.getTo().toVector()).normalize().multiply(10));
    EDIT
    or if it still backwards multiply by -10

    basic logic cmon dude...

    Jeez I will break it down into parts so you understand...
    Code (Java):
    e.getPlayer().setVelocity()
    that velocity needs to be set to something

    here we subtract two vectors from each other, (draw a line from one point in the world to another)
    Code (Java):
    e.getTo().toVector().subtract()
    We are taking the point they are moving to, then subtracting where they came from. This should give us a line starting at your detector moving towards where they came from.
    Code (Java):
    e.getTo().toVector().subtract(e.getFrom().toVector())
    then we normalize that vector so it is one unit long, (goes from one block to the next)
    Code (Java):
    e.getTo().toVector().subtract(e.getFrom().toVector()).normalize()
    then we multiply that by 10, so that it throws them 10 blocks back or multiply by how ever many blocks you want.
    Code (Java):
    e.getTo().toVector().subtract(e.getFrom().toVector()).normalize().multiply(10)
    then finally we put it all together and set the vector we just created as the players velocity.
    Code (Java):
    e.getPlayer().setVelocity(e.getTo().toVector().subtract(e.getFrom().toVector()).normalize().multiply(10));
    That will only work if they are walking forwards, if they are walking backwards it will throw them into the safe area.
     
    #8 ForbiddenSoul, Jan 13, 2018
    Last edited: Jan 13, 2018
  9. I feel like these solutions would work normally, but the problem is that I get glitched and I bounce off the edge of blocks and sometimes go the wrong way. Think I need to somehow implement a cooldown or something


    Sent from my iPhone using Tapatalk
     
  10. You shouldn't need a cool down, as it takes them out of range from triggering it again as soon as it happens.
    post the code your using and let me see what you got now.

    Give me a bit and I'll write up something that does this tested and everything.

    Yeah this code works no problem and doesn't glitch, maybe it is your detector that its gltiching (10 was way too intense set it to 2)

    This bounces a player out of water if they walk into it.
    Code (Text):
    @EventHandler
        public static void onPlayerMove(PlayerMoveEvent event) {
            if (event.getTo().getBlock().getType().equals(Material.STATIONARY_WATER)) {
                event.getPlayer().setVelocity(event.getFrom().toVector().subtract(event.getTo().toVector()).normalize().multiply(2));
            }
        }
    Ugh i just saw the glitch your talking about... let me see if I can do something about that...

    OK this check will fix it, sorry about that.
    Code (Java):
    if (event.getTo().getBlock().getType().equals(Material.STATIONARY_WATER) && !event.getFrom().getBlock().getType().equals(Material.STATIONARY_WATER)) {
                System.out.println("Player in water");
                event.getPlayer().setVelocity(event.getFrom().toVector().subtract(event.getTo().toVector()).normalize().multiply(2));
            }
    just make sure they are also not in your detector already (replace water with your detector)
    !event.getFrom().getBlock().getType().equals(Material.STATIONARY_WATER)
     
    #10 ForbiddenSoul, Jan 13, 2018
    Last edited: Jan 13, 2018
  11. It doesnt take them out of range, because setting their velocity would still trigger the event again. The code you gave doesnt work 100% of the time, it works 95% of the time though, but keep trying to get through and youll sometimes be thrown the wrong way.
    Ill send you the .zip of my plugin currently in PM.
     
  12. Did you try that?
     

Share This Page