Problem with detecting if a player is on a block

Discussion in 'Plugin Development' started by Baummann, Jan 12, 2012.

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

    Baummann

    I'm currently creating a teleport system. You can create teleporters with it. Saving and loading works well. Getting the coordinates of a teleporter, too. But somehow detecting if a player is standing on a teleporter doesn't work.

    Check if player is on a teleporter:

    Code:
        public boolean isTeleporter(Location loc) {
            boolean isTeleporter = false;
            for (Teleporter teleporter : teleporters) {
                Location from = teleporter.getFrom().deconvert(loc.getWorld());
                Location from2 = new Location(from.getWorld(), from.getX(), from.getY() - 1, from.getZ());
                if (compare(loc, from2)) {
                    isTeleporter = true;
                    break;
                }
            }
            return isTeleporter;
        }
    
        public Teleporter getTeleporterAt(Location loc) {
            for (Teleporter teleporter : teleporters) {
                Location from = teleporter.getFrom().deconvert(loc.getWorld());
                Location from2 = new Location(from.getWorld(), from.getX(), from.getY() - 1, from.getZ());
                if (compare(loc, from2))
                    return teleporter;
            }
            return null;
        }
    
        public boolean compare(Location loc1, Location loc2) {
            if (loc1.getBlockX() == loc2.getBlockX()
                    && loc1.getBlockY() == loc2.getBlockY()
                    && loc1.getBlockZ() == loc2.getBlockZ()) {
                return true;
            }
            return false;
        }
    onPlayerMove (I did register it):

    Code:
        public void onPlayerMove(PlayerMoveEvent event) {
            Location to = event.getTo();
            Player player = event.getPlayer();
            if (plugin.isTeleporter(to)) {
                System.out.println(player.getName() + " is on a teleporter!");
                Teleporter teleporter = plugin.getTeleporterAt(to);
                teleporter.teleportPlayer(player);
            }
        }

    Teleporter class:
    Code:
    package com.baummann.teleportsystem;
    
    import java.io.Serializable;
    
    import org.bukkit.Location;
    import org.bukkit.entity.Player;
    
    public class Teleporter implements Serializable {
        private static final long serialVersionUID = 1L;
        private StorableLocation from;
        private StorableLocation to;
        private String name;
    
        public Teleporter(Location from, Location to, String name) {
            this.from = StorableLocation.convert(from);
            this.to = StorableLocation.convert(to);
            this.name = name;
        }
    
        public Teleporter(StorableLocation from, StorableLocation to, String name) {
            this.from = from;
            this.to = to;
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void teleportPlayer(Player player) {
            player.teleport(to.deconvert(player.getWorld()));
        }
    
        public StorableLocation getFrom() {
            return from;
        }
    
        public void setFrom(Location from) {
            this.from = StorableLocation.convert(from);
        }
    
        public StorableLocation getTo() {
            return to;
        }
    
        public void setTo(Location to) {
            this.to = StorableLocation.convert(to);
        }
    }
    Whenever I'm standing on a teleporter, nothing happens at all. No errors, nothing.
    What could be the problem here?
     
  2. Offline

    tomjw64

    I think it may be that you are checking below where the player would be standing. Just as a test, increase the leeway for error when it comes to checking if the Y coordinates are the same.

    Edit: Also, if that doesn't work, put a test message in the for loops within isTeleporter just to make sure that it actually does have values.
     
  3. Offline

    Baummann

    Oh... I get the problem. You mean that loc1 and loc2 are always different because loc1 is 1 lower on the Y axis, right? I feel dumb now ._.

    EDIT:
    I change the code of the compare method to:
    Code:
        public boolean compare(Location loc1, Location loc2) {
            if (loc1.getBlockX() == loc2.getBlockX()
                    && loc1.getBlockY() - 1 == loc2.getBlockY() - 1
                    && loc1.getBlockZ() == loc2.getBlockZ()) {
                return true;
            }
            return false;
        }
    Nothing really changed.

    I also put that in if (plugin.isTeleporter(to)):
    Code:
                System.out.println(player.getName() + " is on a teleporter!");
    I never get an output.
     
  4. Offline

    V10lator

    Why don't you just use:
    Code:java
    1. Block underPlayer = player.getLocation().getBlock().getRelative(BlockFace.DOWN);
    2. if(underPlayer.getType() == Material.X)
    3. {
    4. //Teleportblock!
    5. }

    ? :)
     
  5. Offline

    kevhog

    So in your "compare" method, loc1 is 1 block lower, and loc2 is 2 blocks lower
    @V10lator I don't think he literally means a teleporter, but a block that you can set to teleport players
     
  6. Offline

    Baummann

    I've changed
    Code:
    Location from2 = new Location(from.getWorld(), from.getX(), from.getY() - 1, from.getZ());
    to
    Code:
    Location from2 = new Location(from.getWorld(), from.getX(), from.getY(), from.getZ());
    already.

    @V10lator What @kevhog said.
     
  7. Offline

    kevhog

    @Baummann By the way, your "isTeleporter" method is confusing to mentally run through
    Code:java
    1. public boolean isTeleporter(Location loc) {
    2. for (Teleporter teleporter : teleporters) {
    3. Location from = teleporter.getFrom().deconvert(loc.getWorld());
    4. Location from2 = new Location(from.getWorld(), from.getX(), from.getY() - 1, from.getZ());
    5. if (compare(loc, from2)) {
    6. return true;
    7. }
    8. }
    9. return false;
    10. }

    It doesn't matter, but it's confusing to be running through a program in your head and seeing you return "isTeleporter" in the method "isTeleporter"
    I'm still looking for logic errors
    EDIT: I think V10lator suggested this, try printing out your variables everywhere you can to see if a var isn't what you expected
     
  8. Offline

    Digi

    So you just want to check if a player is on the *location* specified in a teleporter instance ?
    You'd have to check player location against block location - block location + 1 because a location points to a corner of block, and you need to get everything from that corner to the other corner to detect whenever the player is standing on the block.
     
  9. Offline

    kevhog

    I'm working on a plugin that works fine no matter where the player is on the block, without having to do that
     
  10. Offline

    Digi

    You don't get it.
    Get in the game, press F3 and look at your coordinates, when you're in the middle of a block your coords are X = n.5, Z = n.5 (approximate :) ) because n.0 is in the corner of that block, not in the middle.

    If you want to check whenever a player is anywhere on a block, you *must* check if he's between n and n+1 to cover n.0, n.2, n.5, n.9 and everything between.

    n = any number, I'm talking about the number after the point (decimal is it ?).

    EDIT:
    Also, I was talking to @Baummann

    But anyway, I think a better way would be to floor() (or ceil ?) the values and just compare directly.
     
  11. Offline

    Baummann

    Wouldn't getBlock[coord]() do the job? I'll try it with floor anyway.
     
  12. Offline

    Zimp

    Digi is right, the way you are comparing coordinates requires the player to be standing on a very very specific x/y/z coordinate.

    A more simpler approach would be:

    Location loc = player.getLocation();
    loc.setY(loc.getY() - 1.0); //Get the location of the block below the player

    int x = loc.getBlockX();
    int y = loc.getBlockY();
    int z = loc.getBlockZ();

    and then use those x,y,z coordinates to compare against the stored block coordinates.
     
  13. Offline

    kevhog

    Oh derp yeah that's what I use. In stead of just getting the location of the player, get the location of the block... I'll check my source and see exactly how I did it
     
  14. Offline

    Baummann

    That fixed it!
    But now it only works when two teleporters are set to the same locations.
    And I'm getting this error:
    Code:
    21:53:05 [INFO] Baummann1703 is on a teleporter!
    21:53:05 [SEVERE] Could not pass event PLAYER_MOVE to TeleportSystem
    java.lang.NullPointerException
        at com.baummann.teleportsystem.listeners.TSPlayerListener.onPlayerMove(TSPlayerListener.java:63)
        at org.bukkit.plugin.java.JavaPluginLoader$7.execute(JavaPluginLoader.java:307)
        at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:58)
        at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:339)
        at net.minecraft.server.NetServerHandler.a(NetServerHandler.java:182)
        at org.getspout.spout.SpoutNetServerHandler.a(SpoutNetServerHandler.java:679)
        at net.minecraft.server.Packet10Flying.a(SourceFile:126)
        at net.minecraft.server.NetworkManager.b(NetworkManager.java:226)
        at net.minecraft.server.NetServerHandler.a(NetServerHandler.java:93)
        at org.getspout.spout.SpoutNetServerHandler.a(SpoutNetServerHandler.java:550)
        at net.minecraft.server.NetworkListenThread.a(SourceFile:108)
        at net.minecraft.server.MinecraftServer.w(MinecraftServer.java:527)
        at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:425)
        at net.minecraft.server.ThreadServerApplication.run(SourceFile:457)
    
    Which points at

    Code:
                Teleporter teleporter = plugin.getTeleporterAt(to);
                teleporter.teleportPlayer(player); //<---- Line 63
    Code:
        public void teleportPlayer(Player player) {
            player.teleport(to.deconvert(player.getWorld()));
        }
    
    Code:
        public Teleporter getTeleporterAt(Location loc) {
            Teleporter result = null;
            for (Teleporter teleporter : teleporters) {
                Location from = teleporter.getFrom().deconvert(loc.getWorld());
                if (compare(loc, from)) {
                    result = teleporter;
                    break;
                }
            }
            return result;
        }
    
    When I only have 1 teleporter, nothing happens at all.
     
  15. Offline

    kevhog

    By the way, isn't it better to use a scheduler rather than onPlayerMove?
     
  16. Offline

    Baummann

    What makes you think that? A scheduler runs every tick and uses a lot of RAM. onPlayerMove gets called when one of the player's position variables change (posX, posY, posZ, rotPitch, rotYaw).
     
  17. Offline

    V10lator

    So what happens more? A predefined action every X ticks or a player moving one of the 6 things for 0.00001 (random number)? :p Better eat a bit more RAM and save CPU time!
     
  18. Offline

    Baummann

    onPlayerMove gets called whenever a player moves. A scheduler would loop every tick and compare the positions.
     
  19. Offline

    V10lator

    Which can be more times a tick for just one player.
    You can set the delay to whatever you want, no need to check every tick.
     
  20. Offline

    Baummann

    But wouldn't the scheduler loop every tick and execute a code when a specific tick has been reached?
     
  21. Offline

    kevhog

    It would count X ticks and then execute the code, and repeat. Do it every three ticks since it takes 180ms to sprint accross a block
     
  22. Offline

    Digi

    Yes, and whenever a player moves .0000000000001 that method gets called :)
    I dare you to print yourself a message whenever you just tap forward button, them method will get called like 10 times in that second =)

    A scheduler is best for this, not every tick, every 10 (half of second) or even 20 ticks (a second) would be fine.
     
Thread Status:
Not open for further replies.

Share This Page