Jump to content

Change placed block according to neighbouring blocks


Bugsy6

Recommended Posts

I'm trying to make a water pipe system that works like redstone.

 

This is my first project, it has already helped me learn so much, but now I'm a bit stuck.

 

I would like the Pipe block to change model depending on the blocks surrounding it. So if there is a block above the new block and to the right of the new block then it should place a corner pipe, or if there is a block above, below and to the side or both sides lay a junction type pipe block.

 

I have made the corner model and it works in the game, I just can't get the logic to make it change block model.

 

Here's the code I've written to try and do it. If more code is needed I can post more.

 

 

 

public void getBlockMetadata(World world, int x, int y, int z)
{
	int i = world.getBlockId(x + 1, y, z);
	int j = world.getBlockId(x, y, z - 1);
	int k = world.getBlockId(x, y, z + 1);
	int l = world.getBlockId(x - 1, y, z);

	if(j == this.blockID && i == this.blockID)
	{
		world.setBlock(x, y, z, SteamPower.LeadPipeCorner.blockID);
	}
	else if(i == this.blockID && k == this.blockID)
	{
		world.setBlock(x, y, z, SteamPower.LeadPipeCorner.blockID);
	}
	else if(k == this.blockID && l == this.blockID)
	{
		world.setBlock(x, y, z, SteamPower.LeadPipeCorner.blockID);
	}
	else if(l == this.blockID && j == this.blockID)
	{
		world.setBlock(x, y, z, SteamPower.LeadPipeCorner.blockID);
	}
	else
	{
		world.setBlock(x, y, z, SteamPower.LeadPipe.blockID);
	}
}

 

 

Link to comment
Share on other sites

if(...) corner pipe

else if(...) corner pipe

else if(...) corner pipe

else if(...) corner pipe

else if(...) corner pipe

else if(...) corner pipe

else if(...) corner pipe

...

 

Gee.  I wonder what's wrong with this picture.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

With the risk of me not seeing how the previous post was the most helpful post ever could someone please elaborate.

 

I'm staring at this if statement trying to see the issue.

 

It always displays the straight pipe even though my if statement says if these to conditions are there then lay a different block ID.

Link to comment
Share on other sites

With the risk of me not seeing how the previous post was the most helpful post ever could someone please elaborate.

 

Your entire if-block results in corner pieces, with exception of the final else.

 

Your code CANNOT generate anything else:

 

if(j == this.blockID && i == this.blockID)

{

world.setBlock(x, y, z, SteamPower.LeadPipeCorner.blockID);

}

else if(i == this.blockID && k == this.blockID)

{

world.setBlock(x, y, z, SteamPower.LeadPipeCorner.blockID);

}

else if(k == this.blockID && l == this.blockID)

{

world.setBlock(x, y, z, SteamPower.LeadPipeCorner.blockID);

}

else if(l == this.blockID && j == this.blockID)

{

world.setBlock(x, y, z, SteamPower.LeadPipeCorner.blockID);

}

else

{

world.setBlock(x, y, z, SteamPower.LeadPipe.blockID);

}

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

Ok, but I want it to find and generate corner pieces.

 

At the moment all that is placed in the world is straight pieces, the code doesn't seem to change them to the corner pieces.

 

It almost seems to either disregard the code or using setBlockId isn't the right function, maybe?

 

Thanks for trying to help.

Link to comment
Share on other sites

It almost seems to either disregard the code or using setBlockId isn't the right function, maybe?

 

Let's see...

 

public void getBlockMetadata(...) {...}

 

Yeah, I'd say that's the wrong function.

 

You should be using onPlaced or onAdded as well as onNeighborChanged.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

Ok so I'm not having any luck with these addition, can't think what I need to add.

 

I've been looking at the redstone block to try and use similar code it uses to change texture, but it doesn't seem to transfer across. I think it is because I'm using a full model as opposed to just a texture.

 

