package openblocks.common.tileentity; import java.util.List; import java.util.Random; import net.minecraft.block.Block; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.IIcon; import net.minecraftforge.common.util.ForgeDirection; import openblocks.OpenBlocks; import openblocks.common.Stencil; import openblocks.common.block.BlockCanvas; import openblocks.common.item.ItemPaintBrush; import openblocks.common.item.ItemSqueegee; import openblocks.common.item.ItemStencil; import openblocks.common.sync.SyncableBlockLayers; import openblocks.common.sync.SyncableBlockLayers.Layer; import openmods.api.IActivateAwareTile; import openmods.api.ICustomBreakDrops; import openmods.api.ICustomHarvestDrops; import openmods.sync.SyncableBlock; import openmods.sync.SyncableInt; import openmods.sync.SyncableIntArray; import openmods.tileentity.SyncedTileEntity; import openmods.utils.BlockNotifyFlags; import openmods.utils.BlockUtils; public class TileEntityCanvas extends SyncedTileEntity implements IActivateAwareTile, ICustomBreakDrops, ICustomHarvestDrops { public static final int[] ALL_SIDES = { 0, 1, 2, 3, 4, 5 }; /* Used for painting other blocks */ private SyncableBlock paintedBlock; private SyncableInt paintedBlockMeta; private SyncableIntArray baseColors; private SyncableBlockLayers stencilsUp; private SyncableBlockLayers stencilsDown; private SyncableBlockLayers stencilsEast; private SyncableBlockLayers stencilsWest; private SyncableBlockLayers stencilsNorth; private SyncableBlockLayers stencilsSouth; private SyncableBlockLayers[] allSides; public TileEntityCanvas() { syncMap.addUpdateListener(createRenderUpdateListener()); } public SyncableIntArray getBaseColors() { return baseColors; } @Override protected void createSyncedFields() { stencilsUp = new SyncableBlockLayers(); stencilsDown = new SyncableBlockLayers(); stencilsEast = new SyncableBlockLayers(); stencilsWest = new SyncableBlockLayers(); stencilsNorth = new SyncableBlockLayers(); stencilsSouth = new SyncableBlockLayers(); allSides = new SyncableBlockLayers[] { stencilsDown, stencilsUp, stencilsNorth, stencilsSouth, stencilsWest, stencilsEast }; baseColors = new SyncableIntArray(new int[] { 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF }); paintedBlock = new SyncableBlock(); paintedBlockMeta = new SyncableInt(0); } public SyncableBlockLayers getLayersForSide(int side) { return allSides[side]; } public Layer getLayerForSide(int renderSide, int layerId) { final SyncableBlockLayers layers = getLayersForSide(renderSide); return layers != null? layers.getLayer(layerId) : null; } public int getColorForRender(int renderSide, int layerId) { if (layerId == BlockCanvas.BASE_LAYER) return baseColors.getValue(renderSide); final Layer layer = getLayerForSide(renderSide, layerId); return layer != null? layer.getColorForRender() : 0xCCCCCC; } public IIcon getTextureForRender(int renderSide, int layerId) { if (layerId > BlockCanvas.BASE_LAYER) { Layer layer = getLayerForSide(renderSide, layerId); if (layer != null) { Stencil stencil = layer.getStencil(); if (stencil != null) { return layer.hasStencilCover()? stencil.getCoverBlockIcon() : stencil.getBlockIcon(); } } } return getBaseTexture(renderSide); } private IIcon getBaseTexture(int side) { Block block = paintedBlock.getValue(); if (block == Blocks.air) return OpenBlocks.Blocks.canvas.baseIcon; return block.getIcon(side, paintedBlockMeta.get()); } @Override public boolean canUpdate() { return false; } private boolean isBlockUnpainted() { for (int i = 0; i < allSides.length; i++) { if (!allSides[i].isEmpty() || baseColors.getValue(i) != 0xFFFFFF) return false; } return true; } public boolean applyPaint(int color, ForgeDirection... sides) { boolean hasChanged = false; for (ForgeDirection side : sides) { final int sideId = side.ordinal(); SyncableBlockLayers layers = getLayersForSide(sideId); if (layers.isLastLayerStencil()) { layers.setLastLayerColor(color); layers.moveStencilToNextLayer(); } else { // collapse all layers, since they will be fully covered by paint layers.clear(); baseColors.setValue(sideId, color); } hasChanged |= layers.isDirty(); } hasChanged |= baseColors.isDirty(); if (!worldObj.isRemote) sync(); return hasChanged; } private void dropStackFromSide(ItemStack stack, int side) { if (worldObj.isRemote) return; ForgeDirection dropSide = ForgeDirection.getOrientation(side); double dropX = xCoord + dropSide.offsetX; double dropY = yCoord + dropSide.offsetY; double dropZ = zCoord + dropSide.offsetZ; BlockUtils.dropItemStackInWorld(worldObj, dropX, dropY, dropZ, stack); } public void removePaint(int... sides) { for (int side : sides) { SyncableBlockLayers layer = getLayersForSide(side); // If there is a stencil on top, pop it off. if (layer.isLastLayerStencil()) { Stencil stencil = layer.getTopStencil(); ItemStack dropStack = new ItemStack(OpenBlocks.Items.stencil, 1, stencil.ordinal()); dropStackFromSide(dropStack, side); } layer.clear(); baseColors.setValue(side, 0xFFFFFF); } if (isBlockUnpainted() && paintedBlock.containsValidBlock()) { Block block = paintedBlock.getValue(); worldObj.setBlock(xCoord, yCoord, zCoord, block, paintedBlockMeta.get(), BlockNotifyFlags.SEND_TO_CLIENTS); } if (!worldObj.isRemote) sync(); } public boolean useStencil(int side, Stencil stencil) { SyncableBlockLayers layer = getLayersForSide(side); if (layer.isLastLayerStencil()) { Stencil topStencil = layer.getTopStencil(); if (topStencil == stencil) return false; ItemStack dropStack = new ItemStack(OpenBlocks.Items.stencil, 1, topStencil.ordinal()); dropStackFromSide(dropStack, side); layer.setLastLayerStencil(stencil); } else layer.pushNewStencil(stencil); if (!worldObj.isRemote) sync(); return true; } @Override public boolean onBlockActivated(EntityPlayer player, int side, float hitX, float hitY, float hitZ) { ItemStack held = player.getHeldItem(); if (held != null) { Item heldItem = held.getItem(); if (heldItem instanceof ItemSqueegee || heldItem instanceof ItemPaintBrush || heldItem instanceof ItemStencil) return false; } SyncableBlockLayers layer = getLayersForSide(side); if (layer.isLastLayerStencil()) { if (player.isSneaking()) { if (!worldObj.isRemote) { ItemStack dropStack = new ItemStack(OpenBlocks.Items.stencil, 1, layer.getTopStencil().ordinal()); dropStackFromSide(dropStack, side); } layer.removeCover(); } else getLayersForSide(side).rotateCover(); if (!worldObj.isRemote) sync(); return true; } return false; } @Override public void addDrops(List<ItemStack> drops) { for (SyncableBlockLayers sideLayers : allSides) { if (sideLayers.isLastLayerStencil()) { Stencil stencil = sideLayers.getTopStencil(); if (stencil != null) drops.add(new ItemStack(OpenBlocks.Items.stencil, 1, stencil.ordinal())); } } } @Override public boolean suppressNormalHarvestDrops() { return paintedBlock.containsValidBlock(); } @Override public void addHarvestDrops(EntityPlayer player, List<ItemStack> drops) { if (paintedBlock.containsValidBlock()) { final Block paintedBlock = this.paintedBlock.getValue(); final int paintedBlockMeta = this.paintedBlockMeta.get(); final Random rand = worldObj.rand; int fortune = player != null? EnchantmentHelper.getFortuneModifier(player) : 0; int count = paintedBlock.quantityDropped(paintedBlockMeta, fortune, rand); int damageDropped = paintedBlock.damageDropped(paintedBlockMeta); for (int i = 0; i < count; i++) { Item item = paintedBlock.getItemDropped(paintedBlockMeta, rand, fortune); if (item != null) drops.add(new ItemStack(item, 1, damageDropped)); } } } public void setPaintedBlockBlock(Block block, int meta) { paintedBlock.setValue(block); paintedBlockMeta.set(meta); } }