Bektor Posted June 13, 2014 Share Posted June 13, 2014 Hello. I'm using the lastest forge version with Java 8 and I'm getting every time a crash when I add particle to my Campfire block. So what I'm doing wrong, and no its not the particle class, because the same code without TileEntity and custom renderer worked fine. package minecraftplaye.primevalforest.blocks; import java.util.Random; import cpw.mods.fml.client.FMLClientHandler; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import minecraftplaye.primevalforest.PrimevalForest; import minecraftplaye.primevalforest.items.PFItems; import minecraftplaye.primevalforest.tilentities.TileEntityCampFire; import net.minecraft.block.Block; import net.minecraft.block.ITileEntityProvider; import net.minecraft.block.material.Material; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.IIcon; import net.minecraft.util.MathHelper; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; public class BlockPFCampFire extends Block implements ITileEntityProvider { protected BlockPFCampFire() { super(Material.wood); this.setStepSound(Block.soundTypeWood); this.setHardness(3.0F); } @Override /** * Returns a new instance of a block's tile entity class. Called on placing the block. */ public TileEntity createNewTileEntity(World world, int var2) { return new TileEntityCampFire(); } public IIcon getIcon(int side, int meta) { return Blocks.log.getIcon(side, 0); } // It's not an opaque cube, so you need this. @Override public boolean isOpaqueCube() { return false; } // You don't want the normal render type, or it wont render properly. @Override public int getRenderType() { return -1; } // It's not a normal block, so you need this too. @Override public boolean renderAsNormalBlock() { return false; } @Override /** * Returns the items to drop on destruction. */ public Item getItemDropped(int metadata, Random random, int fortune) { return Items.stick; } @Override /** * Returns the quantity of items to drop on block destruction. */ public int quantityDropped(Random random) { return 3; } @Override @SideOnly(Side.CLIENT) /** * only called by clickMiddleMouseButton, and passed to inventory.setCurrentItem (along with isCreative) */ public Item getItem(World world, int x, int y, int z) { return PFItems.campFireItem; } @Override /** * Updates the blocks bounds based on its current state. Args: world, x, y, z */ public void setBlockBoundsBasedOnState(IBlockAccess world, int x, int y, int z) { int l = world.getBlockMetadata(x, y, z) & 7; switch (l) { case 1: default: this.setBlockBounds(0.25F, 0.0F, 0.25F, 0.75F, 0.5F, 0.75F); break; } /*switch (l) { case 1: default: this.setBlockBounds(0.25F, 0.0F, 0.25F, 0.75F, 0.5F, 0.75F); break; case 2: this.setBlockBounds(0.25F, 0.25F, 0.5F, 0.75F, 0.75F, 1.0F); break; case 3: this.setBlockBounds(0.25F, 0.25F, 0.0F, 0.75F, 0.75F, 0.5F); break; case 4: this.setBlockBounds(0.5F, 0.25F, 0.25F, 1.0F, 0.75F, 0.75F); break; case 5: this.setBlockBounds(0.0F, 0.25F, 0.25F, 0.5F, 0.75F, 0.75F); }*/ } @Override /** * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been * cleared to be reused) */ public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int x, int y, int z) { this.setBlockBoundsBasedOnState(world, x, y, z); return super.getCollisionBoundingBoxFromPool(world, x, y, z); } @Override /** * Called when the block is placed in the world. */ public void onBlockPlacedBy(World world, int x, int y, int z, EntityLivingBase livingBase, ItemStack itemStack) { if(world.isRemote) return; if(livingBase instanceof EntityPlayer) { int l = MathHelper.floor_double((double)(livingBase.rotationYaw * 4.0F / 360.0F) + 2.5D) & 3; world.setBlockMetadataWithNotify(x, y, z, l, 2); } } @Override public void breakBlock(World world, int x, int y, int z, Block blocks, int par6) { super.breakBlock(world, x, y, z, blocks, par6); } @Override @SuppressWarnings("static-access") /** * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z */ public boolean canPlaceBlockAt(World world, int x, int y, int z) { return world.doesBlockHaveSolidTopSurface(world, x, y - 1, z); } /** * Spawns flame particle over the camp fire */ @Override @SideOnly(Side.CLIENT) public void randomDisplayTick(World world, int x, int y, int z, Random random) { TileEntityCampFire tile = (TileEntityCampFire)world.getTileEntity(x, y, z); for(int i = 0; i < 3; i++) { float motionY = (random.nextFloat() / 40F) + 0.025F; double particleX = ((x + 0.5F) - 0.15F) + (random.nextInt(30) / 100F); double particleY = y + 0.1F + (random.nextInt(15) / 100F); double particleZ = ((z + 0.5F) - 0.15F) + (random.nextInt(30) / 100F); PrimevalForest.proxy.spawnFlame(world, particleX, particleY, particleZ, 0.0F, motionY, 0.0F, 16); world.spawnParticle("smoke", particleX, particleY, particleZ, 0.0D, 0.05D, 0.0D); } } @Override @SuppressWarnings("static-access") /** * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are * their own) Args: x, y, z, neighbor blockID */ public void onNeighborBlockChange(World world, int x, int y, int z, Block blocks) { if (!world.isRemote) { int i1 = world.getBlockMetadata(x, y, z); int j1 = i1; boolean flag = false; if (!world.doesBlockHaveSolidTopSurface(world, x, y - 1, z)) { flag = true; } if (world.doesBlockHaveSolidTopSurface(world, x, y + 1, z)) { flag = true; } if (flag) { this.dropBlockAsItem(world, x, y, z, world.getBlockMetadata(x, y, z), 0); world.setBlockToAir(x, y, z); } else { this.func_94358_a(world, x, y, z, i1, j1, blocks); } } } protected void func_94358_a(World world, int x, int y, int z, int par5, int par6, Block blocks) {} } package minecraftplaye.primevalforest.client.render; import org.lwjgl.opengl.GL11; import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; import cpw.mods.fml.client.registry.RenderingRegistry; import minecraftplaye.primevalforest.client.model.ModelCampFire; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.RenderBlocks; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import net.minecraft.entity.Entity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ResourceLocation; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; public class RenderTileEntityCampFire extends TileEntitySpecialRenderer { private final ModelCampFire model; public static int blockRenderId = RenderingRegistry.getNextAvailableRenderId(); public RenderTileEntityCampFire() { this.model = new ModelCampFire(); } @Override public void renderTileEntityAt(TileEntity te, double x, double y, double z, float scale) { //The PushMatrix tells the renderer to "start" doing something. GL11.glPushMatrix(); //This is setting the initial location. GL11.glTranslatef((float) x + 0.5F, (float) y + 1.5F, (float) z + 0.5F); //This is the texture of your block. It's pathed to be the same place as your other blocks here. //ResourceLocation textures = (new ResourceLocation("primevalforest:textures/model/campFire.png")); //the ':' is very important //binding the textures Minecraft.getMinecraft().renderEngine.bindTexture(new ResourceLocation("primevalforest:textures/model/campFire.png")); //This rotation part is very important! Without it, your model will render upside-down! And for some reason you DO need PushMatrix again! GL11.glPushMatrix(); GL11.glRotatef(180F, 0.0F, 0.0F, 1.0F); //A reference to your Model file. Again, very important. this.model.render((Entity)null, 0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F); //Tell it to stop rendering for both the PushMatrix's GL11.glPopMatrix(); GL11.glPopMatrix(); } private void adjustRotatePivotViaMeta(World world, int x, int y, int z) { int meta = world.getBlockMetadata(x, y, z); GL11.glPushMatrix(); GL11.glRotatef(180F, 0.0F, 0.0F, 1.0F); GL11.glPopMatrix(); } //Set the lighting stuff, so it changes it's brightness properly. /*@SuppressWarnings("unused") private void adjustLightFixture(World world, int i, int j, int k, Block block) { Tessellator tess = Tessellator.instance; float brightness = block.getBlockBrightness(world, i, j, k); int skyLight = world.getLightBrightnessForSkyBlocks(i, j, k, 0); int modulousModifier = skyLight % 65536; int divModifier = skyLight / 65536; tess.setColorOpaque_F(brightness, brightness, brightness); OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float) modulousModifier, divModifier); }*/ } package minecraftplaye.primevalforest.tilentities; import java.util.Random; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.play.server.S35PacketUpdateTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.World; public class TileEntityCampFire extends TileEntity { /** The Camp Fire rotation. */ private int campFireRotation; public TileEntityCampFire() {} @Override /** * Writes a tile entity to NBT. */ public void writeToNBT(NBTTagCompound par1NBTTagCompound) { super.writeToNBT(par1NBTTagCompound); par1NBTTagCompound.setByte("Rot", (byte)(this.campFireRotation & 255)); } @Override /** * Reads a tile entity from NBT. */ public void readFromNBT(NBTTagCompound par1NBTTagCompound) { this.campFireRotation = par1NBTTagCompound.getByte("Rot"); } @Override /** * Overridden in a sign to provide the text. */ public S35PacketUpdateTileEntity getDescriptionPacket() { NBTTagCompound nbttagcompound = new NBTTagCompound(); this.writeToNBT(nbttagcompound); return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, 4, nbttagcompound); } /** * Set the skull's rotation */ public void setSkullRotation(int par1) { this.campFireRotation = par1; } @SideOnly(Side.CLIENT) public int func_82119_b() { return this.campFireRotation; } } And yes, I tested it with different Forge versions... Oh and before I forget it ... here is the crash: ---- Minecraft Crash Report ---- // Ooh. Shiny. Time: 13.06.14 23:17 Description: Exception in server tick loop java.lang.ArrayIndexOutOfBoundsException: -88 at net.minecraft.world.chunk.NibbleArray.get(NibbleArray.java:42) at net.minecraft.world.chunk.storage.ExtendedBlockStorage.getExtBlockMetadata(ExtendedBlockStorage.java:125) at net.minecraft.world.chunk.Chunk.getBlockMetadata(Chunk.java:620) at net.minecraft.world.chunk.Chunk.func_150812_a(Chunk.java:967) at net.minecraft.world.chunk.Chunk.addTileEntity(Chunk.java:951) at net.minecraft.world.chunk.storage.AnvilChunkLoader.loadEntities(AnvilChunkLoader.java:529) at net.minecraftforge.common.chunkio.ChunkIOProvider.callStage2(ChunkIOProvider.java:41) at net.minecraftforge.common.chunkio.ChunkIOProvider.callStage2(ChunkIOProvider.java:12) at net.minecraftforge.common.util.AsynchronousExecutor.skipQueue(AsynchronousExecutor.java:344) at net.minecraftforge.common.util.AsynchronousExecutor.getSkipQueue(AsynchronousExecutor.java:302) at net.minecraftforge.common.chunkio.ChunkIOExecutor.syncChunkLoad(ChunkIOExecutor.java:12) at net.minecraft.world.gen.ChunkProviderServer.loadChunk(ChunkProviderServer.java:140) at net.minecraft.world.gen.ChunkProviderServer.loadChunk(ChunkProviderServer.java:115) at net.minecraft.server.MinecraftServer.initialWorldChunkLoad(MinecraftServer.java:307) at net.minecraft.server.integrated.IntegratedServer.loadAllWorlds(IntegratedServer.java:79) at net.minecraft.server.integrated.IntegratedServer.startServer(IntegratedServer.java:96) at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:442) at net.minecraft.server.MinecraftServer$2.run(MinecraftServer.java:747) A detailed walkthrough of the error, its code path and all known details is as follows: --------------------------------------------------------------------------------------- -- System Details -- Details: Minecraft Version: 1.7.2 Operating System: Windows 8.1 (amd64) version 6.3 Java Version: 1.8.0_05, Oracle Corporation Java VM Version: Java HotSpot(TM) 64-Bit Server VM (mixed mode), Oracle Corporation Memory: 873440400 bytes (832 MB) / 1038876672 bytes (990 MB) up to 1038876672 bytes (990 MB) JVM Flags: 3 total; -Xincgc -Xmx1024M -Xms1024M AABB Pool Size: 0 (0 bytes; 0 MB) allocated, 0 (0 bytes; 0 MB) used IntCache: cache: 15, tcache: 0, allocated: 13, tallocated: 95 FML: MCP v9.03 FML v7.2.211.1124 Minecraft Forge 10.12.2.1124 4 mods loaded, 4 mods active mcp{9.03} [Minecraft Coder Pack] (minecraft.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available FML{7.2.211.1124} [Forge Mod Loader] (forgeSrc-1.7.2-10.12.2.1124.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available Forge{10.12.2.1124} [Minecraft Forge] (forgeSrc-1.7.2-10.12.2.1124.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available primevalforest{Dev Build 1 - Beta 0.0.9} [Primeval Forest] (bin) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available Profiler Position: N/A (disabled) Vec3 Pool Size: 0 (0 bytes; 0 MB) allocated, 0 (0 bytes; 0 MB) used Player Count: 0 / 8; [] Type: Integrated Server (map_client.txt) Is Modded: Definitely; Client brand changed to 'fml,forge' Bektor Quote Developer of Primeval Forest. Link to comment Share on other sites More sharing options...
TheGreyGhost Posted June 14, 2014 Share Posted June 14, 2014 Hi The problem is related to your TileEntity setup code. FYI I traced it back like this: NibbleArray:: /** * Returns the nibble of data corresponding to the passed in x, y, z. y is at most 6 bits, z is at most 4. */ public int get(int par1, int par2, int par3) { int l = par2 << this.depthBitsPlusFour | par3 << this.depthBits | par1; int i1 = l >> 1; int j1 = l & 1; return j1 == 0 ? this.data[i1] & 15 : this.data[i1] >> 4 & 15; // From Error log: error is here, i1 is -88 } So int par1, par2, and par3 are out of the expected range, and from the index it looks one or more is probably negative when they're expected to be positive Tracing this back up through the list of callers brings us eventually to public void addTileEntity(TileEntity p_150813_1_) { int i = p_150813_1_.xCoord - this.xPosition * 16; int j = p_150813_1_.yCoord; int k = p_150813_1_.zCoord - this.zPosition * 16; this.func_150812_a(i, j, k, p_150813_1_); // i, j, and/or k are out of expected range, probably smaller than the chunk [x,y,z] position //[..] } So it looks to me like your TileEntity x coordinate and/or z coordinate is wrong for the chunk that it's being added to; the vanilla assumes that the TileEntity [x,y,z] will be within the 16x256x16 block cube for that chunk. A search through the code shows that xCoord is normally set in only two places: Chunk.setChunkBlockTileEntity() and TileEntity.readFromNBT() Your TileEntity had an override of readFromNBT, so what should that look like for a vanilla TileEntity such as TileEntityChest? TileEntityChest:: /** * Reads a tile entity from NBT. */ public void readFromNBT(NBTTagCompound par1NBTTagCompound) { super.readFromNBT(par1NBTTagCompound); NBTTagList nbttaglist = par1NBTTagCompound.getTagList("Items"); --> I think this is the problem - compare with yours -TGG Quote Link to comment Share on other sites More sharing options...
Bektor Posted June 14, 2014 Author Share Posted June 14, 2014 Ok, now it works. But one question, how could I render a block model inside of the inventory, that the block icon looks exact the same as the block is placed? Quote Developer of Primeval Forest. Link to comment Share on other sites More sharing options...
Kwibble Posted June 14, 2014 Share Posted June 14, 2014 Well... I am wondering the same thing. I have made a small fix for this problem by creating an item that places the wanted block via the onItemUse() method. Then, from there, create an IItemRenderer (I think its called) and register it. Then for the actual rendering you use your tile entity renderer and position 0,0,0. But I would like to know the better way of doing it... Quote We all stuff up sometimes... But I seem to be at the bottom of that pot. Link to comment Share on other sites More sharing options...
TheGreyGhost Posted June 14, 2014 Share Posted June 14, 2014 Hi ISimpleBlockRenderingHandler will do the trick. IItemRenderer is also a possibility. This link might be useful to help you understand the background information - see the ItemRendering sections http://greyminecraftcoder.blogspot.com.au/p/list-of-topics.html -TGG Quote Link to comment Share on other sites More sharing options...
Kwibble Posted June 14, 2014 Share Posted June 14, 2014 @TGG How does ISimpleBlockRenderingHandler take care of rendering a block in the inventory? Can you give an example? Quote We all stuff up sometimes... But I seem to be at the bottom of that pot. Link to comment Share on other sites More sharing options...
TheGreyGhost Posted June 14, 2014 Share Posted June 14, 2014 Hi Some more info here http://greyminecraftcoder.blogspot.com.au/2013/07/block-rendering.html and here http://greyminecraftcoder.blogspot.com.au/2013/08/rendering-inventory-items.html -TGG Quote Link to comment Share on other sites More sharing options...
Bektor Posted June 14, 2014 Author Share Posted June 14, 2014 Thanks. Quote Developer of Primeval Forest. Link to comment Share on other sites More sharing options...
Recommended Posts
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.