Anymore guidance would be appreciated.

 

 

public void onPlaced(World world, int x, int y, int z)
{
	int i = world.getBlockId(x + 1, y, z);
	int j = world.getBlockId(x, y, z - 1);
	int k = world.getBlockId(x, y, z + 1);
	int l = world.getBlockId(x - 1, y, z);
	  
	if(j == this.blockID && i == this.blockID)
	{
		world.setBlock(x, y, z, SteamPower.LeadPipeCorner.blockID);
	}
	else if(i == this.blockID && k == this.blockID)
	{
		world.setBlock(x, y, z, SteamPower.LeadPipeCorner.blockID);
	}
	else if(k == this.blockID && l == this.blockID)
	{
	    world.setBlock(x, y, z, SteamPower.LeadPipeCorner.blockID);
	}
	else if(l == this.blockID && j == this.blockID)
	{
	    world.setBlock(x, y, z, SteamPower.LeadPipeCorner.blockID);
	} 
	else
	{
	    world.setBlock(x, y, z, SteamPower.LeadPipe.blockID);
	}
}

/**
     * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z
     */
    public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4)
    {
        return par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4);
    }
    
    public void onNeighborChanged(World par1World, int par2, int par3, int par4, int par5)
    {
    	 if (!par1World.isRemote)
         {
             boolean flag = this.canPlaceBlockAt(par1World, par2, par3, par4);

             if (flag)
             {
                 
             }
             else
             {
                 this.dropBlockAsItem(par1World, par2, par3, par4, 0, 0);
                 par1World.setBlockToAir(par2, par3, par4);
             }

             super.onNeighborBlockChange(par1World, par2, par3, par4, par5);
         }
    }

 

Link to comment
Share on other sites

Haven't had any luck with trying a few bits out.

 

I've been pouring over the redstone block files and render files to try and see how it decides on what textures, but in the end ths wasn't that helpful as I want to use a different Block model all together.

 

Any help on how to check surrounding blocks and then place the relevant block model would be appreciated.

Link to comment
Share on other sites

BuildCraft is open source I believe.  Look for it on Github.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

