Solved Getting blocks near a player?

Discussion in 'Plugin Development' started by krizzdawg, May 17, 2016.

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

    krizzdawg

    How do I get the blocks that are nearby a player (In a radius), for example:
    lets say I did /nearby diamondore. I want it to send me a message saying "30 diamondore near you."
    Please help!
     
  2. Offline

    DoggyCode™

    Block.java:
    Represents a block. This is a live object, and only one Block may exist for any given location in a world. The state of the block may change concurrently to your own handling of it; use block.getState() to get a snapshot state of a block which will not be modified.

    Here is a method which will loop through all the blocks between two given locations and return a List<Block>.

    Code:
    public static List<Block> getRegionBlocks(World world, Location loc1, Location loc2) {
      List<Block> blocks = new ArrayList<Block>();
      for(double x = loc1.getX(); x <= loc2.getX(); x++) {
        for(double y = loc1.getY(); y <= loc2.getY(); y++) {
          for(double z = loc1.getZ(); z <= loc2.getZ(); z++) {
            Location loc = new Location(world, x, y, z);
            blocks.add(loc.getBlock());
          }
        }
      }
      return blocks;
    }
    You could then create a list using this method and then loop through it, increasing a counter if the block's material is equal to diamond p:

    Code:
    List<Block> blocks = getRegionBlocks(World#, Location#, Location#);
    int counter = 0;
    for (Block block : blocks) {
      Material type = block.getType();
      if(type.equals(Material.DIAMOND_ORE)) {
        counter++;
      }
    }
    //counter = amount of diamond ores between the two specified locations for the list
    You could possibly do some math in order to get your wanted two locations from the players current location. For the world it's just "Player#getWorld();"
     
  3. Offline

    I Al Istannen

    @DoggyCode™
    I would compare enums with "==" not equals. There can only be ONE instance of an enum ==> Memory address equals every time ==> "==" works. Apart from that, the default imlementation of equals is using "==", unless you specify it otherwise. And it isn't specified as far as I know. "==" is also null safe and more clear to read. I don't know any reason why you should use equals for enums.

    Code:
    Location loc = new Location(world, x, y, z);
    blocks.add(loc.getBlock())
    You are creating a throwaway Location object every time, which then gets garbage collected.
    This is quite inefficient, especially, when World#getBlockAt(int x, int y, int z) is clearer (the intention is more obvious).
    Normally you don't want to do premature optimizations, but in this case it adds to the readability (At least I think so). Depending on the implemenation it also creates a throwaway object, but that is not in your hands. Just checked, it doesn't.
    To get the block location (which is an int), just use Location#getBlockX/Y/Z() instead of Location#getX/Y/Z().

    Instead of a cube you could also use a sphere, checking if the distance is less or equal to the specified radius. Depends on what he wants to do.


    @krizzdawg
    Checking that requires looping through all the blocks nearby, which might get a bit resource heavy. I am not sure, but you may be able to loop through the blocks async. Although I wouldn't encourage you to do so. But I would add some kind of cooldown.
     
    DoggyCode™ likes this.
  4. Offline

    DoggyCode™

    @I Al Istannen Bukkit wouldn't allow you to get a block async I think.

    EDIT:
    "[​IMG] Warning: Asynchronous tasks should never access any API in Bukkit."

    Now it should throw warnings to the console and make it not work.
     
  5. Offline

    I Al Istannen

    @DoggyCode™
    It doesn't actually. It throws an error if it needs to load the chunk (Asynchronous entity add), but works just fine if the chunk is loaded.
    I made an implementation of A* in Minecraft some time ago, and, due to the runtime of these algorithms, it would have lagged the server to death. So I made it async.
    You can catch the exception and then perfrom the lookup for this block synchronous, waiting for the query to finish. The next blocks nearby can then be looked up async.
    Made the whole thing quite a bit faster (-50ms per block, as the call methods returns the value on the next tick).

    You could have probably made it, so that it waits a few ticks, then fetches blocks on the main thread and then sleeps again. But it was some time ago and I didn't think of this. It worked like a charm though.

    Yes, you should never access a method of the Bukkit API async. Some methods are thread safe (at least according to the german wiki page, like Player#sendMessage()). I don't know if they really are though.
    But in this case you don't seem to really get punished for violating it.

    It could also be that it just slipped past the AsyncCatcher and I was just lucky nothing blew off though.
     
  6. Offline

    DoggyCode™

    AsyncCatcher, sounds like some sort of police that's always watching to see if we violate their async rules. Anyways, thanks for that Wiki page, if they all are thread-safe I would now know what Bukkit methods I can run async (although they aren't a lot) ;)
     
Thread Status:
Not open for further replies.

Share This Page