Jump to content

[1.11][SOLVED-ish] Tile Entity breaks after placing 64 blocks in a single chunk


Recommended Posts

Posted

I am creating a conveyor belt block which uses a tile entity to hold the current item on a specific conveyor at any given time. I render the sides of the conveyor using json, but then render the belt and the item on the belt using a TESR.

 

Everything works fine until I place 64 conveyors in a single chunk. Upon placing the 64th, the TESR breaks, the tile entity stops ticking, and the number of chunk updates skyrockets (from around 0-1 to 160-170).

 

Conveyors in other chunks continue to operate perfectly fine (unless I reach 64+ in that chunk, in which case the same thing happens within that chunk).

 

I haven't been able to determine what limit I'm hitting that causes this to happen. It happening only within a single chunk suggests to me that it maybe has something to do with marking the chunk as dirty, or putting too much info in the update packet. I'm not sure.

 

Edit: I've added a gif showing the issue:

[spoiler=Example]CEPIZ3d.gif

 

 

My mod is open source at https://github.com/Drakmyth/Manufactory. Relevant files are included below.

 

[spoiler=BlockConveyor.java]

public class BlockConveyor extends Block implements ITileEntityProvider {

private static final AxisAlignedBB AABB = new AxisAlignedBB(0.0f, 0.0f, 0.0f, 1.0f, 0.5f, 1.0f);

/**
 * BlockState Properties
 */
private static final PropertyDirection FACING = PropertyDirection.create("facing", EnumFacing.Plane.HORIZONTAL);

/**
 * Actual State Properties
 */
private static final PropertyBool EAST_WALL = PropertyBool.create("east_wall");
private static final PropertyBool WEST_WALL = PropertyBool.create("west_wall");

private final Item _itemBlock;

public BlockConveyor() {

	super(Material.ROCK, MapColor.BLACK);
	this.setRegistryName(Constants.BlockNames.CONVEYOR_BELT);
	this.setUnlocalizedName(Constants.MODID + "." + Constants.BlockNames.CONVEYOR_BELT);
	this.setCreativeTab(CreativeTabs.MISC);

	this.setDefaultState(this.getBlockState().getBaseState()
	                         .withProperty(FACING, EnumFacing.NORTH)
	                         .withProperty(EAST_WALL, true)
	                         .withProperty(WEST_WALL, true));

	_itemBlock = new ItemBlock(this).setRegistryName(this.getRegistryName());
}

public Item getItemBlock() {

	return _itemBlock;
}

@Override
@Nonnull
public AxisAlignedBB getBoundingBox(final IBlockState state, final IBlockAccess source, final BlockPos pos) {

	return AABB;
}

/**
 * Returns a new instance of a block's tile entity class. Called on placing the block.
 */
@Override
public TileEntity createNewTileEntity(@Nonnull final World world, final int meta) {

	return new TileEntityConveyor(getStateFromMeta(meta).getValue(FACING));
}

/**
 * Called when the block is right clicked by a player.
 */
@Override
public boolean onBlockActivated(final World world, final BlockPos position, final IBlockState blockState, final EntityPlayer player, final EnumHand hand, EnumFacing facing, final float hitX, final float hitY, final float hitZ) {

	if (world.isRemote) {
		return true;
	}

	final TileEntity entity = world.getTileEntity(position);
	if (!(entity instanceof TileEntityConveyor)) {
		return true;
	}

	final TileEntityConveyor tileEntity = (TileEntityConveyor)entity;
	final ItemStack itemOnConveyor = tileEntity.getItemOnConveyor();
	if (player.inventory.addItemStackToInventory(itemOnConveyor)) {
		player.inventoryContainer.detectAndSendChanges();
		tileEntity.clearItem();
	}

	return true;
}

/**
 * Used to determine ambient occlusion and culling when rebuilding chunks for render
 */
@Override
public boolean isOpaqueCube(IBlockState state) {

	return false;
}

@Override
public boolean isFullCube(IBlockState state) {

	return false;
}

/**
 * The type of render function called. MODEL for mixed tesr and static model, MODELBLOCK_ANIMATED for TESR-only,
 * LIQUID for vanilla liquids, INVISIBLE to skip all rendering
 */
@Override
@Nonnull
public EnumBlockRenderType getRenderType(IBlockState state) {

	return EnumBlockRenderType.MODEL;
}

/**
 * Called by ItemBlocks just before a block is actually set in the world, to allow for adjustments to the
 * IBlockstate
 */
@Override
@Nonnull
public IBlockState getStateForPlacement(final World world, final BlockPos position, final EnumFacing blockSideClicked, final float hitX, final float hitY, final float hitZ, final int meta, final EntityLivingBase placer) {

	EnumFacing placerFacing = placer.getHorizontalFacing();

	if (placerFacing.equals(blockSideClicked.getOpposite())) {
		IBlockState targetState = world.getBlockState(position.offset(placerFacing));
		boolean isConveyor = targetState.getBlock() instanceof BlockConveyor;
		if (isConveyor) {
			EnumFacing targetStateFacing = targetState.getValue(FACING);
			if (placerFacing.equals(targetStateFacing.getOpposite())) {
				placerFacing = targetStateFacing;
			}
		}
	}

	return this.getDefaultState().withProperty(FACING, placerFacing);
}

@Override
@Nonnull
protected BlockStateContainer createBlockState() {

	return new BlockStateContainer(this, FACING, EAST_WALL, WEST_WALL);
}

/**
 * Convert the given metadata into a BlockState for this Block
 */
@Override
@Nonnull
public IBlockState getStateFromMeta(final int meta) {

	final EnumFacing facing = EnumFacing.getHorizontal(meta);
	return this.getDefaultState().withProperty(FACING, facing);
}

/**
 * Convert the BlockState into the correct metadata value
 */
@Override
public int getMetaFromState(final IBlockState state) {

	final EnumFacing facing = state.getValue(FACING);
	return facing.getHorizontalIndex();
}

/**
 * Get the actual Block state of this Block at the given position. This applies properties not visible in the
 * metadata, such as fence connections.
 */
@Override
@Nonnull
public IBlockState getActualState(@Nonnull final IBlockState state, final IBlockAccess world, final BlockPos position) {

	final EnumFacing facing = state.getValue(FACING);

	boolean eastWall = !isFacingTargetLocation(world, position.offset(facing.rotateY()), position);
	boolean westWall = !isFacingTargetLocation(world, position.offset(facing.rotateYCCW()), position);

	return state.withProperty(EAST_WALL, eastWall)
	            .withProperty(WEST_WALL, westWall);
}

private boolean isFacingTargetLocation(final IBlockAccess world, final BlockPos position, final BlockPos target) {

	IBlockState state = world.getBlockState(position);

	boolean isConveyor = state.getBlock() instanceof BlockConveyor;
	return isConveyor && position.offset(state.getValue(FACING)).equals(target);
}

/**
 * Called serverside after this block is replaced with another in Chunk, but before the Tile Entity is updated
 */
@Override
public void breakBlock(@Nonnull final World world, @Nonnull final BlockPos position, @Nonnull final IBlockState state) {

	final TileEntity entity = world.getTileEntity(position);
	if (!(entity instanceof TileEntityConveyor)) {
		return;
	}

	final TileEntityConveyor tileEntity = (TileEntityConveyor)entity;
	final ItemStack itemOnConveyor = tileEntity.getItemOnConveyor();

	if (!itemOnConveyor.isEmpty()) {
		final EntityItem item = new EntityItem(world, position.getX() + 0.5, position.getY() + 0.5, position.getZ() + 0.5, itemOnConveyor);

		final float multiplier = 0.1f;
		final float motionX = world.rand.nextFloat() - 0.5f;
		final float motionY = world.rand.nextFloat() - 0.5f;
		final float motionZ = world.rand.nextFloat() - 0.5f;

		item.motionX = motionX * multiplier;
		item.motionY = motionY * multiplier;
		item.motionZ = motionZ * multiplier;

		world.spawnEntity(item);
	}

	super.breakBlock(world, position, state);
}
}

 

 

