Posted January 25, 20178 yr Here is my hot tub. As you can see, I can hop inside of it. It has walls which work properly so that I can't just walk out of it. But here's the major problem. When I make the hot tub larger, it doesn't get rid of the collision box for the wall that is no longer there. So because of that, I can't move around in the hot tub (move to the other hot tub part that I placed down). It's only meant to have collision boxes on the faces that are false. Just realised my problem but don't know how to fix it. The addCollisionBoxes method only gets called on once - when it's first placed down. So when the blockstate properties change, the collision boxes don't get updated. How do I update the collision boxes? Block Class: public class BlockHotTub extends Block { public static final PropertyBool BACK = PropertyBool.create("back"); public static final PropertyBool FORWARD = PropertyBool.create("forward"); public static final PropertyBool LEFT = PropertyBool.create("left"); public static final PropertyBool RIGHT = PropertyBool.create("right"); public BlockHotTub(Material materialIn) { super(materialIn); this.setCreativeTab(OddmentsMod.tabOddments); this.setDefaultState(this.blockState.getBaseState().withProperty(BACK, false).withProperty(FORWARD, false).withProperty(LEFT, false).withProperty(RIGHT, false)); } @Override public boolean isOpaqueCube() { return false; } @Override public boolean isFullCube() { return false; } @Override public IBlockState getActualState(IBlockState state, IBlockAccess world, BlockPos pos) { boolean forward = world.getBlockState(pos.north()).getBlock() == this; boolean back = world.getBlockState(pos.south()).getBlock() == this; boolean left = world.getBlockState(pos.west()).getBlock() == this; boolean right = world.getBlockState(pos.east()).getBlock() == this; return state.withProperty(BACK, back).withProperty(FORWARD, forward).withProperty(LEFT, left).withProperty(RIGHT, right); } @Override protected BlockState createBlockState() { return new BlockState(this, new IProperty[] {BACK, FORWARD, LEFT, RIGHT}); } @Override public int getMetaFromState(IBlockState state) { return 0; } @Override public IBlockState getStateFromMeta(int meta) { return this.getDefaultState(); } // Not working but this method is meant to update the value of the boolean properties whenever a hot tub is connected to the current one @Override public void onNeighborBlockChange(World worldIn, BlockPos pos, IBlockState state, Block neighborBlock) { getActualState(state, worldIn, pos); addCollisionBoxesToList(worldIn, pos, state, null, null, null); } public void addCollisionBoxesToList(World worldIn, BlockPos pos, IBlockState state, AxisAlignedBB mask, List<AxisAlignedBB> list, Entity collidingEntity) { if (state.getValue(BACK) == false) { this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.125F); super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } if (state.getValue(FORWARD) == false) { this.setBlockBounds(0.0F, 0.0F, 0.875F, 1.0F, 1.0F, 1.0F); super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } if (state.getValue(LEFT) == false) { this.setBlockBounds(0.0F, 0.0F, 0.0F, 0.125F, 1.0F, 1.0F); super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } if (state.getValue(RIGHT) == false) { this.setBlockBounds(0.875F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.1875F, 1.0F); // the default bounding box at the end of the method? super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } }
January 25, 20178 yr Author The state being passed in is the state you should compute the collision boxes for. So you need to analyze the state and then return different collision boxes based on that. Great, so I just need to check the value of the state passed through using an if statement in this method and add the collision box accordingly?
January 25, 20178 yr Author Sorry, I thought I understood what to do but apparently not. I have one blockstate for the hot tub and in there I have this: { "variants": { "normal": {"model": "odm:hot_tub_empty"}, "back=false,forward=false,left=false,right=false": {"model": "odm:hot_tub_empty"}, "back=true,forward=true,left=true,right=true": {"model": "odm:hot_tub_center_empty"}, "back=true,forward=false,left=false,right=false": {"model": "odm:hot_tub_side_empty"}, "back=false,forward=true,left=false,right=false": {"model": "odm:hot_tub_side_empty", "y": 180}, "back=false,forward=false,left=true,right=false": {"model": "odm:hot_tub_side_empty", "y": 270}, "back=false,forward=false,left=false,right=true": {"model": "odm:hot_tub_side_empty", "y": 90}, "back=true,forward=true,left=false,right=false": {"model": "odm:hot_tub_sides_two_empty", "y": 90}, "back=false,forward=false,left=true,right=true": {"model": "odm:hot_tub_sides_two_empty"}, "back=true,forward=false,left=true,right=false": {"model": "odm:hot_tub_corner_empty", "y": 270}, "back=true,forward=false,left=false,right=true": {"model": "odm:hot_tub_corner_empty"}, "back=false,forward=true,left=true,right=false": {"model": "odm:hot_tub_corner_empty", "y": 180}, "back=true,forward=false,left=true,right=false": {"model": "odm:hot_tub_corner_empty", "y": 270}, "back=true,forward=true,left=false,right=true": {"model": "odm:hot_tub_sides_three_empty"}, "back=false,forward=true,left=true,right=true": {"model": "odm:hot_tub_sides_three_empty", "y": 90}, "back=true,forward=true,left=true,right=false": {"model": "odm:hot_tub_sides_three_empty", "y": 190}, "back=true,forward=false,left=true,right=true": {"model": "odm:hot_tub_sides_three_empty", "y": 270}, } } And in the hot tub's class I have set the blockstate properties: public static final PropertyBool BACK = PropertyBool.create("back"); public static final PropertyBool FORWARD = PropertyBool.create("forward"); public static final PropertyBool LEFT = PropertyBool.create("left"); public static final PropertyBool RIGHT = PropertyBool.create("right"); So under the addCollisionBoxesToList method, what exactly should I be checking for the value of in the if statements?
January 27, 20178 yr Author You get the values for those properties out of the block state using IBlockState::getValue . Sorry again but I'm still struggling to get this to work. I'm checking the value of one of the properties to see if it is true, then if it is I alter the collision box. But when I test this in-game, the block just doesn't have a collision box at all (no matter whether the back is true or false). public void addCollisionBoxesToList(World worldIn, BlockPos pos, IBlockState state, AxisAlignedBB mask, List<AxisAlignedBB> list, Entity collidingEntity) { if (state.getValue(BACK) == true) { this.setBlockBounds(0.5F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } }
January 28, 20178 yr Author Don't call setBlockBounds like that, you have to actually add the collision box. Do you mean by calling setBlockBounds in the constructor? Because when I do that, I still get this problem where my collision boxes aren't all adding together but instead it's just taking the last block bounds that I set in the addCollisionBoxes method. I want the hot tub to have a regular 1x1x1 bound box which you look at to select the block and break/interact with it. But I want the actual collision of the hot tub to vary depending on what type of hot tub it is (if it's facing left it's missing its left wall or if it's in the corner it's missing both its right and left wall etc.) I have looked at the BrewingStand code as Choonster pointed out to be a good reference for collision boxes, but I can't find anything in there which uses some other function to add the collision box.
January 28, 20178 yr Which version of Minecraft are you using? My advice in your previous thread assumed you were using 1.9+, but it looks like you're using 1.8.9 (where the collision box logic is slightly different). In 1.8.x, you override Block#addCollisionBoxesToList to call Block#setBlockBounds followed by the super method for each bounding box, then call Block#setBlockBounds to restore the block's default bounding box at the end of the method. To make it easier to update to newer versions, I suggest you store each bounding box in a static final field and create a method like Block#setBlockBounds that sets Block#minX/Y/Z and Block#maxX/Y/Z from the coordinates of an AxisAlignedBoundingBox . When you update to 1.9+, you can simply replace each pair of calls to this method and the super method with calls to Block.addCollisionBoxToList . Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
January 28, 20178 yr Author Which version of Minecraft are you using? My advice in your previous thread assumed you were using 1.9+, but it looks like you're using 1.8.9 (where the collision box logic is slightly different). In 1.8.x, you override Block#addCollisionBoxesToList to call Block#setBlockBounds followed by the super method for each bounding box, then call Block#setBlockBounds to restore the block's default bounding box at the end of the method. You are correct, I am using 1.8.9. So here's my current code (I added that last thing you said to it): public void addCollisionBoxesToList(World worldIn, BlockPos pos, IBlockState state, AxisAlignedBB mask, List<AxisAlignedBB> list, Entity collidingEntity) { if (state.getValue(BACK) == false) { this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.125F); super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } if (state.getValue(FORWARD) == false) { this.setBlockBounds(0.0F, 0.0F, 0.875F, 1.0F, 1.0F, 1.0F); super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } if (state.getValue(LEFT) == false) { this.setBlockBounds(0.0F, 0.0F, 0.0F, 0.125F, 1.0F, 1.0F); super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } if (state.getValue(RIGHT) == false) { this.setBlockBounds(0.875F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F); // the default bounding box at the end of the method? super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } The default bounding box is the base of the hot tub which is obviously always going to be there regardless of how big the hot tub is.
January 28, 20178 yr Are those properties stored in the metadata or set in the actual state? If it's the latter, you have to call Block#getActualState yourself. In 1.11.2, an extra boolean parameter was added to Block#addCollisionBoxToList indicating whether the actual state should be used ( false ) or not ( true ). Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
January 28, 20178 yr Author Are those properties stored in the metadata or set in the actual state? If it's the latter, you have to call Block#getActualState yourself. In 1.11.2, an extra boolean parameter was added to Block#addCollisionBoxToList indicating whether the actual state should be used ( false ) or not ( true ). I believe they are stored in the actual state. But to avoid any confusion, here is the hot tub's class code just in case I'm wrong: public class BlockHotTub extends Block { public static final PropertyBool BACK = PropertyBool.create("back"); public static final PropertyBool FORWARD = PropertyBool.create("forward"); public static final PropertyBool LEFT = PropertyBool.create("left"); public static final PropertyBool RIGHT = PropertyBool.create("right"); public BlockHotTub(Material materialIn) { super(materialIn); this.setCreativeTab(OddmentsMod.tabOddments); this.setDefaultState(this.blockState.getBaseState().withProperty(BACK, false).withProperty(FORWARD, false).withProperty(LEFT, false).withProperty(RIGHT, false)); } @Override public boolean isOpaqueCube() { return false; } @Override public boolean isFullCube() { return false; } @Override public IBlockState getActualState(IBlockState state, IBlockAccess world, BlockPos pos) { boolean forward = world.getBlockState(pos.north()).getBlock() == this; boolean back = world.getBlockState(pos.south()).getBlock() == this; boolean left = world.getBlockState(pos.west()).getBlock() == this; boolean right = world.getBlockState(pos.east()).getBlock() == this; return state.withProperty(BACK, back).withProperty(FORWARD, forward).withProperty(LEFT, left).withProperty(RIGHT, right); } @Override protected BlockState createBlockState() { return new BlockState(this, new IProperty[] {BACK, FORWARD, LEFT, RIGHT}); } @Override public int getMetaFromState(IBlockState state) { return 0; } @Override public IBlockState getStateFromMeta(int meta) { return this.getDefaultState(); } // Not working but this method is meant to update the value of the boolean properties whenever a hot tub is connected to the current one @Override public void onNeighborBlockChange(World worldIn, BlockPos pos, IBlockState state, Block neighborBlock) { getActualState(state, worldIn, pos); } public void addCollisionBoxesToList(World worldIn, BlockPos pos, IBlockState state, AxisAlignedBB mask, List<AxisAlignedBB> list, Entity collidingEntity) { if (state.getValue(BACK) == false) { this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.125F); super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } if (state.getValue(FORWARD) == false) { this.setBlockBounds(0.0F, 0.0F, 0.875F, 1.0F, 1.0F, 1.0F); super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } if (state.getValue(LEFT) == false) { this.setBlockBounds(0.0F, 0.0F, 0.0F, 0.125F, 1.0F, 1.0F); super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } if (state.getValue(RIGHT) == false) { this.setBlockBounds(0.875F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.1875F, 1.0F); // the default bounding box at the end of the method? super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } } Just realised my problem but don't know how to fix it. The addCollisionBoxes method only gets called on once - when it's first placed down. So when the blockstate properties change, the collision boxes don't get updated. How do I update the collision boxes?
January 28, 20178 yr Since the properties are stored in the actual state, you need to call Block#getActualState and get the values from the IBlockState returned by it. Block#addCollisionBoxesToList is called whenever an entity moves into the block space and in various other places. You don't need to manually update it. Side note: Always annotate override methods with @Override . Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
January 28, 20178 yr Author Since the properties are stored in the actual state, you need to call Block#getActualState and get the values from the IBlockState returned by it. Block#addCollisionBoxesToList is called whenever an entity moves into the block space and in various other places. You don't need to manually update it. Side note: Always annotate override methods with @Override . Okay, I'm slightly confused as to how to call it. Should I just be calling getActualState within the addCollisionBoxes method like so? @Override public void addCollisionBoxesToList(World worldIn, BlockPos pos, IBlockState state, AxisAlignedBB mask, List<AxisAlignedBB> list, Entity collidingEntity) { getActualState(state, worldIn, pos); if (state.getValue(BACK) == false) { this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.125F); super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } if (state.getValue(FORWARD) == false) { this.setBlockBounds(0.0F, 0.0F, 0.875F, 1.0F, 1.0F, 1.0F); super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } if (state.getValue(LEFT) == false) { this.setBlockBounds(0.0F, 0.0F, 0.0F, 0.125F, 1.0F, 1.0F); super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } if (state.getValue(RIGHT) == false) { this.setBlockBounds(0.875F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); } this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.1875F, 1.0F); // the default bounding box at the end of the method? super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity); }
January 28, 20178 yr getActualState doesn't modify its arguments (and it can't, since IBlockState is immutable), it returns the actual state. You need to get the values from the IBlockState returned by getActualState instead of getting them from the IBlockState argument. Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
January 28, 20178 yr Author You need to get the values from the IBlockState returned by getActualState I can tell you're spelling the answer out for me but I'm just not getting it The addCollisionBoxesToList method needs to constantly know what BACK, FORWARD, LEFT and RIGHT are equal to. And to do this, you're saying that I need to call the getActualState method whenever addCollisionBoxesToList is called on. This makes complete sense to me so far, but the matter of calling the method properly is what I don't understand. This is my understanding of it: The getActualState method sets the boolean fields: forward, back, left and right and then gives those values to my PropertyBools using the return keyword followed by state.withProperty(BACK, back), state.withProperty(FORWARD, forward), state.withProperty(LEFT, left) and state.withProperty(RIGHT, right). When the addCollisionBoxesToList method checks what, for example, BACK is equal to, shouldn't I call everything in the getActualState method?
January 28, 20178 yr Your getActualState method checks each of the adjacent blocks to see if they're hot tubs and then returns an IBlockState with the BACK , FORWARD , LEFT and RIGHT properties set to the appropriate values. Your addCollisionBoxesToList method needs to call getActualState and store the IBlockState returned by it in a variable. It then needs to call IBlockState#getValue on this IBlockState value instead of the IBlockState argument. Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
January 28, 20178 yr Author Your getActualState method checks each of the adjacent blocks to see if they're hot tubs and then returns an IBlockState with the BACK , FORWARD , LEFT and RIGHT properties set to the appropriate values. I completely understand this and it serves as a much better explanation of the code than my attempt. Your addCollisionBoxesToList method needs to call getActualState Got it. public void addCollisionBoxesToList(World worldIn, BlockPos pos, IBlockState state, AxisAlignedBB mask, List<AxisAlignedBB> list, Entity collidingEntity) { getActualState(state, worldIn, pos); and store the IBlockState returned by it in a variable. This is where you lose me. What exactly is it that I'm storing in this variable? And are you referring to each of the four possible properties? Are these what I need to be storing in variables? It then needs to call IBlockState#getValue on this IBlockState value instead of the IBlockState argument. So here you mean instead of having state.getValue(BACK) I should be putting state.getValue(variable that stores the state.withProperty(BACK, back)? It's 3AM and I should probably spare you anymore trouble. I feel like a pest at this point. Maybe going over the forge documentation a few more times and I'll eventually get it :'(
January 28, 20178 yr and store the IBlockState returned by it in a variable. This is where you lose me. What exactly is it that I'm storing in this variable? And are you referring to each of the four possible properties? Are these what I need to be storing in variables? getActualState returns a value of type IBlockState , you need to store this value in a variable. It then needs to call IBlockState#getValue on this IBlockState value instead of the IBlockState argument. So here you mean instead of having state.getValue(BACK) I should be putting state.getValue(variable that stores the state.withProperty(BACK, back)? Instead of calling state.getValue(...) , call actualState.getValue(...) ; where actualState is the variable storing the value returned by getActualState . Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.