Jump to content

[1.7.2] [Solved] Particle crash by custom block renderer


Bektor

Recommended Posts

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

Developer of Primeval Forest.

Link to comment
Share on other sites

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

 

Link to comment
Share on other sites

Well... :P 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...

We all stuff up sometimes... But I seem to be at the bottom of that pot.

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.