Encasing a Player in Glass

Discussion in 'Plugin Development' started by AstramG, Jul 21, 2013.

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

    AstramG

    Hello, I am trying to work on a plugin which includes Spells. However, I'm having trouble with one. I'm currently trying to encase a player in glass which will only require 10 blocks to be laid down, then the glass will disappear in 8 seconds and revert the blocks that were changed to glass to their original state. Thank you!
     
  2. Offline

    chasechocolate

    Before you change the block's type, save the BlockState in a list. Then, after 8 seconds, loop through all the states in the list and revert it.
     
  3. Offline

    AstramG

    I understand that, but the main issue is getting the locations that surround the player so I know which blocks to change to glass, sorry for not specifying this.
     
  4. Offline

    ERROR372

    AstramG

    Locations should be:

    • 1 up from player location
    • 2 in front of player location
      • 1 directly in front of them
      • 1 below ^
    • 2 behind player location
      • 1 directly behind them
      • 1 below ^
    • 2 to each side
      • 1 directly to the side
      • 1 below ^
    • 1 underneath the player
    I'm pretty sure the player's location is taken from the block their head is at. Does that help?
     
    AstramG likes this.
  5. Offline

    AstramG

    Thank you, I'll try this! But do you mean 2 below the player for the last one?
     
  6. Offline

    ERROR372

    AstramG

    Oh right, yeah, 2 below the player. Even I get confused =P
     
  7. Offline

    AstramG

    This is my code and it seems to be generating something that is not relevant at all:
    Code:
    public List<BlockState> createGlass(Location loc) {
            //loc is the Player's location
            List<BlockState> blocks = new ArrayList<BlockState>();
            List<BlockState> blocks2 = new ArrayList<BlockState>();
            Block below = loc.add(0, -2, 0).getBlock();
            Block front1 = loc.add(1, 0, 0).getBlock();
            Block front2 = loc.add(1, -1, 0).getBlock();
            Block side11 = loc.add(0, 0, 1).getBlock();
            Block side12 = loc.add(0, -1, 1).getBlock();
            Block side21 = loc.add(0, 0, -1).getBlock();
            Block side22 = loc.add(0, -1, -1).getBlock();
            Block back1 = loc.add(-1, 0, 0).getBlock();
            Block back2 = loc.add(-1, -1, 0).getBlock();
            Block top = loc.add(0, 1, 0).getBlock();
            blocks = Arrays.asList(below.getState(), front1.getState(), front2.getState(), side11.getState(), side12.getState(), side21.getState(), side22.getState(), back1.getState(), back2.getState(), top.getState());
            blocks2 = blocks;
            for (BlockState bs : blocks) {
                Block b = bs.getBlock();
                b.setType(Material.GLASS);
            }
            return blocks2;
        }
    Here is an image of what generates (Note it generates 2 below me):
    http://i.imgur.com/Ctk6gRr.png
     
  8. Offline

    chasechocolate

    ERROR372 I believe it returns the location at their legs/feet.
     
  9. Offline

    ERROR372

    AstramG chasechocolate

    I'm doing some testing with the code. Lots of print statements x_x

    And you are right, it seems to be from the feet, chase.

    AstramG

    OH! I got it!

    location.add(x, y, z) isn't reset every time you call it. So when you have location 0,0,0... you do:

    location.add(1,0,0)... now location is: 1,0,0
    location.add(0,1,0)... now location is: 1,1,0


    That make sense?

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

    blablubbabc

    Yes, that makes sense. You can use location.clone().add(1, 0, 0) instead to make sure to work on a new location object each time.
     
  11. Offline

    Comphenix

    I recommend staying away from the Location object for this exact reason - it's not immutable, so it's very painful to use in algorithms such as this. Instead, just loop through all the blocks near the player.

    You might also want to try sendBlockUpdate() instead, as then you don't have to store the original block ID yourself. Here's a very simple illustration of these two approaches:
    Code:java
    1. private void encasePlayer(Player player) {
    2. Location position = player.getLocation();
    3. World world = player.getWorld();
    4.  
    5. // Location of the current player
    6. int pX = position.getBlockX();
    7. int pY = position.getBlockY();
    8. int pZ = position.getBlockZ();
    9.  
    10. // Note that y goes from [-1, 2] + pY
    11. for (int x = pX - 1; x <= pX + 1; x++) {
    12. for (int y = pY - 1; y <= pY + 2; y++) {
    13. for (int z = pZ - 1; z <= pZ + 1; z++) {
    14.  
    15. boolean insidePlayer = (x == pX && (y == pY || y == pY + 1) && z == pZ);
    16.  
    17. // Only update if we are outside the player boundary box
    18. if (!insidePlayer) {
    19. player.sendBlockChange(new Location(world, x, y, z), Material.GLASS.getId(), (byte)0);
    20. }
    21. }
    22. }
    23. }
    24. }

    To reset the blocks, you simply resend the block changes, but with the block IDs of the actual block instead of glass.

    You could also write your own BoundaryBox class and use that to "grow" the border around the player:
    Code:java
    1. public class BoundaryBox {
    2. public final int left;
    3. public final int top;
    4. public final int front;
    5. public final int right;
    6. public final int bottom;
    7. public final int behind;
    8.  
    9. public BoundaryBox(int left, int top, int front, int right, int bottom, int behind) {
    10. this.left = left;
    11. this.top = top;
    12. this.front = front;
    13. this.right = right;
    14. this.bottom = bottom;
    15. this.behind = behind;
    16. }
    17.  
    18. public BoundaryBox(Location minimum, Location maximum) {
    19. this.left = minimum.getBlockX();
    20. this.top = minimum.getBlockY();
    21. this.front = minimum.getBlockZ();
    22. this.right = maximum.getBlockX();
    23. this.bottom = maximum.getBlockY();
    24. this.behind = maximum.getBlockZ();
    25. }
    26.  
    27. public BoundaryBox grow(int dX, int dY, int dZ) {
    28. return new BoundaryBox(left - dX, top - dY, front - dZ, right + dX, bottom + dY, behind + dZ);
    29. }
    30.  
    31. public boolean intersect(int x, int y, int z) {
    32. return (x >= left && x <= right) &&
    33. (y >= top && y <= bottom) &&
    34. (z >= front && z <= behind);
    35. }
    36. }

    Which you could use like so:
    Code:java
    1. private void encasePlayer(Player player) {
    2. // Bounding box of the given player
    3. Location position = player.getLocation();
    4. World world = position.getWorld();
    5.  
    6. BoundaryBox playerBoundary = new BoundaryBox(
    7. position.clone(),
    8. position.clone().add(0, 1, 0)
    9. );
    10. BoundaryBox glassBoundary = playerBoundary.grow(1, 1, 1);
    11.  
    12. for (int x = glassBoundary.left; x <= glassBoundary.right; x++) {
    13. for (int y = glassBoundary.top; y <= glassBoundary.bottom; y++) {
    14. for (int z = glassBoundary.front; z <= glassBoundary.behind; z++) {
    15.  
    16. // Only update if we are outside the player boundary box
    17. if (!playerBoundary.intersect(x, y, z)) {
    18. player.sendBlockChange(new Location(world, x, y, z), Material.GLASS.getId(), (byte)0);
    19. }
    20. }
    21. }
    22. }
    23. }

    That's the more general solution, which would work for bigger things than players.
     
    chasechocolate likes this.
  12. Offline

    AstramG

    Comphenix Thanks that's very in depth! I will probably be using it in the near future, thanks.
     
Thread Status:
Not open for further replies.

Share This Page