package com.carpentersblocks.entity.item; import java.util.ArrayList; import java.util.List; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.DamageSource; import net.minecraft.util.IIcon; import net.minecraft.util.MathHelper; import net.minecraft.util.MovingObjectPosition; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; import com.carpentersblocks.api.ICarpentersHammer; import com.carpentersblocks.util.BlockProperties; import com.carpentersblocks.util.handler.DesignHandler; import com.carpentersblocks.util.handler.DyeHandler; import com.carpentersblocks.util.protection.PlayerPermissions; import com.carpentersblocks.util.registry.IconRegistry; import com.carpentersblocks.util.registry.ItemRegistry; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; public class EntityCarpentersTile extends EntityBase { private int ticks; private boolean boundsSet; private final static byte ID_DIRECTION = 13; private final static byte ID_DYE = 14; private final static byte ID_DESIGN = 15; private final static byte ID_ROTATION = 16; private final static String TAG_DESIGN = "tile"; // Description holding for compatibility with pre-3.2.0 private final static String TAG_DIRECTION = "dir"; private final static String TAG_DYE = "dye"; private final static String TAG_ROTATION = "rot"; /** Depth of tile. */ private final static double depth = 0.0625D; private final static double[][] bounds = { { 0.0D, 1.0D - depth, 0.0D, 1.0D, 1.0D, 1.0D }, { 0.0D, 0.0D, 0.0D, 1.0D, depth, 1.0D }, { 0.0D, 0.0D, 1.0D - depth, 1.0D, 1.0D, 1.0D }, { 0.0D, 0.0D, 0.0D, 1.0D, 1.0D, depth }, { 1.0D - depth, 0.0D, 0.0D, 1.0D, 1.0D, 1.0D }, { 0.0D, 0.0D, 0.0D, depth, 1.0D, 1.0D } }; public EntityCarpentersTile(World world) { super(world); } public EntityCarpentersTile(EntityPlayer entityPlayer, World world, int x, int y, int z, ForgeDirection dir, ForgeDirection offset_side, boolean ignoreNeighbors) { super(world, entityPlayer); posX = x; posY = y; posZ = z; setDirection(dir); setBoundingBox(); if (!ignoreNeighbors) { List<EntityCarpentersTile> list = new ArrayList<EntityCarpentersTile>(); double factor = 0.2D; boundingBox.contract(0.1D, 0.1D, 0.1D); switch (offset_side) { case DOWN: list = world.getEntitiesWithinAABB(EntityCarpentersTile.class, boundingBox.offset(0.0D, -factor, 0.0D)); break; case UP: list = world.getEntitiesWithinAABB(EntityCarpentersTile.class, boundingBox.offset(0.0D, factor, 0.0D)); break; case NORTH: list = world.getEntitiesWithinAABB(EntityCarpentersTile.class, boundingBox.offset(0.0D, 0.0D, -factor)); break; case SOUTH: list = world.getEntitiesWithinAABB(EntityCarpentersTile.class, boundingBox.offset(0.0D, 0.0D, factor)); break; case WEST: list = world.getEntitiesWithinAABB(EntityCarpentersTile.class, boundingBox.offset(-factor, 0.0D, 0.0D)); break; case EAST: list = world.getEntitiesWithinAABB(EntityCarpentersTile.class, boundingBox.offset(factor, 0.0D, 0.0D)); break; default: switch (dir) { case DOWN: case UP: list = world.getEntitiesWithinAABB(EntityCarpentersTile.class, boundingBox.expand(factor, 0.0D, factor)); break; case NORTH: case SOUTH: list = world.getEntitiesWithinAABB(EntityCarpentersTile.class, boundingBox.expand(factor, factor, 0.0D)); break; case WEST: case EAST: list = world.getEntitiesWithinAABB(EntityCarpentersTile.class, boundingBox.expand(0.0D, factor, factor)); break; default: {} } } for (EntityCarpentersTile tile : list) { /* Skip checking diagonal tiles when tile is placed in center. */ if (offset_side.equals(ForgeDirection.UNKNOWN)) { switch (dir) { case DOWN: case UP: if (!(tile.posX == posX || tile.posZ == posZ)) { continue; } break; case NORTH: case SOUTH: if (!(tile.posX == posX || tile.posY == posY)) { continue; } break; case WEST: case EAST: if (!(tile.posZ == posZ || tile.posY == posY)) { continue; } break; default: {} } } /* Match up tile properties with neighbor. */ if (!tile.getDye().equals(getDefaultDye())) { setDye(tile.getDye()); } if (tile.getRotation() != 0) { setRotation(tile.getRotation()); } if (tile.hasDesign()) { setDesign(tile.getDesign()); } } } } /** * Keeps moving the entity up so it isn't colliding with blocks and other requirements for this entity to be spawned * (only actually used on players though its also on Entity) */ @Override @SideOnly(Side.CLIENT) protected void preparePlayerToSpawn() { } /** * Sets the width and height of the entity. Args: width, height */ @Override protected void setSize(float width, float height) { } /** * Sets the x,y,z of the entity from the given parameters. Also seems to set up a bounding box. */ @Override public void setPosition(double x, double y, double z) { } /** * Sets the position and rotation. Only difference from the other one is no bounding on the rotation. Args: posX, * posY, posZ, yaw, pitch */ @Override @SideOnly(Side.CLIENT) public void setPositionAndRotation2(double posX, double posY, double posZ, float yaw, float pitch, int par9) { } /** * Called when a player mounts an entity. e.g. mounts a pig, mounts a boat. */ @Override public void mountEntity(Entity entity) { } @Override protected boolean func_145771_j(double x, double y, double z) { return false; } public String getDefaultDye() { return "dyeWhite"; } public void playTileSound() { BlockProperties.playBlockSound(worldObj, new ItemStack(Blocks.hardened_clay), (int) Math.floor(posX), (int) Math.floor(posY), (int) Math.floor(posZ), true); } public void playDyeSound() { BlockProperties.playBlockSound(worldObj, new ItemStack(Blocks.sand), (int) Math.floor(posX), (int) Math.floor(posY), (int) Math.floor(posZ), true); } public double[] getBounds() { return bounds[getDataWatcher().getWatchableObjectInt(ID_DIRECTION)]; } public void setBoundingBox() { double bounds[] = getBounds(); boundingBox.setBounds(posX + bounds[0], posY + bounds[1], posZ + bounds[2], posX + bounds[3], posY + bounds[4], posZ + bounds[5]); } public ForgeDirection getDirection() { return ForgeDirection.getOrientation(getDataWatcher().getWatchableObjectInt(ID_DIRECTION)); } public void setDirection(ForgeDirection dir) { getDataWatcher().updateObject(ID_DIRECTION, new Integer(dir.ordinal())); } public void setRotation(int rotation) { getDataWatcher().updateObject(ID_ROTATION, new Integer(rotation)); } public void rotate() { int rotation = getRotation(); setRotation(++rotation & 3); } public int getRotation() { return getDataWatcher().getWatchableObjectInt(ID_ROTATION); } public void setDye(String dye) { getDataWatcher().updateObject(ID_DYE, new String(dye)); } public String getDye() { return getDataWatcher().getWatchableObjectString(ID_DYE); } public boolean hasDesign() { return DesignHandler.listTile.contains(getDesign()); } public void setDesign(String tile) { getDataWatcher().updateObject(ID_DESIGN, new String(tile)); } public String getDesign() { return getDataWatcher().getWatchableObjectString(ID_DESIGN); } public IIcon getIcon() { if (hasDesign()) { return IconRegistry.icon_design_tile.get(DesignHandler.listTile.indexOf(getDesign())); } else { return IconRegistry.icon_tile_blank; } } /** * (abstract) Protected helper method to read subclass entity data from NBT. */ @Override public void readEntityFromNBT(NBTTagCompound nbtTagCompound) { getDataWatcher().updateObject(ID_DESIGN, String.valueOf(nbtTagCompound.getString(TAG_DESIGN))); getDataWatcher().updateObject(ID_DYE, String.valueOf(nbtTagCompound.getString(TAG_DYE))); getDataWatcher().updateObject(ID_DIRECTION, Integer.valueOf(nbtTagCompound.getInteger(TAG_DIRECTION))); getDataWatcher().updateObject(ID_ROTATION, Integer.valueOf(nbtTagCompound.getInteger(TAG_ROTATION))); super.readEntityFromNBT(nbtTagCompound); } /** * (abstract) Protected helper method to write subclass entity data to NBT. */ @Override public void writeEntityToNBT(NBTTagCompound nbtTagCompound) { nbtTagCompound.setString(TAG_DESIGN, getDataWatcher().getWatchableObjectString(ID_DESIGN)); nbtTagCompound.setString(TAG_DYE, getDataWatcher().getWatchableObjectString(ID_DYE)); nbtTagCompound.setInteger(TAG_DIRECTION, getDataWatcher().getWatchableObjectInt(ID_DIRECTION)); nbtTagCompound.setInteger(TAG_ROTATION, getDataWatcher().getWatchableObjectInt(ID_ROTATION)); super.writeEntityToNBT(nbtTagCompound); } /** * Called when this entity is broken. Entity parameter may be null. */ public void onBroken(Entity entity) { if (entity instanceof EntityPlayer) { EntityPlayer entityPlayer = (EntityPlayer) entity; ItemStack itemStack = entityPlayer.getHeldItem(); boolean hasHammer = false; if (itemStack != null) { Item item = itemStack.getItem(); if (item instanceof ICarpentersHammer) { hasHammer = true; } } if (entityPlayer.capabilities.isCreativeMode && !hasHammer) { return; } } entityDropItem(getItemDrop(), 0.0F); } /** * Called to update the entity's position/logic. */ @Override public void onUpdate() { if (!boundsSet) { setBoundingBox(); boundsSet = true; } if (!worldObj.isRemote) { if (ticks++ >= 20) { ticks = 0; if (!isDead && !onValidSurface()) { setDead(); onBroken((Entity)null); } } } } /** * Returns representative ItemStack for entity. */ private ItemStack getItemDrop() { return new ItemStack(ItemRegistry.itemCarpentersTile); } /** * Called when a user uses the creative pick block button on this entity. * * @param target The full target the player is looking at * @return A ItemStack to add to the player's inventory, Null if nothing should be added. */ @Override public ItemStack getPickedResult(MovingObjectPosition target) { return getItemDrop(); } @Override public boolean shouldRenderInPass(int pass) { // Has absolutely no effect return pass == 0; } /** * Returns true if tile is on a valid surface. */ public boolean onValidSurface() { ForgeDirection dir = getDirection(); int x_offset = MathHelper.floor_double(posX) - dir.offsetX; int y_offset = MathHelper.floor_double(posY) - dir.offsetY; int z_offset = MathHelper.floor_double(posZ) - dir.offsetZ; return worldObj.getBlock(x_offset, y_offset, z_offset).isSideSolid(worldObj, x_offset, y_offset, z_offset, dir); } /** * Called when the entity is attacked. */ @Override public boolean attackEntityFrom(DamageSource damageSource, float par2) { if (!worldObj.isRemote) { Entity entity = damageSource.getEntity(); boolean dropItem = false; if (entity instanceof EntityPlayer && PlayerPermissions.hasElevatedPermission(this, (EntityPlayer)entity, false)) { EntityPlayer entityPlayer = (EntityPlayer) entity; ItemStack itemStack = entityPlayer.getHeldItem(); if (itemStack != null) { if (itemStack.getItem() instanceof ICarpentersHammer) { if (entity.isSneaking()) { if (!isDead) { dropItem = true; } } else { setDesign(DesignHandler.getNext("tile", getDesign())); } } else if (entityPlayer.capabilities.isCreativeMode) { if (!isDead) { dropItem = true; } } } } playTileSound(); if (dropItem) { setDead(); setBeenAttacked(); onBroken(damageSource.getEntity()); return true; } } return false; } @Override /** * First layer of player interaction. */ public boolean interactFirst(EntityPlayer entityPlayer) { if (worldObj.isRemote) { return true; } else if (PlayerPermissions.hasElevatedPermission(this, entityPlayer, false)) { ItemStack itemStack = entityPlayer.getHeldItem(); if (itemStack != null) { if (itemStack.getItem() instanceof ICarpentersHammer) { if (entityPlayer.isSneaking()) { rotate(); } else { setDesign(DesignHandler.getPrev("tile", getDesign())); } playTileSound(); } else if (BlockProperties.isDye(itemStack, true)) { if (entityPlayer.isSneaking()) { String dye = DyeHandler.getOreDictName(itemStack); if (!getDye().equals(dye)) { setDye(DyeHandler.getOreDictName(itemStack)); playDyeSound(); } } } return true; } } return false; } /** * Tries to moves the entity by the passed in displacement. Args: x, y, z */ @Override public void moveEntity(double x, double y, double z) { if (!worldObj.isRemote && !isDead && x * x + y * y + z * z > 0.0D) { setDead(); onBroken((Entity)null); } } /** * Adds to the current velocity of the entity. Args: x, y, z */ @Override public void addVelocity(double x, double y, double z) { if (!worldObj.isRemote && !isDead && x * x + y * y + z * z > 0.0D) { setDead(); onBroken((Entity)null); } } @Override protected void entityInit() { super.entityInit(); getDataWatcher().addObject(ID_DESIGN, new String("")); getDataWatcher().addObject(ID_DYE, new String("dyeWhite")); getDataWatcher().addObject(ID_DIRECTION, new Integer(0)); getDataWatcher().addObject(ID_ROTATION, new Integer(0)); } /** * Returns true if other Entities should be prevented from moving through this Entity. */ @Override public boolean canBeCollidedWith() { return true; } /** * returns the bounding box for this entity */ @Override public AxisAlignedBB getBoundingBox() { return boundingBox; } @Override public float getCollisionBorderSize() { return 0.0F; } @Override protected boolean shouldSetPosAfterLoading() { return false; } }