Posted November 3, 201212 yr Hello, Could someone tell me the method to make multiblock structures (e.g. railcraft coke oven or liquid tanks). Just want to know the basic idea behind these. And how I could make the whole thing render as one block and make it clickable as one block? Would be nice if someone could link me to a source code example of any mod implementing this. greets
November 5, 201212 yr The liquid tanks in buildcraft are awesome. The source code is on github which is doubly awesome. Great to look and learn from, but please respect the guy's effort and copyright. https://github.com/SirSengir/BuildCraft/blob/master/common/buildcraft/factory/TileTank.java
January 30, 201312 yr Just throwing a wild guess here but perhaps it's just a block which onUpdate() checks to see if it's a part of a structure(by checking the blocks around it). and if it is, then create a new TileEntityXXX and let all the parts of the struct setTileEntity to that. OnBlockActiviated -> if this.TileEntity != null -> open GUI etc. The railcraft mod warns you that you should NOT use the block as a part of regular construction due to the fact that it will slow down the server with all it's constant checks to see if is a whole coke oven. I have no idea how it is actually done inn RC, but I guess it's something along those lines If you guys dont get it.. then well ya.. try harder...
January 31, 201312 yr a simple way to do it is in the block class public int onBlockPlaced(World par1World, int par2, int par3, int par4, int par5, float par6, float par7, float par8, int par9) { if(par1World.getBlockId(par2, par3, par4) == YourMod.YourBlock.blockID && par1World.getBlockId(par2, par3, par4 + 1) == YourMod.YourBlock.blockID) { par1World.setBlock(par2, par3, par4, YourMod.YourMultiBlockPart.blockID); par1World.setBlock(par2, par3, par4 + 1, YourMod.YourMultiBlockPart.blockID); } } then in your other block class put the open gui things in there or you could use the same one by doing this first declare an integer that equals 0 then public int onBlockPlaced(World par1World, int par2, int par3, int par4, int par5, float par6, float par7, float par8, int par9) { if(par1World.getBlockId(par2, par3, par4) == YourMod.YourBlock.blockID && par1World.getBlockId(par2, par3, par4 + 1) == YourMod.YourBlock.blockID) { multiblock = 1; } else { multiblock = 0; } } then in your on block activated class add this @Override public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int i, float f, float g, float t){ TileEntity tile_entity = world.getBlockTileEntity(x, y, z); if(tile_entity == null || player.isSneaking() || this.multiblock == 0){ return false; } if(this.multiblock == 1) { player.openGui(yourMod.instance, 0, world, x, y, z); return true; } } Creator of Jobo's ModLoader If I helped you could you please click the thank you button and applaud my karma.
January 31, 201312 yr but then the tileentity won't open if you click on the other block. right? or atleast they won't be synced
February 1, 201312 yr I can tell you how I'm doing this in my upcoming stargates mod. The basic idea is that the onBlockAdded method of the component block searches the area around it looking for a particular pattern of blocks. When that pattern is found, the component blocks are flagged as having been merged into a structure. Also, one of the component blocks is picked to be the "master" block having a TileEntity holding the state of the structure as a whole. When any of the component blocks is right-clicked, the click is forwarded to the master block, which opens the GUI. Unmerging is handled by the breakBlock method of the component blocks, which clears the merge flag on all the other merged blocks of the structure. As for rendering the merged structure, I'm doing that using a TileEntitySpecialRenderer on the master block, and the normal block renderers of the component blocks don't render anything when they're merged. But you could also have the component blocks render themselves in two different ways for the merged and unmerged states, or replace the component blocks with different block types when they merge. From what was said about Railcraft above, it sounds like it's using a somewhat inefficient method to detect merging. It shouldn't be necessary to continually check for merging, only when a potential component block is placed or removed, or possibly when a neighbour of such a block changes state.
February 1, 201312 yr I can tell you how I'm doing this in my upcoming stargates mod. The basic idea is that the onBlockAdded method of the component block searches the area around it looking for a particular pattern of blocks. When that pattern is found, the component blocks are flagged as having been merged into a structure. Also, one of the component blocks is picked to be the "master" block having a TileEntity holding the state of the structure as a whole. When any of the component blocks is right-clicked, the click is forwarded to the master block, which opens the GUI. Unmerging is handled by the breakBlock method of the component blocks, which clears the merge flag on all the other merged blocks of the structure. As for rendering the merged structure, I'm doing that using a TileEntitySpecialRenderer on the master block, and the normal block renderers of the component blocks don't render anything when they're merged. But you could also have the component blocks render themselves in two different ways for the merged and unmerged states, or replace the component blocks with different block types when they merge. From what was said about Railcraft above, it sounds like it's using a somewhat inefficient method to detect merging. It shouldn't be necessary to continually check for merging, only when a potential component block is placed or removed, or possibly when a neighbour of such a block changes state. Could you maybe explain a little more how your mod checks for the pattern? I want to make my mod recognize an entire house and give it a health and it sounds like your approach might be able to help me with that.
February 1, 201312 yr I can tell you how I'm doing this in my upcoming stargates mod. The basic idea is that the onBlockAdded method of the component block searches the area around it looking for a particular pattern of blocks. When that pattern is found, the component blocks are flagged as having been merged into a structure. Also, one of the component blocks is picked to be the "master" block having a TileEntity holding the state of the structure as a whole. When any of the component blocks is right-clicked, the click is forwarded to the master block, which opens the GUI. Unmerging is handled by the breakBlock method of the component blocks, which clears the merge flag on all the other merged blocks of the structure. As for rendering the merged structure, I'm doing that using a TileEntitySpecialRenderer on the master block, and the normal block renderers of the component blocks don't render anything when they're merged. But you could also have the component blocks render themselves in two different ways for the merged and unmerged states, or replace the component blocks with different block types when they merge. From what was said about Railcraft above, it sounds like it's using a somewhat inefficient method to detect merging. It shouldn't be necessary to continually check for merging, only when a potential component block is placed or removed, or possibly when a neighbour of such a block changes state. If you could show us exactly what you did, that would be great.
February 3, 201312 yr Here's some of the code I've been working with @Override public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9) { if (isValidCombination(par2, par3, par4, par1World)) { if (par1World.getBlockTileEntity(par2, par3, par4) != null) { System.out.println("This is the master block"); TileEntityFurnace tile = (TileEntityFurnace) par1World.getBlockTileEntity(par2, par3, par4); par5EntityPlayer.displayGUIFurnace(tile); return true; } } return false; } public void onBlockAdded(World world, int x, int y, int z) { if (isValidCombination(x, y, z, world)) { super.onBlockAdded(world, x, y, z); System.out.println("this is a valid combination"); } } For some reason, this code creates three seperate TileEntities when the last block is placed. Can anyone see why this is occuring?
February 3, 201312 yr Here's some of the code I've been working with @Override public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9) { if (isValidCombination(par2, par3, par4, par1World)) { if (par1World.getBlockTileEntity(par2, par3, par4) != null) { System.out.println("This is the master block"); TileEntityFurnace tile = (TileEntityFurnace) par1World.getBlockTileEntity(par2, par3, par4); par5EntityPlayer.displayGUIFurnace(tile); return true; } } return false; } public void onBlockAdded(World world, int x, int y, int z) { if (isValidCombination(x, y, z, world)) { super.onBlockAdded(world, x, y, z); System.out.println("this is a valid combination"); } } For some reason, this code creates three seperate TileEntities when the last block is placed. Can anyone see why this is occuring? how are you detecting if it's valid?
February 3, 201312 yr This is the code that checks for valid combinations private boolean isValidCombination(int x, int y, int z, World world) { if (getNextX(x, y, z, world) && getNextZ(x, y, z, world)) { return getTopRightDiag(x, y, z, world); } if (getNextX(x, y, z, world) && getPrevZ(x, y, z, world)) { return getTopLeftDiag(x, y, z, world); } if (getPrevX(x, y, z, world) && getNextZ(x, y, z, world)) { return getBottomRightDiag(x, y, z, world); } if (getPrevX(x, y, z, world) && getPrevZ(x, y, z, world)) { return getBottomLeftDiag(x, y, z, world); } return false; } private boolean getNextX(int x, int y, int z, World world) { return world.getBlockId(x + 1, y, z) == modHerbcraft.BlockOvenBrick.blockID; } private boolean getPrevX(int x, int y, int z, World world) { return world.getBlockId(x - 1, y, z) == modHerbcraft.BlockOvenBrick.blockID; } private boolean getNextZ(int x, int y, int z, World world) { return world.getBlockId(x, y, z + 1) == modHerbcraft.BlockOvenBrick.blockID; } private boolean getPrevZ(int x, int y, int z, World world) { return world.getBlockId(x, y, z - 1) == modHerbcraft.BlockOvenBrick.blockID; } private boolean getTopLeftDiag(int x, int y, int z, World world) { return world.getBlockId(x + 1, y, z - 1) == modHerbcraft.BlockOvenBrick.blockID; } private boolean getTopRightDiag(int x, int y, int z, World world) { return world.getBlockId(x + 1, y, z + 1) == modHerbcraft.BlockOvenBrick.blockID; } private boolean getBottomLeftDiag(int x, int y, int z, World world) { return world.getBlockId(x - 1, y, z - 1) == modHerbcraft.BlockOvenBrick.blockID; } private boolean getBottomRightDiag(int x, int y, int z, World world) { return world.getBlockId(x + 1, y, z + 1) == modHerbcraft.BlockOvenBrick.blockID; } It's just a boolean check.
February 3, 201312 yr change private boolean getBottomRightDiag(int x, int y, int z, World world) { return world.getBlockId(x + 1, y, z + 1) == CodeLyoko.SuperCalc.blockID; } to private boolean getBottomRightDiag(int x, int y, int z, World world) { return world.getBlockId(x - 1, y, z + 1) == CodeLyoko.SuperCalc.blockID; } but I'm not sure about why it makes 4 different tile entities. EDIT: I figured out why. when you right click each of the blocks to open it, it checks if they're valid and then makes them they're own tile entity.
February 4, 201312 yr Interesting. The TileEntity should only be called once, and that's when the last block is placed. I added a println statement at several points, and it's clear from console feedback that the method calls occur for all blocks when a new one is placed in close proximity to existing ones. The method calls should only happen once. What do I need to change to stop this from happening?
February 4, 201312 yr the method only calls once from what I can tell when I tested it, so I'm not really sure.
February 4, 201312 yr I figured out why!!! In the onActivated method, it checks of it's valid and if so opens the gui. You need to set a variable when the block is placed and is valid and check the variable in the onActivated method
February 4, 201312 yr I previously had a boolean field which would be set to "true" if the block being placed was the master block (ie: it would only be true if it was the last block in the combination). The same problem was still present even with this field present. Additionally, the GUI can only open if a TileEntity exists at the location, so it's creating TileEntities multiple times for some reason. Try this version of the boolean check. It has more console statements and should show the method calls occuring more than once. private boolean isValidCombination(int x, int y, int z, World world) { System.out.println("checking for valid combinations"); if (getNextX(x, y, z, world) && getNextZ(x, y, z, world)) { return getTopRightDiag(x, y, z, world); } if (getNextX(x, y, z, world) && getPrevZ(x, y, z, world)) { return getTopLeftDiag(x, y, z, world); } if (getPrevX(x, y, z, world) && getNextZ(x, y, z, world)) { return getBottomRightDiag(x, y, z, world); } if (getPrevX(x, y, z, world) && getPrevZ(x, y, z, world)) { return getBottomLeftDiag(x, y, z, world); } System.out.println("no combinations found"); return false; } private boolean getNextX(int x, int y, int z, World world) { return world.getBlockId(x + 1, y, z) == modHerbcraft.BlockOvenBrick.blockID; } private boolean getPrevX(int x, int y, int z, World world) { return world.getBlockId(x - 1, y, z) == modHerbcraft.BlockOvenBrick.blockID; } private boolean getNextZ(int x, int y, int z, World world) { return world.getBlockId(x, y, z + 1) == modHerbcraft.BlockOvenBrick.blockID; } private boolean getPrevZ(int x, int y, int z, World world) { return world.getBlockId(x, y, z - 1) == modHerbcraft.BlockOvenBrick.blockID; } private boolean getTopLeftDiag(int x, int y, int z, World world) { return world.getBlockId(x + 1, y, z - 1) == modHerbcraft.BlockOvenBrick.blockID; } private boolean getTopRightDiag(int x, int y, int z, World world) { return world.getBlockId(x + 1, y, z + 1) == modHerbcraft.BlockOvenBrick.blockID; } private boolean getBottomLeftDiag(int x, int y, int z, World world) { return world.getBlockId(x - 1, y, z - 1) == modHerbcraft.BlockOvenBrick.blockID; } private boolean getBottomRightDiag(int x, int y, int z, World world) { return world.getBlockId(x - 1, y, z - 1) == modHerbcraft.BlockOvenBrick.blockID; }
February 4, 201312 yr the block by default will create a tile entity. I guess you need to set something up that tells the block where the tileentity is, and then open the gui for that tileentity
February 4, 201312 yr How is it creating a TileEntity by default? It should only create a TileEntity if a block is added and it detects a valid combination. I tried removing removing references to the superclass, but that doesn't fix it.
February 4, 201312 yr it's this method public TileEntity createNewTileEntity(World world) { return new TileEntitySuperCalc(); }
February 20, 201312 yr Alright can someone come and actually talk me through it because this is just confusing me. Thank You.
February 20, 201312 yr @insane_gravy I figured out how to make it open the gui of a certain block. it's hard to explain, so I'll link you to the code which is on my github. Also, the method "isMultiBlock" is akin to your isValidCombination method. https://github.com/code-lyoko-modding/CodeLyokoMod/blob/master/lyoko/blocks/BlockSuperCalc.java
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.