package net.minecraft.server;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Nullable;
import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit
public class EntityFallingBlock extends Entity {
private IBlockData block;
public int ticksLived;
public boolean dropItem = true;
private boolean f;
public boolean hurtEntities;
private int fallHurtMax = 40;
private float fallHurtAmount = 2.0F;
public NBTTagCompound tileEntityData;
protected static final DataWatcherObject<BlockPosition> d = DataWatcher.a(EntityFallingBlock.class, DataWatcherRegistry.j);
public EntityFallingBlock(World world) {
super(world);
}
public EntityFallingBlock(World world, double d0, double d1, double d2, IBlockData iblockdata) {
super(world);
this.block = iblockdata;
this.i = true;
this.setSize(0.98F, 0.98F);
this.setPosition(d0, d1 + (double) ((1.0F - this.length) / 2.0F), d2);
this.motX = 0.0D;
this.motY = 0.0D;
this.motZ = 0.0D;
this.lastX = d0;
this.lastY = d1;
this.lastZ = d2;
this.a(new BlockPosition(this));
}
public void a(BlockPosition blockposition) {
this.datawatcher.set(EntityFallingBlock.d, blockposition);
}
protected boolean playStepSound() {
return false;
}
protected void i() {
this.datawatcher.register(EntityFallingBlock.d, BlockPosition.ZERO);
}
public boolean isInteractable() {
return !this.dead;
}
public void A_() {
Block block = this.block.getBlock();
if (this.block.getMaterial() == Material.AIR) {
this.die();
} else {
this.lastX = this.locX;
this.lastY = this.locY;
this.lastZ = this.locZ;
BlockPosition blockposition;
if (this.ticksLived++ == 0) {
blockposition = new BlockPosition(this);
if (this.world.getType(blockposition).getBlock() == block && !CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, Blocks.AIR, 0).isCancelled()) {
this.world.setAir(blockposition);
} else if (!this.world.isClientSide) {
this.die();
return;
}
}
if (!this.isNoGravity()) {
this.motY -= 0.03999999910593033D;
}
this.move(EnumMoveType.SELF, this.motX, this.motY, this.motZ);
// Paper start - Configurable EntityFallingBlock height nerf
if (this.world.paperConfig.fallingBlockHeightNerf != 0 && this.locY > this.world.paperConfig.fallingBlockHeightNerf) {
if (this.dropItem && this.world.getGameRules().getBoolean("doEntityDrops")) {
this.a(new ItemStack(block, 1, block.getDropData(this.block)), 0.0F);
}
this.die();
}
// Paper end
this.motX *= 0.9800000190734863D;
this.motY *= 0.9800000190734863D;
this.motZ *= 0.9800000190734863D;
if (!this.world.isClientSide) {
blockposition = new BlockPosition(this);
if (this.onGround) {
IBlockData iblockdata = this.world.getType(blockposition);
if (!isOnGround()) {
this.onGround = false;
if (this.world.paperConfig.altFallingBlockOnGround) return; // Paper
}
this.motX *= 0.699999988079071D;
this.motZ *= 0.699999988079071D;
this.motY *= -0.5D;
if (iblockdata.getBlock() != Blocks.PISTON_EXTENSION) {
this.die();
if (!this.f) {
// CraftBukkit start
if (this.world.a(block, blockposition, true, EnumDirection.UP, (Entity) null) && !BlockFalling.i(this.world.getType(blockposition.down()))) {
if (CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, this.block.getBlock(), this.block.getBlock().toLegacyData(this.block)).isCancelled()) {
return;
}
this.world.setTypeAndData(blockposition, this.block, 3);
// CraftBukkit end
if (block instanceof BlockFalling) {
((BlockFalling) block).a_(this.world, blockposition);
}
if (this.tileEntityData != null && block instanceof ITileEntity) {
TileEntity tileentity = this.world.getTileEntity(blockposition);
if (tileentity != null) {
NBTTagCompound nbttagcompound = tileentity.save(new NBTTagCompound());
Iterator iterator = this.tileEntityData.c().iterator();
while (iterator.hasNext()) {
String s = (String) iterator.next();
NBTBase nbtbase = this.tileEntityData.get(s);
if (!"x".equals(s) && !"y".equals(s) && !"z".equals(s)) {
nbttagcompound.set(s, nbtbase.clone());
}
}
tileentity.a(nbttagcompound);
tileentity.update();
}
}
} else if (this.dropItem && this.world.getGameRules().getBoolean("doEntityDrops")) {
this.a(new ItemStack(block, 1, block.getDropData(this.block)), 0.0F);
}
} else if (block instanceof BlockFalling) {
((BlockFalling) block).b(this.world, blockposition);
}
}
} else if (this.ticksLived > 100 && !this.world.isClientSide && (blockposition.getY() < 1 || blockposition.getY() > 256) || this.ticksLived > 600) {
if (this.dropItem && this.world.getGameRules().getBoolean("doEntityDrops")) {
this.a(new ItemStack(block, 1, block.getDropData(this.block)), 0.0F);
}
this.die();
}
}
}
}
// Paper start
private boolean isOnGround() {
BlockPosition where = new BlockPosition(this.locX, this.locY - 0.009999999776482582D, this.locZ);
boolean cannotMoveThrough = !BlockFalling.canMoveThrough(this.world.getType(where));
if (!this.world.paperConfig.altFallingBlockOnGround) return cannotMoveThrough;
if (cannotMoveThrough) {
return true;
}
IBlockData blockData = this.world.getType(where.down());
if (BlockFalling.canMoveThrough(blockData)) {
return false;
}
List<AxisAlignedBB> list = new ArrayList<>();
addCollisions(blockData, getWorld(), where, this.getBoundingBox(), list, this);
return list.size() > 0;
}
// OBFHELPER
private void addCollisions(IBlockData blockData, World world, BlockPosition where, AxisAlignedBB collider, List<AxisAlignedBB> list, Entity entity) {
blockData.a(world, where, collider, list, entity, false);
}
// Paper end
public void e(float f, float f1) {
Block block = this.block.getBlock();
if (this.hurtEntities) {
int i = MathHelper.f(f - 1.0F);
if (i > 0) {
ArrayList arraylist = Lists.newArrayList(this.world.getEntities(this, this.getBoundingBox()));
boolean flag = block == Blocks.ANVIL;
DamageSource damagesource = flag ? DamageSource.ANVIL : DamageSource.FALLING_BLOCK;
Iterator iterator = arraylist.iterator();
while (iterator.hasNext()) {
Entity entity = (Entity) iterator.next();
CraftEventFactory.entityDamage = this; // CraftBukkit
entity.damageEntity(damagesource, (float) Math.min(MathHelper.d((float) i * this.fallHurtAmount), this.fallHurtMax));
CraftEventFactory.entityDamage = null; // CraftBukkit
}
if (flag && (double) this.random.nextFloat() < 0.05000000074505806D + (double) i * 0.05D) {
int j = ((Integer) this.block.get(BlockAnvil.DAMAGE)).intValue();
++j;
if (j > 2) {
this.f = true;
} else {
this.block = this.block.set(BlockAnvil.DAMAGE, Integer.valueOf(j));
}
}
}
}
}
public static void a(DataConverterManager dataconvertermanager) {}
protected void b(NBTTagCompound nbttagcompound) {
Block block = this.block != null ? this.block.getBlock() : Blocks.AIR;
MinecraftKey minecraftkey = (MinecraftKey) Block.REGISTRY.b(block);
nbttagcompound.setString("Block", minecraftkey == null ? "" : minecraftkey.toString());
nbttagcompound.setByte("Data", (byte) block.toLegacyData(this.block));
nbttagcompound.setInt("Time", this.ticksLived);
nbttagcompound.setBoolean("DropItem", this.dropItem);
nbttagcompound.setBoolean("HurtEntities", this.hurtEntities);
nbttagcompound.setFloat("FallHurtAmount", this.fallHurtAmount);
nbttagcompound.setInt("FallHurtMax", this.fallHurtMax);
if (this.tileEntityData != null) {
nbttagcompound.set("TileEntityData", this.tileEntityData);
}
}
protected void a(NBTTagCompound nbttagcompound) {
int i = nbttagcompound.getByte("Data") & 255;
if (nbttagcompound.hasKeyOfType("Block", 8)) {
this.block = Block.getByName(nbttagcompound.getString("Block")).fromLegacyData(i);
} else if (nbttagcompound.hasKeyOfType("TileID", 99)) {
this.block = Block.getById(nbttagcompound.getInt("TileID")).fromLegacyData(i);
} else {
this.block = Block.getById(nbttagcompound.getByte("Tile") & 255).fromLegacyData(i);
}
// Paper start - Block FallingBlocks with Command Blocks
// Check mappings on update - dc = "repeating_command_block" - dd = "chain_command_block"
final Block b = this.block.getBlock();
if (this.world.paperConfig.filterNBTFromSpawnEgg && (b == Blocks.COMMAND_BLOCK || b == Blocks.dc || b == Blocks.dd)) {
this.block = Blocks.STONE.getBlockData();
}
// Paper end
this.ticksLived = nbttagcompound.getInt("Time");
Block block = this.block.getBlock();
if (nbttagcompound.hasKeyOfType("HurtEntities", 99)) {
this.hurtEntities = nbttagcompound.getBoolean("HurtEntities");
this.fallHurtAmount = nbttagcompound.getFloat("FallHurtAmount");
this.fallHurtMax = nbttagcompound.getInt("FallHurtMax");
} else if (block == Blocks.ANVIL) {
this.hurtEntities = true;
}
if (nbttagcompound.hasKeyOfType("DropItem", 99)) {
this.dropItem = nbttagcompound.getBoolean("DropItem");
}
if (nbttagcompound.hasKeyOfType("TileEntityData", 10)) {
this.tileEntityData = nbttagcompound.getCompound("TileEntityData");
}
if (block == null || block.getBlockData().getMaterial() == Material.AIR) {
this.block = Blocks.SAND.getBlockData();
}
// Paper start - Try and load origin location from the old NBT tags for backwards compatibility
if (nbttagcompound.hasKey("SourceLoc_x")) {
int srcX = nbttagcompound.getInt("SourceLoc_x");
int srcY = nbttagcompound.getInt("SourceLoc_y");
int srcZ = nbttagcompound.getInt("SourceLoc_z");
origin = new org.bukkit.Location(world.getWorld(), srcX, srcY, srcZ);
}
// Paper end
}
public void a(boolean flag) {
this.hurtEntities = flag;
}
public void appendEntityCrashDetails(CrashReportSystemDetails crashreportsystemdetails) {
super.appendEntityCrashDetails(crashreportsystemdetails);
if (this.block != null) {
Block block = this.block.getBlock();
crashreportsystemdetails.a("Immitating block ID", (Object) Integer.valueOf(Block.getId(block)));
crashreportsystemdetails.a("Immitating block data", (Object) Integer.valueOf(block.toLegacyData(this.block)));
}
}
@Nullable
public IBlockData getBlock() {
return this.block;
}
public boolean bu() {
return true;
}
// Paper start - Old TNT cannon behaviors
@Override
public double getDistance(double d0, double d1, double d2) {
if (!world.paperConfig.oldCannonBehaviors) return super.getDistance(d0, d1, d2);
double newX = this.locX - d0;
double newY = this.locY + this.getHeadHeight() - d1;
double newZ = this.locZ - d2;
return (double) MathHelper.sqrt(newX * newX + newY * newY + newZ * newZ);
}
// Paper end
}