[spoiler=TileEntityConveyor.java]

public class TileEntityConveyor extends TileEntity implements ITickable, IConveyorReceiver {

private static final String NBT_ITEM_ON_CONVEYOR = "itemOnConveyor";
private static final String NBT_IS_HEAD = "isHead";
private static final String NBT_BELT_OFFSET = "beltOffset";
private static final String NBT_ITEM_OFFSET = "itemOffset";
private static final String NBT_ITEM_RELEASE_OFFSET = "itemReleaseOffset";
private static final String NBT_FACING = "facing";
private static final String NBT_LAST_ITEM_SOURCE_FACING = "lastItemSourceFacing";
private static final int MAX_BELT_OFFSET = 16; // 16/x = number of pixels to rotate per tick
private static final int MAX_ITEM_HOLD_DURATION = MAX_BELT_OFFSET;

private boolean _isHead;
private ItemStack _itemOnConveyor;
private EnumFacing _facing;
private int _beltOffset;
private int _itemOffset;
private int _itemReleaseOffset;
private boolean _justReceivedItem;
private Vec3i _lastItemSourceFacing;

@SuppressWarnings("unused")
public TileEntityConveyor() {

	this(EnumFacing.NORTH);
}

public TileEntityConveyor(final EnumFacing facing) {

	_isHead = true;
	_itemOnConveyor = ItemStack.EMPTY;
	_facing = facing;
	_beltOffset = 0;
	_itemOffset = 0;
	_itemReleaseOffset = 0;
	_justReceivedItem = false;
	_lastItemSourceFacing = facing.getDirectionVec();
}

@Override
public SPacketUpdateTileEntity getUpdatePacket() {

	final NBTTagCompound compound = new NBTTagCompound();
	writeToNBT(compound);
	return new SPacketUpdateTileEntity(pos, getBlockMetadata(), compound);
}

@Override
public void onDataPacket(final NetworkManager networkManager, final SPacketUpdateTileEntity packet) {

	readFromNBT(packet.getNbtCompound());
}

@Override
@Nonnull
public NBTTagCompound writeToNBT(final NBTTagCompound compound) {

	super.writeToNBT(compound);

	final NBTTagCompound itemOnConveyorNBT = new NBTTagCompound();
	_itemOnConveyor.writeToNBT(itemOnConveyorNBT);
	compound.setTag(NBT_ITEM_ON_CONVEYOR, itemOnConveyorNBT);

	compound.setBoolean(NBT_IS_HEAD, _isHead);
	compound.setInteger(NBT_BELT_OFFSET, _beltOffset);
	compound.setInteger(NBT_ITEM_OFFSET, _itemOffset);
	compound.setInteger(NBT_ITEM_RELEASE_OFFSET, _itemReleaseOffset);
	compound.setInteger(NBT_FACING, _facing.getHorizontalIndex());
	compound.setIntArray(NBT_LAST_ITEM_SOURCE_FACING, new int[] { _lastItemSourceFacing.getX(), _lastItemSourceFacing.getY(), _lastItemSourceFacing.getZ() });

	return compound;
}

@Override
public void readFromNBT(final NBTTagCompound compound) {

	super.readFromNBT(compound);

	_itemOnConveyor = ItemStack.EMPTY;
	if (compound.hasKey(NBT_ITEM_ON_CONVEYOR)) {
		final NBTTagCompound itemOnConveyorNBT = compound.getCompoundTag(NBT_ITEM_ON_CONVEYOR);
		_itemOnConveyor = new ItemStack(itemOnConveyorNBT);
	}

	_isHead = true;
	if (compound.hasKey(NBT_IS_HEAD)) {
		_isHead = compound.getBoolean(NBT_IS_HEAD);
	}

	_beltOffset = 0;
	if (compound.hasKey(NBT_BELT_OFFSET)) {
		_beltOffset = compound.getInteger(NBT_BELT_OFFSET);
	}

	_itemOffset = 0;
	if (compound.hasKey(NBT_ITEM_OFFSET)) {
		_itemOffset = compound.getInteger(NBT_ITEM_OFFSET);
	}

	_itemReleaseOffset = 0;
	if (compound.hasKey(NBT_ITEM_RELEASE_OFFSET)) {
		_itemReleaseOffset = compound.getInteger(NBT_ITEM_RELEASE_OFFSET);
	}

	_facing = EnumFacing.NORTH;
	if (compound.hasKey(NBT_FACING)) {
		_facing = EnumFacing.getHorizontal(compound.getInteger(NBT_FACING));
	}

	// TODO: Should be able to sync this to the client without using NBT
	_lastItemSourceFacing = _facing.getDirectionVec();
	if (compound.hasKey(NBT_LAST_ITEM_SOURCE_FACING)) {
		final int[] facingVals = compound.getIntArray(NBT_LAST_ITEM_SOURCE_FACING);
		_lastItemSourceFacing = new Vec3i(facingVals[0], facingVals[1], facingVals[2]);
	}

	_justReceivedItem = false;
}

@Override
public void update() {

	if (!hasWorld() || getWorld().isRemote) {
		return;
	}

	// TODO: this check only needs to happen onNeighborBlockChanged, not every tick
	_isHead = amIHead();

	if (_isHead) {
		updateConveyorHead();
	}
}

private boolean amIHead() {

	final TileEntity destination = getWorld().getTileEntity(pos.offset(_facing));
	if (destination == null || !(destination instanceof TileEntityConveyor)) {
		return true;
	}

	final TileEntityConveyor tileEntity = (TileEntityConveyor)destination;
	return tileEntity.getFacing() != _facing;
}

private void updateConveyorHead() {

	if (!_justReceivedItem && canGiveItemToDestination()) {
		final TileEntity destination = getWorld().getTileEntity(pos.offset(_facing));
		if (destination instanceof IConveyorReceiver) {
			if (!giveItemToDestination()) {
				return;
			}
		} else {
			ejectItem();
		}
	}
	_justReceivedItem = false;

	updateConveyorChild((_beltOffset + 1) % MAX_BELT_OFFSET, (_itemOffset + 1) % MAX_ITEM_HOLD_DURATION);

	final Queue<TileEntityConveyor> children = getChildren();
	children.forEach(conveyor -> conveyor.updateConveyorChild(_beltOffset, _itemOffset));
}

private Queue<TileEntityConveyor> getChildren() {

	final Queue<TileEntityConveyor> children = new ArrayDeque<>();
	final World world = getWorld();
	final EnumFacing backFacing = _facing.getOpposite();
	BlockPos nextPos = pos.offset(backFacing);
	while (true) {
		final TileEntity tileEntity = world.getTileEntity(nextPos);
		if (tileEntity == null || !(tileEntity instanceof TileEntityConveyor)) {
			break;
		}

		final TileEntityConveyor child = (TileEntityConveyor)tileEntity;
		if (child.getFacing() != _facing) {
			break;
		}

		children.add(child);
		nextPos = nextPos.offset(backFacing);
	}

	return children;
}

private void updateConveyorChild(final int currentBeltOffset, final int currentItemOffset) {

	if (_beltOffset == currentBeltOffset) {
		return;
	}

	_beltOffset = currentBeltOffset;
	_itemOffset = currentItemOffset;

	if (canGiveItemToDestination()) {
		giveItemToDestination();
	}

	if (canGrabItemFromAbove()) {
		grabItemFromAbove();
	}

	markDirty();
	World world = getWorld();
	IBlockState blockState = world.getBlockState(pos);
	world.notifyBlockUpdate(pos, blockState, blockState, 0);
}

private boolean canGiveItemToDestination() {

	return !_itemOnConveyor.isEmpty() && _itemOffset == _itemReleaseOffset;
}

private boolean giveItemToDestination() {

	boolean gaveItemToDestination = false;

	final TileEntity potentialDestination = getWorld().getTileEntity(pos.offset(_facing));
	if (potentialDestination instanceof IConveyorReceiver) {
		final IConveyorReceiver destination = (IConveyorReceiver)potentialDestination;
		gaveItemToDestination = destination.onReceiveItem(_itemOnConveyor, pos);
	}

	if (gaveItemToDestination) {
		_itemOnConveyor = ItemStack.EMPTY;
	}

	return gaveItemToDestination;
}

// TODO: Can this be replaced with a simple onReceiveItem call?
private boolean canGrabItemFromAbove() {

	if (!_itemOnConveyor.isEmpty()) {
		return false;
	}

	final boolean okInFront;
	if (_isHead) {
		okInFront = true;
	} else {
		final TileEntity tileEntity = getWorld().getTileEntity(pos.offset(_facing));
		if (tileEntity instanceof TileEntityConveyor) {
			final TileEntityConveyor conveyor = (TileEntityConveyor)tileEntity;
			final int timeBeforeItemRelease = conveyor.getTimeBeforeItemRelease();
			okInFront = timeBeforeItemRelease < MAX_ITEM_HOLD_DURATION / 2 || timeBeforeItemRelease == Integer.MAX_VALUE;
		} else {
			okInFront = true;
		}
	}

	final boolean okBehind;
	final TileEntity tileEntity = getWorld().getTileEntity(pos.offset(_facing.getOpposite()));
	if (tileEntity instanceof TileEntityConveyor) {
		final TileEntityConveyor conveyor = (TileEntityConveyor)tileEntity;
		okBehind = conveyor.getFacing() != _facing || conveyor.getTimeBeforeItemRelease() > MAX_ITEM_HOLD_DURATION / 2;
	} else {
		okBehind = true;
	}

	return okInFront && okBehind;
}

private void grabItemFromAbove() {

	final AxisAlignedBB aabb = new AxisAlignedBB(pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1.0D, pos.getY() + 1.0D, pos.getZ() + 1.0D);
	final List<Entity> entitiesAboveConveyor = getWorld().getEntitiesWithinAABB(EntityItem.class, aabb);

	for (final Entity entity : entitiesAboveConveyor) {
		final EntityItem item = (EntityItem)entity;
		if (!item.isAirBorne) {
			// TODO: This should probably call onReceiveItem to check for rejection instead of setting _itemOnConveyor directly
			_itemOnConveyor = item.getEntityItem().splitStack(1);
			if (item.getEntityItem().getCount() < 1) {
				item.isDead = true;
			}
			_itemReleaseOffset = calculateItemReleaseOffset(MAX_ITEM_HOLD_DURATION / 2);
			break;
		}
	}
}

public void clearItem() {

	_itemOnConveyor = ItemStack.EMPTY;
	markDirty();
	IBlockState state = getWorld().getBlockState(pos);
	getWorld().notifyBlockUpdate(pos, state, state, 0);
}

public EnumFacing getFacing() {

	return _facing;
}

private int getTimeBeforeItemRelease() {

	if (_itemOnConveyor.isEmpty()) {
		return Integer.MAX_VALUE;
	}

	if (_itemOffset < _itemReleaseOffset) {
		return _itemReleaseOffset - _itemOffset;
	}

	return (_itemReleaseOffset + MAX_ITEM_HOLD_DURATION) - _itemOffset;
}

public float getBeltTextureOffset() {

	return _beltOffset / (float)MAX_BELT_OFFSET;
}

public float getItemOffset() {

	return 1.0f - (getTimeBeforeItemRelease() / (float)MAX_ITEM_HOLD_DURATION);
}

private void ejectItem() {

	final Vec3i facing = _facing.getDirectionVec();
	final double spawnX = pos.getX() + 0.5 + (facing.getX() * 0.7);
	final double spawnY = pos.getY() + (5.0 / 16);
	final double spawnZ = pos.getZ() + 0.5 + (facing.getZ() * 0.7);
	final EntityItem item = new EntityItem(getWorld(), spawnX, spawnY, spawnZ, _itemOnConveyor);
	final double velocity = 0.1;
	item.motionX = facing.getX() * velocity;
	item.motionY = facing.getY() * velocity;
	item.motionZ = facing.getZ() * velocity;
	getWorld().spawnEntity(item);
	_itemOnConveyor = ItemStack.EMPTY;
}

public ItemStack getItemOnConveyor() {

	return _itemOnConveyor;
}

@Override
public boolean onReceiveItem(final ItemStack itemStack, final BlockPos sourceDir) {

	boolean reject = false;

	final BlockPos behindMe = pos.offset(_facing.getOpposite());

	if (!_itemOnConveyor.isEmpty() || sourceDir.equals(pos.offset(_facing))) {
		reject = true;
	} else if (!sourceDir.equals(behindMe)) {
		final TileEntity tileEntity = getWorld().getTileEntity(behindMe);
		if (tileEntity instanceof TileEntityConveyor) {
			final TileEntityConveyor conveyor = (TileEntityConveyor)tileEntity;
			reject = conveyor.getFacing() == _facing && conveyor.getTimeBeforeItemRelease() < MAX_ITEM_HOLD_DURATION;
		}
	}

	if (!reject) {
		_itemOnConveyor = itemStack;
		_itemReleaseOffset = calculateItemReleaseOffset(MAX_ITEM_HOLD_DURATION);
		if (_isHead) {
			_justReceivedItem = true;
		}
		_lastItemSourceFacing = pos.subtract(sourceDir);
		markDirty();
		IBlockState state = getWorld().getBlockState(pos);
		getWorld().notifyBlockUpdate(pos, state, state, 0);
	}

	return !reject;
}

public Vec3i getLastItemSourceFacingVector() {

	return _lastItemSourceFacing;
}

private int calculateItemReleaseOffset(final int duration) {

	return (_itemOffset + duration) % MAX_ITEM_HOLD_DURATION;
}
}

 

 