The first step to do this is using metadata. I created a similar block, like a fence block, you need to check each block next to it set every scenario to a metadata, for example, I set up booleans representing north, south, east, west, up.  Do a check on each spot, if there is a pipe north of the block set boolean to true, if not set it to false.  Do this for all the directions and then you will have to set a metadata for each scenario.  For example if(!south && !north && !east && !west) { set metdata to 0.  that would mean the block has no surrounding pipes, then you would have to do each possible outcome as a metdata.  If only pipe to the east, that would be one metadata, if pipe is to the east and west another seperate metata.  Then in the TileEntityRender you get the blocks metadata and based on the metadata you render the proper model.

Link to comment
Share on other sites

Fences actually don't use metadata :P

The fence renderer checks neighboring blocks in the render function.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

Thanks a bunch Robustus for that I've started implementing that way of doing it, I will report my progress lol.

 

Also thanks Draco for pointing me at Buildcraft source code that has been a huge help.

 

Hopefully get this cracked after work!

Link to comment
Share on other sites

True it doesn't, but someone had once advised me that checking neighboring blocks in the render call is a drain on resources, but what do I know

 

It would be more intensive than if you used metadata.  But if you can't use metadata (like redstone, because metadata is being used for other things, or for devices that have more than 16 configurations, like pipes) then it's not too bad.

 

You'd actually be surprised, but the 3D render calls (the tessalator) aren't performed that often.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

Ok, I've got myself stuck any guidance would be appreciated.

 

So I added this in the renderer to get the meta data, though I don't think this is right lol.

 

 

public TileEntityLeadPipeRenderer(World world, int x, int y, int z, Block block, int d)
{
	this.blockMetadata = BlockLeadPipe.checkNeighbour(world, x, y, z, block, d);

	int i = world.getBlockMetadata(x, y, z);

	if(i == 0)
	{
		model = new ModelLeadPipe();
	}
	else if(i == 1)
	{
		model1 = new ModelLeadPipeCorner();
	}
}

 

 

 

Then I made this function in the block file to set block meta data, I think.

 

 

public static boolean checkNeighbour(World world, int x, int y, int z, Block block, int d)
{		
	int g = world.getBlockId(x, y, z);

	int i = world.getBlockId(x, y, z - 1);
	int j = world.getBlockId(x + 1, y, z);
	int k = world.getBlockId(x, y, z + 1);
	int l = world.getBlockId(x-1, y, z);
	int m = world.getBlockId(x, y + 1, z);
	int n = world.getBlockId(x, y - 1, z);

	if(i == g)
	{
		world.setBlock(x, y, z, g, 0, 2);
		return true;
	}
	if(j == g)
	{
		world.setBlock(x, y, z, g, 0, 2);
		return true;
	}	
	if(k == g)
	{
		world.setBlock(x, y, z, g, 0, 2);
		return true;
	}	
	if(l == g)
	{
		world.setBlock(x, y, z, g, 0, 2);
		return true;
	}	
	if(i == g && j == g)
	{
		world.setBlock(x, y, z, g, 1, 2);
		return true;
	}	
	if(i == g && l == g)
	{
		world.setBlock(x, y, z, g, 1, 2);
		return true;
	}	
	if(k == g && j == g)
	{
		world.setBlock(x, y, z, g, 1, 2);
		return true;
	}	
	if(k == g && l == g)
	{
		world.setBlock(x, y, z, g, 1, 2);
		return true;
	}
	return false;	
}

 

 

Link to comment
Share on other sites

Instead of trying to change the renderer to choose a certain model and texture depending on metadata, would it be easier to get the Block file to choose a different TileEntityRenderer depending on the meta data?

 

 

Link to comment
Share on other sites

So in the Block file I now have this:

 

 

public void checkNeighbour(World world, int x, int y, int z, Block block, int d)
{		
	int g = world.getBlockId(x, y, z);

	int i = world.getBlockId(x, y, z - 1);
	int j = world.getBlockId(x + 1, y, z);
	int k = world.getBlockId(x, y, z + 1);
	int l = world.getBlockId(x-1, y, z);
	int m = world.getBlockId(x, y + 1, z);
	int n = world.getBlockId(x, y - 1, z);

	if(i == g)
	{
		world.setBlockMetadata(x, y, z, 0);
	}
	if(j == g)
	{
		world.setBlockMetadata(x, y, z, 0);
	}	
	if(k == g)
	{
		world.setBlockMetadata(x, y, z, 0);
	}	
	if(l == g)
	{
		world.setBlockMetadata(x, y, z, 0);
	}	
	if(i == g && j == g)
	{
		world.setBlockMetadata(x, y, z, 1);
	}	
	if(i == g && l == g)
	{
		world.setBlockMetadata(x, y, z, 1);
	}	
	if(k == g && j == g)
	{
		world.setBlockMetadata(x, y, z, 1);
	}	
	if(k == g && l == g)
	{
		world.setBlockMetadata(x, y, z, 1);
	}	

}

 

 

Then instead of using the creatTileentity method I put this inside the onBlockAdded:

 

int i = par1World.getBlockMetadata(par2, par3, par4);
        
        if(i == 0)
        {
        	par1World.setBlockTileEntity(par2, par3, par4, new TileEntityLeadPipe());
        }
        else if(i == 1)
        {
        	par1World.setBlockTileEntity(par2, par3, par4, new TileEntityLeadPipeCorner());
        }

 

 

Though now when I go into the game the block still places (I can see the bounding lines around the cube), but there is no model rendered.

 

So it doesn't seem to be picking a tileentity in my if statement.

 

Help I'm lost lol.

 

Edit: So my issue (after using the system.out) seems to be in the createTileEntity method. I'm not sure how to pass the metadata into that method so I can then do an if statement to choose which rendering to use depending on the metadata.

 

Thanks for any help.

Link to comment
Share on other sites

Ok so I have got the onBlockAdded function to send the metadata of the newly placed block to the create TileEntity class, but now the block isn't rendering.

 

It has the correct metadata and seems to be receiving it correctly, I've checked by using System outs, here's the code:

 

@Override
public TileEntity createTileEntity(World world, int metadata)
{ 		
	System.out.println(metadata);
	if(metadata == 0)
        {
        	return new TileEntityLeadPipe();
        }
        else if(metadata == 1)
        {
        	return new TileEntityLeadPipeCorner();
        }
		return null;
}

 

 

The problem seems to be that the renderer isn't running through, if I put a system out in the renderer nothing prints to the console, I'm just left with invisible blocks. Here's the renderer:

 

package SteamPower.Blocks;

import org.lwjgl.opengl.GL11;

import SteamPower.Models.ModelLeadPipe;
import SteamPower.Models.ModelLeadPipeCorner;
import net.minecraft.block.Block;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;

public class TileEntityLeadPipeRenderer extends TileEntitySpecialRenderer
{

public TileEntityLeadPipeRenderer()
{

		model = new ModelLeadPipe();
}

public void renderAModelAt(TileEntityLeadPipe tile, double d, double d1, double d2, float f) 
{
	int rotation = 0;

	if(tile.worldObj != null)
	{
		System.out.println("hello");
		rotation = tile.getBlockMetadata();
	}

	bindTextureByName("/textures/models/ModelLeadPipe.png");
	GL11.glPushMatrix();
	GL11.glTranslatef((float)d + 0.5F, (float)d1 + 1.5F, (float)d2 + 0.5F);
	GL11.glScalef(1.0F, -1F, -1F);
	GL11.glRotatef(rotation*90, 0.0F, 1.0F, 0.0F);
	model.renderAll();


	GL11.glPopMatrix(); //end
}

	private ModelLeadPipe model;

@Override
public void renderTileEntityAt(TileEntity tileentity, double d0, double d1, double d2, float f)
{
	this.renderAModelAt((TileEntityLeadPipe)tileentity, d0, d1, d2, f);

}

}

 

Link to comment
Share on other sites

Ok so I had a little break did some other bits and now I'm back to being lost on this again.

 

I want to place a block and have it render the correct model depending on its surrounding blocks.

 

Here is my onBlockPlacedBy code which sets the blocks metadata depending on its surroundings:

 

int g = par1World.getBlockId(par2, par3, par4);

	int i = par1World.getBlockId(par2, par3, par4 - 1);
	int j = par1World.getBlockId(par2 + 1, par3, par4);
	int k = par1World.getBlockId(par2, par3, par4 + 1);
	int l = par1World.getBlockId(par2-1, par3, par4);
	int m = par1World.getBlockId(par2, par3 + 1, par4);
	int n = par1World.getBlockId(par2, par3 - 1, par4);

	if(i == g && j != g && k != g && l != g)
	{
		int o = 0;
		par1World.setBlockMetadata(par2, par3, par4, o);
		this.createTileEntity(par1World, o);
	}
	if(j == g && i != g && k != g && l != g)
	{
		int o = 0;
		par1World.setBlockMetadata(par2, par3, par4, 0);
		this.createTileEntity(par1World, o);
	}	
	if(k == g && j != g && i != g && l != g)
	{
		int o = 0;
		par1World.setBlockMetadata(par2, par3, par4, 0);
		this.createTileEntity(par1World, o);
	}	
	if(l == g && j != g && k != g && i != g)
	{
		int o = 0;
		par1World.setBlockMetadata(par2, par3, par4, 0);
		this.createTileEntity(par1World, o);
	}	
	if(i == g && j == g)
	{
		int o = 1;
		par1World.setBlockMetadata(par2, par3, par4, 1);
		this.createTileEntity(par1World, o);
	}	
	if(i == g && l == g)
	{
		int o = 1;
		par1World.setBlockMetadata(par2, par3, par4, 1);
		this.createTileEntity(par1World, o);
	}	
	if(k == g && j == g)
	{
		int o = 1;
		par1World.setBlockMetadata(par2, par3, par4, 1);
		this.createTileEntity(par1World, o);
	}	
	if(k == g && l == g)
	{
		int o = 1;
		par1World.setBlockMetadata(par2, par3, par4, 1);
		this.createTileEntity(par1World, o);
	}	

 

 

Then I have this code to set the TileEntity:

 

@Override
public TileEntity createTileEntity(World world, int metadata)
{ 		
	if(metadata == 0)
        {
		renderID = -1;
        	return new TileEntityLeadPipe();
        }
        else if(metadata == 1)
        {
        	renderID = -2;
        	return new TileEntityLeadPipeCorner();
        }
		return null;			
}

 

 

It also sets the variable renderID which is then called in the getRenderType function:

 

@Override
public int getRenderType()
{
	System.out.println(renderID);
	return renderID;
}

 

 

Though the block doesn't render at all just the block bounds lines, so any ideas what I'm missing here.

 

Thanks.

Link to comment
Share on other sites

 

@Override
public int getRenderType()
{
	System.out.println(renderID);
	return renderID;
}

 

 

And that variable is equal to..?

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

Ok the good news is that I've got the blocks to render and I have got them to partial change depending on their surrounding blocks. Though they aren't changing as I want them to, of course lol.

 

So I changed the code when the block is added to simply set a value to a variable:

 

int g = SteamPower.LeadPipe.blockID;

	int i = par1World.getBlockId(par2, par3, par4 - 1);
	int j = par1World.getBlockId(par2 + 1, par3, par4);
	int k = par1World.getBlockId(par2, par3, par4 + 1);
	int l = par1World.getBlockId(par2-1, par3, par4);
	int m = par1World.getBlockId(par2, par3 + 1, par4);
	int n = par1World.getBlockId(par2, par3 - 1, par4);

	if(i == g && j != g && k != g && l != g)
	{
		MetaData = 0;
	}
	if(j == g && i != g && k != g && l != g)
	{
		MetaData = 0;
	}	
	if(k == g && j != g && i != g && l != g)
	{
		MetaData = 0;
	}	
	if(l == g && j != g && k != g && i != g)
	{
		MetaData = 0;
	}	
	if(i == g && j == g && k != g && l != g)
	{
		MetaData = 1;
	}	
	if(i == g && l == g && k != g && j != g)
	{
		MetaData = 1;
	}	
	if(k == g && j == g && i != g && l != g)
	{
		MetaData = 1;
	}	
	if(k == g && l == g && i != g && j != g)
	{
		MetaData = 1;
	}	

 

 

Then this variable is called in the createTileEnitity function and used to determine what Entity to use and sets a renderID, which is then used in the getRenderType function:

 

@Override
public TileEntity createNewTileEntity(World world) {

	if(MetaData == 0)
        {
		renderID = -1;
        	return new TileEntityLeadPipe();
        }
        else if(MetaData == 1)
        {
        	renderID = -2;
        	return new TileEntityLeadPipeCorner();
        }
		return null;	
}

 

 

So my issue now is that it seems to be a bit random to what block is place and seems to hold the last placed block model, so when I place another block anywhere if it was the corner pipe it will place that one again, I want it to revert to straight pipe after being used.

Link to comment
Share on other sites

So I narrowed the error down to when I place a corner piece it lays a straight piece, but then if I remove it and lay it again this time it will be a corner piece.

 

It seems to take the first placed block to change the model then the second time its placed it actually renders the right block.

 

Any ides what is going on?

Link to comment
Share on other sites

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



×
×
  • Create New...

Important Information

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