package openmods.entity; import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import io.netty.buffer.ByteBuf; import net.minecraft.block.Block; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.DamageSource; import net.minecraft.util.MathHelper; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.ForgeDirection; import openmods.Log; import openmods.fakeplayer.FakePlayerPool; import openmods.fakeplayer.FakePlayerPool.PlayerUserReturning; import openmods.fakeplayer.OpenModsFakePlayer; import openmods.utils.BlockManipulator; import openmods.utils.BlockProperties; //TODO: Review later public class EntityBlock extends Entity implements IEntityAdditionalSpawnData { private static final String TAG_TILE_ENTITY = "TileEntity"; private static final String TAG_BLOCK_META = "BlockMeta"; private static final String TAG_BLOCK_NAME = "BlockName"; private static final int OBJECT_BLOCK_NAME = 11; private static final int OBJECT_BLOCK_META = 12; private boolean hasGravity = false; /* Should this entity return to a block on the ground? */ private boolean shouldDrop = true; private boolean hasAirResistance = true; public static final ForgeDirection[] PLACE_DIRECTIONS = { ForgeDirection.UNKNOWN, ForgeDirection.UP, ForgeDirection.NORTH, ForgeDirection.SOUTH, ForgeDirection.WEST, ForgeDirection.EAST, ForgeDirection.DOWN }; public EntityBlock(World world) { super(world); setSize(0.925F, 0.925F); } private void setHeight(float height) { this.height = height; yOffset = 0; } public static EntityBlock create(EntityPlayer player, World world, int x, int y, int z) { return create(player, world, x, y, z, EntityBlock.class); } public static EntityBlock create(EntityPlayer player, World world, int x, int y, int z, Class<? extends EntityBlock> klazz) { Block block = world.getBlock(x, y, z); if (block.isAir(world, x, y, z)) return null; int meta = world.getBlockMetadata(x, y, z); final EntityBlock entity; try { entity = klazz.getConstructor(World.class).newInstance(world); } catch (Throwable t) { Log.warn(t, "Failed to create EntityBlock(%s) at %d,%d,%d", klazz, x, y, z); return null; } entity.setBlockNameAndMeta(BlockProperties.getBlockName(block), meta); final TileEntity te = world.getTileEntity(x, y, z); if (te != null) { entity.tileEntity = new NBTTagCompound(); te.writeToNBT(entity.tileEntity); } final boolean blockRemoved = new BlockManipulator(world, player, x, y, z).setSilentTeRemove(true).remove(); if (!blockRemoved) return null; entity.setPositionAndRotation(x + 0.5, y + 0.5, z + 0.5, 0, 0); return entity; } private NBTTagCompound tileEntity; @Override protected void entityInit() { dataWatcher.addObject(OBJECT_BLOCK_NAME, BlockProperties.getBlockName(Blocks.bedrock)); dataWatcher.addObject(OBJECT_BLOCK_META, 0); } public void setBlockNameAndMeta(String name, int meta) { this.dataWatcher.updateObject(OBJECT_BLOCK_NAME, name); this.dataWatcher.updateObject(OBJECT_BLOCK_META, meta); } public String getBlockName() { return dataWatcher.getWatchableObjectString(OBJECT_BLOCK_NAME); } public Block getBlock() { return BlockProperties.getBlockByName(getBlockName()); } public int getBlockMeta() { return dataWatcher.getWatchableObjectInt(OBJECT_BLOCK_META); } public void setShouldDrop(boolean bool) { shouldDrop = bool; } public void setHasAirResistance(boolean bool) { this.hasAirResistance = bool; } @Override protected void readEntityFromNBT(NBTTagCompound tag) { String blockName = tag.getString(TAG_BLOCK_NAME); Block block = BlockProperties.getBlockByName(blockName); if (block == null) { setDead(); return; } int blockMeta = tag.getInteger(TAG_BLOCK_META); setBlockNameAndMeta(blockName, blockMeta); if (tag.hasKey(TAG_TILE_ENTITY, Constants.NBT.TAG_COMPOUND)) this.tileEntity = tag.getCompoundTag(TAG_TILE_ENTITY); else this.tileEntity = null; } @Override protected void writeEntityToNBT(NBTTagCompound tag) { tag.setString(TAG_BLOCK_NAME, getBlockName()); tag.setInteger(TAG_BLOCK_META, getBlockMeta()); if (tileEntity != null) tag.setTag(TAG_TILE_ENTITY, tileEntity.copy()); } @Override public void onUpdate() { if (posY < -500.0D) { setDead(); return; } if (hasGravity) { motionY -= 0.03999999910593033D; } if (hasAirResistance) { motionX *= 0.98; motionY *= 0.98; motionZ *= 0.98; } prevPosX = posX; prevPosY = posY; prevPosZ = posZ; extinguish(); moveEntity(motionX, motionY, motionZ); Block block = getBlock(); if (block == null) setDead(); else setHeight((float)block.getBlockBoundsMaxY()); if (worldObj instanceof WorldServer && shouldPlaceBlock()) { int x = MathHelper.floor_double(posX); int y = MathHelper.floor_double(posY); int z = MathHelper.floor_double(posZ); if (!tryPlaceBlock((WorldServer)worldObj, x, y, z)) dropBlock(); setDead(); } } protected boolean shouldPlaceBlock() { return onGround && shouldDrop; } private boolean tryPlaceBlock(WorldServer world, final int baseX, final int baseY, final int baseZ) { return FakePlayerPool.instance.executeOnPlayer(world, new PlayerUserReturning<Boolean>() { @Override public Boolean usePlayer(OpenModsFakePlayer fakePlayer) { for (ForgeDirection dir : PLACE_DIRECTIONS) { int x = baseX + dir.offsetX; int y = baseY + dir.offsetY; int z = baseZ + dir.offsetZ; if (!worldObj.isAirBlock(x, y, z)) continue; boolean blockPlaced = new BlockManipulator(worldObj, fakePlayer, x, y, z).place(getBlock(), getBlockMeta()); if (!blockPlaced) continue; if (tileEntity != null) { tileEntity.setInteger("x", x); tileEntity.setInteger("y", y); tileEntity.setInteger("z", z); TileEntity te = worldObj.getTileEntity(x, y, z); te.readFromNBT(tileEntity); } return true; } return false; } }); } private void dropBlock() { ItemStack item = new ItemStack(getBlock(), 1, getBlockMeta()); entityDropItem(item, 0.1f); if (tileEntity instanceof IInventory) { IInventory inv = (IInventory)tileEntity; for (int i = 0; i < inv.getSizeInventory(); i++) { ItemStack is = inv.getStackInSlot(i); if (is != null) entityDropItem(is, 0.1f); } } } public void setHasGravity(boolean gravity) { this.hasGravity = gravity; } public boolean hasGravity() { return hasGravity; } @Override @SideOnly(Side.CLIENT) public float getShadowSize() { return 0.0F; } @Override public boolean canRenderOnFire() { return false; } @Override public boolean canBeCollidedWith() { return !isDead; } @Override public boolean canBePushed() { return !isDead; } @Override protected void dealFireDamage(int i) {} @Override public void writeSpawnData(ByteBuf data) { data.writeBoolean(hasGravity); } @Override public boolean attackEntityFrom(DamageSource p_70097_1_, float p_70097_2_) { if (!isDead && !worldObj.isRemote) dropBlock(); setDead(); return false; } @Override public void readSpawnData(ByteBuf additionalData) { hasGravity = additionalData.readBoolean(); } }