[spoiler=TileEntityConveyorRenderer.java]

public class TileEntityConveyorRenderer extends TileEntitySpecialRenderer<TileEntityConveyor> {

private static final ResourceLocation beltTexture = new ResourceLocation("manufactory:textures/blocks/conveyor_belt.png");

private final RenderEntityItem _itemRender;

public TileEntityConveyorRenderer() {

	_itemRender = new RenderEntityItem(Minecraft.getMinecraft().getRenderManager(), Minecraft.getMinecraft().getRenderItem()) {

		@Override
		public boolean shouldBob() {

			return false;
		}
	};
}

@Override
public void renderTileEntityAt(final TileEntityConveyor tileEntity, final double x, final double y, final double z, final float partialTicks, final int destroyStage) {

	final ItemStack itemOnConveyor = tileEntity.getItemOnConveyor();

	GlStateManager.pushMatrix();
	GlStateManager.translate(x, y, z);
	drawConveyorBelt(tileEntity);
	if (itemOnConveyor != null) {
		drawItemOnConveyor(tileEntity, itemOnConveyor);
	}
	GlStateManager.popMatrix();
}

private void drawItemOnConveyor(final TileEntityConveyor tileEntity, final ItemStack itemOnConveyor) {

	GlStateManager.pushMatrix();
	final EntityItem customItem = new EntityItem(tileEntity.getWorld());
	customItem.hoverStart = 0.0f;
	customItem.setEntityItemStack(itemOnConveyor);

	final Vec3i sourceDir = tileEntity.getLastItemSourceFacingVector();
	final Vec3i facing = tileEntity.getFacing().getDirectionVec();
	final float progressOffset = tileEntity.getItemOffset() - 0.5f;

	GlStateManager.translate(0.5f, 0.2f, 0.5f);
	piecewiseTranslateOnSourceDir(sourceDir, facing, progressOffset);
	_itemRender.doRender(customItem, 0, 0, 0, 0, 0);
	GlStateManager.scale(0.7f, 0.7f, 0.7f);
	GlStateManager.popMatrix();
}

private void piecewiseTranslateOnSourceDir(final Vec3i sourceDir, final Vec3i facing, final float progressOffset) {

	final Vec3i dirToUse = progressOffset >= 0 ? facing : sourceDir;
	GlStateManager.translate(dirToUse.getX() * progressOffset, 0, dirToUse.getZ() * progressOffset);
}

private void drawConveyorBelt(final TileEntityConveyor tileEntity) {

	final Tessellator tessellator = Tessellator.getInstance();
	final VertexBuffer worldRenderer = tessellator.getBuffer();

	final float beltOffset = tileEntity.getBeltTextureOffset();

	this.bindTexture(beltTexture);

	GlStateManager.pushMatrix();
	GlStateManager.disableLighting();
	GlStateManager.disableBlend();
	GlStateManager.enableDepth();

	GlStateManager.translate(0.5f, 0.0f, 0.5f);
	worldRenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
	addBeltVertices(worldRenderer, beltOffset);

	final float angle;
	switch (tileEntity.getFacing()) {
		case WEST:
			angle = 90;
			break;
		case SOUTH:
			angle = 180;
			break;
		case EAST:
			angle = 270;
			break;
		default:
			angle = 0;
			break;
	}

	GlStateManager.rotate(angle, 0, 1, 0);

	tessellator.draw();
	GlStateManager.popMatrix();
}

private void addBeltVertices(final VertexBuffer worldrenderer, final float beltOffset) {

	final double[][] vertexTable = { { -7.0 / 16, 5.005 / 16, -8.0 / 16, 0.0, 0.0 + beltOffset },          //1
	                                 { -7.0 / 16, 5.005 / 16, 8.0 / 16, 0.0, 1.0 + beltOffset },
	                                 { 7.0 / 16, 5.005 / 16, 8.0 / 16, 1.0, 1.0 + beltOffset },
	                                 { 7.0 / 16, 5.005 / 16, -8.0 / 16, 1.0, 0.0 + beltOffset },
	                                 { -7.0 / 16, 5.0 / 16, 8.005 / 16, 0.0, 0.0 + beltOffset },          //2
	                                 { -7.0 / 16, 0.0 / 16, 8.005 / 16, 0.0, (5.0 / 16) + beltOffset },
	                                 { 7.0 / 16, 0.0 / 16, 8.005 / 16, 1.0, (5.0 / 16) + beltOffset },
	                                 { 7.0 / 16, 5.0 / 16, 8.005 / 16, 1.0, 0.0 + beltOffset },
	                                 { -7.0 / 16, 5.0 / 16, -8.005 / 16, 0.0, (4.0 / 16) + beltOffset },          //3
	                                 { 7.0 / 16, 5.0 / 16, -8.005 / 16, 1.0, (4.0 / 16) + beltOffset },
	                                 { 7.0 / 16, 0.0 / 16, -8.005 / 16, 1.0, (-1.0 / 16) + beltOffset },
	                                 { -7.0 / 16, 0.0 / 16, -8.005 / 16, 0.0, (-1.0 / 16) + beltOffset } };

	for (final double[] vertex : vertexTable) {
		worldrenderer.pos(vertex[0], vertex[1], vertex[2]).tex(vertex[3], vertex[4]).endVertex();
	}
}
}

 

 

Note: This code was originally written in 1.8 and was recently ported to 1.11. I mention this because this is my first mod, and so if there are new ways of doing things or things are not done in a correct way, it is because I am still learning. (Most notably I believe my IConveyorReceiver should likely be replaced by a Capability, but I haven't learned that yet). Any critiques or suggestions to any part of the codebase beyond just the problem I'm asking about would be greatly appreciated as well. This is my first minecraft mod, but I am a software engineer by trade and am very familiar with Java.

  • 3 weeks later...

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.

×
×
  • Create New...

Important Information

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