Creating Beds and Doors

Discussion in 'Plugin Development' started by ssell, Mar 26, 2011.

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

    ssell

    When ever I attempt to set a block as a bed or door it does not work. Example:

    Code:
    //Error and corrupts map
    block.setType( Material.BED );
    
    //Spawns only the foot of the bed
    block.setType( Material.BED_BLOCK );
    
    //Error
    block.setType( Material.WOOD_DOOR );
    Does anyone know how to create these?
     
  2. Offline

    Mixcoatl

    Beds and doors consist of more than one block. You'll need to set data on the block to indicate to Minecraft which part of the complete object and which way it faces. Look here for bed data, and here for door data.
     
  3. Offline

    ssell

    Thanks!

    Still having issues with this.

    First the doors:
    No matter whether I place the bottom or top part first, it does not work. Whichever one was set first will resemble a sign and the other one nothing will happen (crash I assume before it gets to it).

    I am doing it something like this:

    Code:
    Block bottomDoor = block;
    Block topDoor = block.getWorld( ).getBlockAt( new Location( block.getWorld( ), block.getLocation( ).getX( ), block.getLocation( ).getY( ) + 1, block.getLocation( ).getZ( ) );
    
    bottomDoor.setType( Material.WOOD_DOOR );
    bottomDoor.setData( ( byte )0 ); //Or whatever the appropriate side is
    
    topDoor.setType( Material.WOOD_DOOR );
    topDoor.setData( ( byte )( ( byte )0 | ( byte )8 );
    Now the beds:
    I can get the beds to work half the time (when they face either East or West). The other two times both pieces I assume get destroyed because there are just two bed items on the ground that I can pick up.

    Now the times they fail, if I set the head segment to a different type of block (and leave it as something different), then the foot will remain.

    I am out of ideas on how to get them to work.

    Code:
    Block footBed;
    Block headBed; //This is initially actually a different block that gets set to a bed later
    
    byte direction;
    
    //
    //Code to find the orientation of the bed
    //
    
    footBed.setData( direction );
    
    headBed.setType( Material.BED_BLOCK );
    headBed.setData( ( byte )( direction | ( byte )8 );
    
    Anyone have any ideas? Hopefully enough information has been provided.

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

    Mixcoatl

    For doors, try this:
    Code:
    Block bottom = ...;
    bottom.setTypeIdAndData(64, (byte) 0, false);
    bottom.getFace(BlockFacing.UP).setTypeIdAndData(64, (byte) 8, true);
    I suspect your bed code is basically okay. You might not be setting the right direction flags. I would have to look into it a little more deeply to understand how each block needs to be flagged. :7

    Try something like this:
    Code:
    for (Block block: list) {
      if (block.getType() == Material.BED_BLOCK) {
        for (BlockFace face: BlockFace.values()) {
          if (face != BlockFace.DOWN && face != BlockFace.UP) {
            final Block facingBlock = block.getFace(face);
            if (facingBlock.getType() == Material.SPONGE) {
              byte flags = (byte) 8;
              switch (face) {
              case BlockFace.EAST:  flags = (byte) (flags | 0x0); break;
              case BlockFace.SOUTH: flags = (byte) (flags | 0x1); break;
              case BlockFace.WEST:  flags = (byte) (flags | 0x2); break;
              case BlockFace.NORTH: flags = (byte) (flags | 0x3); break;
              }
              facingBlock.setTypeIdAndData(26, flags, true);
            }
          }
        }
      }
    }
    I'm not certain if this code will work verbatim. But you can try it.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Aug 23, 2018
  5. Offline

    ssell

    That worked like a charm! Thanks :)

    I know it is very messy but here is the bed direction code.

    I have a List of known blocks that I check through. If I find a BED_BLOCK then I look around it for a SPONGE. I have the Sponge representing where the head of the bed goes.

    I do this because the blocks in the list I am searching through have already been placed in a primary pass. The head of the bed is a sponge block because I am unsure of how to differentiate between the foot and the head, so as you can see at the end I just change the sponge into a BED_BLOCK and set its flags as the head.

    Code:
    //Beds
            for( int i = 0; i < list.size( ); i++ )
            {
                if( list.get( i ).getType( ).equals( Material.BED_BLOCK ) )
                {
                    Location loc = list.get( i ).getLocation( );
    
                    Block check = list.get( i ).getWorld( ).getBlockAt(
                            new Location( list.get( i ).getWorld( ),
                                          loc.getX( ) - 1,
                                          loc.getY( ),
                                          loc.getZ( ) ) );
    
                    Block head = null;
    
                    byte direction = ( byte )0;
    
                    //--------------------------------------------------------------------------
    
                    //Check which direction the head lies
                    //North
                    if( check.getType( ).equals( Material.SPONGE ) )
                    {
                        head = check;
                        direction = ( byte )1;
                    }
    
                    //South
                    if( direction == 0 )
                    {
                        check = list.get( i ).getWorld( ).getBlockAt(
                                new Location( list.get( i ).getWorld( ),
                                              loc.getX( ) + 1,
                                              loc.getY( ),
                                              loc.getZ( ) ) );
    
                        if( check.getType( ).equals( Material.SPONGE ) )
                        {
                            head = check;
                            direction = ( byte )3;
                        }
                    }
    
                    //West
                    if( direction == 0 )
                    {
                        check = list.get( i ).getWorld( ).getBlockAt(
                                new Location( list.get( i ).getWorld( ),
                                              loc.getX( ),
                                              loc.getY( ),
                                              loc.getZ( ) + 1 ) );
    
                        if( check.getType( ).equals( Material.SPONGE ) )
                        {
                            head = check;
                            direction = ( byte )0;
                        }
                    }
    
                    //East
                    if( direction == 0 )
                    {
                        check = list.get( i ).getWorld( ).getBlockAt(
                                new Location( list.get( i ).getWorld( ),
                                              loc.getX( ),
                                              loc.getY( ),
                                              loc.getZ( ) - 1 ) );
    
                        if( check.getType( ).equals( Material.SPONGE ) )
                        {
                            head = check;
                            direction = ( byte )2;
                        }
                    }
    
                    if( head != null )
                    {
                        list.get( i ).setData( direction );
    
                        head.setType( Material.BED_BLOCK );
                        head.setData( ( byte )( direction | ( byte )8 ) );
    
                    }
                }
    }
    I know the above segment can be written better but I am waiting until I have the beds sorted out before I do so.

    Again, any insight you might have is greatly appreciated. Thanks for your help thus far.

    This kind of works. Its obviously making the sponge into the bed but they still get destroyed for whatever reason and just leave behind the bed items that can be picked up.

    I have gotten so many beds from trying to figure this out.

    I really appreciate your help trying to solve this.

    [​IMG]

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Aug 23, 2018
  6. Offline

    Mixcoatl

    In your code, you check direction == 0 for each case. Is that intentional?
    I'm not necessarily advocating rewriting it if it does what you need done. :)
    No problem. :)
     
  7. Offline

    ssell

    If direction is 0 I have not yet found the sponge.

    So I check if it is still 0 so I don't pointlessly reassign check.
     
  8. Offline

    Mixcoatl

    Perhaps you can post the code that places the first bed block. You may be seeing a side effect of block physics being triggered when the first bed block is placed.
    Nice! That's certainly a lot of beds!

    I'm not convinced it's an insurmountable issue. I continue to suspect it has something to do with block physics and the order blocks in which the bed blocks have been placed.
     
  9. Offline

    ssell

    The block order is relatively unknown since the tent 'schema' that the blocks are loaded from is completely customizable.

    The code that actually creates the blocks is

    Code:
    public boolean buildTent( Location location, int alignment, TTTent tent, Player player )
        {
            int length = tent.blockList.get( 0 ).size( );
            int width = tent.blockList.get( 0 ).get( 0 ).size( );
            int height = tent.blockList.size( );
    
            player.sendMessage( ChatColor.GOLD + "Building Tent '" + tent.schemaName + "'!" );
    
            List< Block > newTent = new ArrayList< Block >( );
    
            for( int y = 0; y < height; y++ )
            {
                for( int z = 0; z < length; z++ )
                {
                    for( int x = 0; x < width; x++ )
                    {
                        Location check;
    
                        if( alignment == 1 )
                        {
                            check = new Location( player.getWorld( ),
                                                  location.getX( ) - x,
                                                  location.getY( ) + y,
                                                  location.getZ( ) + z );
                        }
                        else if( alignment == 3 )
                        {
                            check = new Location( player.getWorld( ),
                                                  location.getX( ) + x,
                                                  location.getY( ) + y,
                                                  location.getZ( ) + z );
                        }
                        else if( alignment == 2 )
                        {
                            check = new Location( player.getWorld( ),
                                      location.getX( ) + z,
                                      location.getY( ) + y,
                                      location.getZ( ) - x );
                        }
                        else
                        {
                            check = new Location( player.getWorld( ),
                                      location.getX( ) - z,
                                      location.getY( ) + y,
                                      location.getZ( ) - x );
                        }
    
                        Material material = tent.blockList.get( y ).get( z ).get( x );
    
                        if( material != null )
                        {
                            player.getWorld( ).getBlockAt( check ).setType( material );
    
                            newTent.add( player.getWorld( ).getBlockAt( check ) );
                        }
                    }
                }
            }
            ...
    
    
    Alignment is a value I calculate earlier to make sure the tent doesn't build on top of the player.

    Roughly, the order that the blocks in this situation are being placed would be something like:

    ... Wool, Air, Bed (Foot), Air, Wool, Wool, Furnace, Sponge (Head), Workbench, Wool ...

    They are also always being made on solid ground.

    Hope some of this helps.
     
  10. Offline

    Mixcoatl

    Okay. Interesting. And a very interesting idea, too.
    Here are some thoughts that might help:
    a. Check if the block is the foot of the bed and use a different call to place the block without triggering block physics, then, when replacing the sponge, trigger the block physics "just in case". It's the third argument, in case you were wondering, in the setTypeIdAndData function call.
    b. Perhaps you can use another block, like the sponge, to indicate the foot of the bed. Then replace the blocks as a post-operation once the replace is laid out. That way you'd have more control over the block physics. But, obviously, it requires some additional work and an additional placeholder block.
     
  11. Offline

    ssell

    I tried disabling physics last night after reading your second newest post, but it did nothing.

    After some more fiddling I have the beds working correct for 2 out of 4 situations. The other two instances have the foot of the bed remaining but the head is still being destroyed.

    The modifications that I made were:

    During the initial pass of building the tents I made the foot a jukebox like how I have the head a sponge.

    I also altered the bits you set for directions. You had them as:
    • East : 0x1
    • South: 0x2
    • West: 0x3
    • North: 0x4
    After I got the foots to stay I noticed they were facing the wrong direction. They had be changed to:
    • East : 0x2
    • South: 0x3
    • West: 0x0
    • North: 0x1
    Which is how they are described on the data value page (http://www.minecraftwiki.net/wiki/Data_values#Beds).

    The code now looks like this:

    Code:
            for( int i = 0; i < list.size( ); i++ )
            {
                Block block = list.get( i );
    
                if( block.getType(  ) == Material.JUKEBOX )
                {
                    for( BlockFace face: BlockFace.values( ) )
                    {
                        if( face != BlockFace.DOWN && face != BlockFace.UP )
                        {
                            final Block facingBlock = block.getFace( face );
    
                            if( facingBlock.getType( ) == Material.SPONGE )
                            {
                                byte flags = ( byte )8;
                                byte direction = ( byte )( 0x0 );
    
                                switch( face )
                                {
    
                                  case EAST:
                                      flags = ( byte )( flags | 0x2 );
                                      direction = ( byte )( 0x2 );
                                      break;
    
                                  case SOUTH:
                                      flags = ( byte )( flags | 0x3 );
                                      direction = ( byte )( 0x3 );
                                      break;
    
                                  case WEST:
                                      flags = ( byte )( flags | 0x0 );
                                      direction = ( byte )( 0x0 );
                                      break;
    
                                  case NORTH:
                                      flags = ( byte )( flags | 0x1 );
                                      direction = ( byte )( 0x1 );
                                      break;
                                  }
    
                                if( ( alignment == 3 ) || ( alignment == 1 ) )
                                {
                                    block.setTypeIdAndData( 26, direction, true );
                                    facingBlock.setTypeIdAndData( 26, flags, true );
                                }
                                else
                                {
                                    facingBlock.setTypeIdAndData( 26, flags, true );
                                    block.setTypeIdAndData( 26, direction, true );
                                }
                            }
                        }
                    }
                }
            }
    At the end I have the alignment == part since I noticed that alignments 3 and 1 were the ones working, and 0 and 2 were failing. So thought the order might just need to be switched.

    Which is odd, since with my initial setup it was 0 and 2 working and 3 and 1 failing.

    This puzzle is almost solved.
     
  12. Offline

    Mixcoatl

    Good catch, that. I must've been looking at the wrong section of the page when I did that bit. In my defense, I indicated that the code might not work verbatim. ;)
    If cases 0 and 2 are working, then the problem lies here:
    Code:
    if (alignment == 3 || alignment == 1) {
      block.setTypeIdAndData( 26, direction, true );
      facingBlock.setTypeIdAndData( 26, flags, true );
    }
    Try doing them in the reverse order, since that seems to work in the else block. It could be that only the placement of the head block or foot block of the bed actually triggers the object to become an item entity.
     
  13. Offline

    ssell

    Actually its 3/1 working and 0/2 not working. I made that little if()else() so I could reverse them like you just suggested, but it did not work.

    It is obviously making a bed in the right location, since there is always a little bed to pick up where the head should be. I don't understand it.
     
  14. Offline

    Mixcoatl

    What I'm suggesting is that the block.setTypeIdAndData() and facingBlock.getTypeIdAndData() calls should be executed in the same order than consistently works in the case that does not work, as they seem to be reversed right now.
     
  15. Offline

    ssell

    Oh yea. If they are in the same order then both beds break. If they are reversed at least the foot remains.
     
  16. Offline

    Mixcoatl

    If they're both using the case that works half the time, none of them work at all anymore? I'm skeptical. To me, it suggests that a different case is being executed for the head block than the foot block.
     
  17. Offline

    ssell

    If they both use

    Code:
    block.setTypeIdAndData( 26, direction, true );
    facingBlock.setTypeIdAndData( 26, flags, true );
    Then:
    • Case 1: Both head and foot blocks work
    • Case 2: No blocks work
    • Case 3: Both head and foot blocks work
    • Case 4: No blocks work
    If they both use

    Code:
    facingBlock.setTypeIdAndData( 26, flags, true );
    block.setTypeIdAndData( 26, direction, true );
    Then:
    • Case 1: No blocks work
    • Case 2: Only foot works
    • Case 3: No blocks work
    • Case 4: Only foot works
    So by mixing the two (case 1 and 3 get the block->faceBlock order, and case 2 and 4 get the faceBlock->block order) then:

    • Case 1: Both blocks work
    • Case 2: Only foot works
    • Case 3: Both blocks work
    • Case 4: Only foot works
     
  18. Offline

    Edward Hand

    Not really been following the thread, but I thought it might be useful to see how minecraft placed beds (since it obviously does just fine). I de-obfuscated/commented the important bits for you:
    Code:
         BlockBed localBlockBed = (BlockBed)Block.BED;
    
         //x,y,z represent the user's aim coord
    
         //get the direction user is facing and turn into an integer (0,1,2,3)
         int i = MathHelper.b(paramEntityHuman.yaw * 4.0F / 360.0F + 0.5D) & 0x3;
    
         //j and k are for modifying the x and z coords of the head of the bed
         int j = 0;
         int k = 0;
    
         if (i == 0) k = 1;
         if (i == 1) j = -1;
         if (i == 2) k = -1;
         if (i == 3) j = 1;
    
         //check for space
         if ((theWorld.isAirAt(x, y, z)) && (theWorld.isAirAt(x+j, y, z+k))
         {
             //make blocks - parameters are (X, Y, Z, BlockID, DataValue)
             theWorld.setBlock(x, y, z, localBlockBed.id,  i);
             theWorld.setBlock(x + j, y, z + k, localBlockBed.id,  i + 8);
         }
    you'll need to adapt for the bukkit API of course, but it shouldn't be too hard.
     
  19. Offline

    Sammy

    Jebus, and I always nag about making beds on real life ^^
     
  20. Offline

    Mixcoatl

    I see. Sorry for the confusion. I'm at a loss for why the alignment has any effect.
     
  21. Offline

    ssell

    I see how/why this works and it suggests that it should always be block->faceBlock order, but that just does not work.

    The first part finds the block that will be a bed (I get this from my list), the second the orientation of the bed (Minecraft gets it from the direction the player is facing, I get this from the location of the sponge [head] to the jukebox [foot]), then finally makes the actual blocks and sets their bit flags.

    It all makes sense but my implementation still doesn't work for whatever reason:(

    I got it working!

    After looking again at the Minecraft code that Edward Hand posted, I noticed it checks to make sure that where the head will go is Air.

    So by making sure the Sponge was air before any bed blocks were set, made it so that all cases worked.

    Thank you so much Mixcoatl and Edward Hand! And thanks for the laugh Sammy!

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 13, 2016
  22. Offline

    Mixcoatl

    Woo! Congrats!
     
Thread Status:
Not open for further replies.

Share This Page