Player Location checking with HashMap Help

Discussion in 'Plugin Development' started by tommyhoogstra, Mar 21, 2014.

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

    tommyhoogstra

    So i'm trying to make it whenever a player lands on a pressure plate, it checks if they have been to that location and if they have - output

    The player location is added to the hashmap everytime they land on a pressure plate with a specific block under it - I can confirm this part works

    Here is my source:
    Code:java
    1. if ((e.getAction().equals(Action.PHYSICAL)) &&
    2. (e.getClickedBlock().getType() == Material.STONE_PLATE))
    3. {
    4. if(p.getLocation() == locations.get(p.getName())){
    5. p.sendMessage("This is a test");
    6. }
    7.  
    8. final Location a = e.getClickedBlock().getLocation().add(0.0D, -1.0D, 0.0D);
    9.  
    10. if (a.getBlock().getRelative(BlockFace.DOWN).getType() == Material.REDSTONE_BLOCK)
    11. {
    12. locations.put(p.getName(), p.getLocation());
    13. }
    14. }
    15.  


    Any ideas?

    Note: This is under a player interact event.
     
  2. Offline

    Scizzr

    1. You should use location.equals(otherLocation) when comparing locations.
    2. Easy checking if a player has been to a specific block, as opposed to an exact location
    Code:
    public class VisitListener implements Listener {
        private static ConcurrentHashMap<String, List<Block>> visits = new ConcurrentHashMap<String, List<Block>>();
     
        public VisitListener() {
            Bukkit.getPluginManager().registerEvents(this, MyPlugin.getInstance());
        }
     
        @EventHandler
        public void onPlayerMove(PlayerMoveEvent event) {
            Player player = event.getPlayer();
            String playerName = player.getName();
            Block block = player.getLocation().getBlock();
         
            visits.putIfAbsent(playerName, new ArrayList<Block>());
            if (!visits.get(playerName).contains(block)) {
                visits.get(playerName).add(block);
            }
        }
     
        public static boolean hasVisited(Player player, Location location) {
            String playerName = player.getName();
            Block theBlock = location.getBlock();
            return (visits.containsKey(playerName) && visits.get(playerName).contains(theBlock));
        }
    }
    

    Disclaimer: Completely untested. May not work. Modify it to fit your needs.

    Edit: You'll need to remember that a player's current block is the block their feet are at. This means that if you're wanting to see if they've stood on a block, you'll need to add 1 to the Y coordinate of the block you're checking against.
    Edit: Thread-safe by using ConcurrentHashMap.
    Edit: Ninja-edit changing a if-then to simply putIfAbsent() in onPlayerMove()
    Edit: Edited edits. (Meta-edit?)
     
  3. Offline

    tommyhoogstra

    Scizzr

    I tried taking your code into action but it didn't seem to work

    First I checked if the hashmap contained the block, and if it did - output a message

    Then under each
    Code:java
    1. if (a.getBlock().getRelative(BlockFace.DOWN).getType() == Material.REDSTONE_BLOCK)

    I did the visits.get(playerName).get(block);

    Don't see what is wrong, but I think block may be a problem in the future as well.
    It will register the block at their feet, so if i were to land on this pressure plate, then go and step on any other pressure plate, it would give me the output.

    The desired output of the code is to stop players going back to previous locations to get free points (every block jump is 1 point (parkour)) Even if i did getBlock() -1 every time they landed on a pressureplate + redstone block it would give the message output. I know what I just said might be confusing but its real hard to explain!

    bump - late night answers?

    Edit: Is it possible to store Multiplayer player locations in a single hashmap?

    Because I tried this:
    Code:java
    1. @EventHandler
    2. public void testClose(InventoryCloseEvent e){
    3. Player p = (Player) e.getPlayer();
    4. if(p.getLocation().equals(locations.get(p.getName()))){
    5. p.sendMessage("You've been here!");
    6.  
    7. }
    8. locations.put(p.getName(), p.getLocation());
    9. }
    10.  


    It works fine, but if I open and close my inventory on a different block, go back to the block ive BEEN on and do it, the hashmap seems to overwrite it.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 7, 2016
  4. Offline

    MRPS

    tommyhoogstra
    I'm not going to write your code for you, but this should work:
    1. Store cached data in a HashMap<String,List<Block>> which stores the player's name and an array of blocks which they have stood on (get the block they are standing on with p.getLocation().getBlock().getRelative(BlockFace.DOWN)
    2. When the player moves, check if the block is contained within the List<Block> - if it is not, add it to the list; if it is, then do whatever to the player
    3. Make sure you create an empty list in that hashmap PRE LOGIN (not join) or you will encounter NPEs.
     
  5. Offline

    tommyhoogstra

    MRPS
    need some clarification but to check against the List<Block> would I use:
    if(p.getLocation().getBlock().equals(locations.get(p.getName()))){

    Also it seems to want me to cast List<Block> to locations.put(p.getName(), (List<Block>) p.getLocation().getBlock().getRelative(BlockFace.DOWN));
     
  6. Offline

    MRPS


    Sorry, I had a loss of clarity when I wrote that suggestion. Here, try this alternatively:
    1. Store visited blocks in a HashMap<String,Block[Long.MAX_VALUE]>
    2. When a player steps on a block check if they have been to that block before (see below)
    3. If they haven't, add it to the block array; if they have, react.
    (Accuracy for above method not guaranteed)

    Adding a visited block
    Code:
    public void addVisitedBlock(Player p, Block b){
      int i;
      Block[] blockArray = new Block[visitedBlocks.get(p.getName).length++];
      // Fill the new array with the existing values
      for(i = 0; i < blockArray.length; i++){
        blockArray[i] = visitedBlocks.get(p.getName)[i];
      }
      // Assign the new value
      blockArray[blockArray.length] = b;
    }
     
  7. Offline

    tommyhoogstra

    MRPS

    If i'm using the player move event, it would register every location over and over even if the player moves the slightest.
    I only need to add the location of the pressure plate they landed on, your method just seems... over complicated for this? Though I understand it completely and see why it would be used, I am still going to search for perhaps a simpler way of checking landed on pressure plate locations.

    Thanks for that source though, I took it into account.
     
  8. Offline

    MRPS

    tommyhoogstra
    Not sure how you can get much more simple than primitive data types.
     
  9. Offline

    Scizzr

    The only problem with arrays is that you have to redefine it every time you want to add something.


    Working on a proof of concept. Give me a little bit. Also, do you have Skype? Could chat by voice there.
     
  10. Offline

    tommyhoogstra

    Alright thanks < my bukkit ID is the same as my skype, feel free to add me
     
Thread Status:
Not open for further replies.

Share This Page