Jump to content

Recommended Posts

Posted

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.

xiFvECV.png

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:

 

  Reveal hidden contents

 

Posted
  On 1/25/2017 at 3:15 PM, diesieben07 said:

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?

Posted

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?

Posted
  On 1/25/2017 at 3:48 PM, diesieben07 said:

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);
	}
    }

Posted
  On 1/27/2017 at 1:17 PM, diesieben07 said:

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.

Posted

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.

Posted
  On 1/28/2017 at 1:01 PM, Choonster said:

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.

Posted

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.

Posted
  On 1/28/2017 at 1:18 PM, Choonster said:

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?

Posted

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.

Posted
  On 1/28/2017 at 2:37 PM, Choonster said:

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);
    }

Posted

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.

Posted
  On 1/28/2017 at 3:23 PM, Choonster said:

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?

Posted

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.

Posted
  On 1/28/2017 at 4:16 PM, Choonster said:

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. 

 

  Quote

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);

 

  Quote

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?

 

  Quote

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 :'(

 

 

Posted
  On 1/28/2017 at 4:37 PM, Branone said:

  Quote

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.

 

 

 

  Quote

  Quote

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

.

  • Like 1

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Hi everyone, I'm currently developing a Forge 1.21 mod for Minecraft and I want to display a custom HUD overlay for a minigame. My goal: When the game starts, all players should see an item/block icon (from the base game, not a custom texture) plus its name/text in the HUD – similar to how the bossbar overlay works. The HUD should appear centered above the hotbar (or at a similar prominent spot), and update dynamically (icon and name change as the target item changes). What I've tried: I looked at many online tutorials and several GitHub repos (e.g. SeasonHUD, MiniHUD), but most of them use NeoForge or Forge versions <1.20 that provide the IGuiOverlay API (e.g. implements IGuiOverlay, RegisterGuiOverlaysEvent). In Forge 1.21, it seems that neither IGuiOverlay nor RegisterGuiOverlaysEvent exist anymore – at least, I can't import them and they are missing from the docs and code completion. I tried using RenderLevelStageEvent as a workaround but it is probably not intended for custom HUDs. I am not using NeoForge, and switching the project to NeoForge is currently not an option for me. I tried to look at the original minecraft source code to see how elements like hearts, hotbar etc are drawn on the screen but I am too new to Minecraft modding to understand. What I'm looking for: What is the correct way to add a custom HUD element (icon + text) in Forge 1.21, given that the previous overlay API is missing? Is there a new recommended event, callback, or method in Forge 1.21 for custom HUD overlays, or is everyone just using a workaround? Is there a minimal open-source example repo for Forge 1.21 that demonstrates a working HUD overlay without relying on NeoForge or deprecated Forge APIs? My ideal solution: Centered HUD element with an in-game item/block icon (from the base game's assets, e.g. a diamond or any ItemStack / Item) and its name as text, with a transparent background rectangle. It should be visible to the players when the mini game is running. Easy to update the item (e.g. static variable or other method), so it can change dynamically during the game. Any help, code snippets, or up-to-date references would be really appreciated! If this is simply not possible right now in Forge 1.21, it would also help to know that for sure. Thank you very much in advance!
    • The simple answer is there is not an easy way. You would need to know how to program in Java, as well as at least some familiarity with how Forge works so you could port the differences. You would also need the sourcecode for the original mod, and permission from the author to modify it, if they did not use some sort of open source license. So it's not impossible, but it would take some effort, but doing so would open up a whole new world of possibilities for you!
    • Does it still crash if you remove holdmyitems? Looks like that mod doesn't work on a server as far as I can tell from the error.  
    • Crashes the server when trying to start. Error code -1. Log  
  • Topics

  • Who's Online (See full list)

    • There are no registered users currently online
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.