package net.glowstone.entity.objects;
import com.flowpowered.network.Message;
import net.glowstone.block.GlowBlock;
import net.glowstone.block.entity.BlockEntity;
import net.glowstone.entity.GlowEntity;
import net.glowstone.net.message.play.entity.SpawnObjectMessage;
import net.glowstone.util.Position;
import net.glowstone.util.nbt.CompoundTag;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.FallingBlock;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
public class GlowFallingBlock extends GlowEntity implements FallingBlock {
private Material material;
private boolean canHurtEntities;
private boolean dropItem;
private byte blockData;
private Location sourceLocation;
private CompoundTag blockEntityCompoundTag;
// todo: implement falling block damage
/*
private boolean fallHurtMax;
private boolean fallHurtAmount;
also FallingBlockStore values
*/
// todo: implement slow in cobwebs (might just be global entity thing)
// todo: implement anvils sometimes taking damage
public GlowFallingBlock(Location location, Material material, byte blockData) {
this(location, material, blockData, null);
}
public GlowFallingBlock(Location location, Material material, byte blockData, BlockEntity blockEntity) {
super(location);
blockEntityCompoundTag = null;
if (blockEntity != null) {
blockEntityCompoundTag = new CompoundTag();
blockEntity.saveNbt(blockEntityCompoundTag);
}
this.sourceLocation = location.clone();
setBoundingBox(0.98, 0.98);
setDrag(0.98, false);
setGravityAccel(new Vector(0, -0.02, 0));
setMaterial(material);
setDropItem(true);
setHurtEntities(true);
this.blockData = blockData;
}
@Override
public Material getMaterial() {
return material;
}
public void setMaterial(Material material) {
this.material = material;
}
@Override
public boolean getDropItem() {
return dropItem;
}
@Override
public void setDropItem(boolean dropItem) {
this.dropItem = dropItem;
}
@Override
public boolean canHurtEntities() {
return canHurtEntities;
}
@Override
public void setHurtEntities(boolean canHurtEntities) {
this.canHurtEntities = canHurtEntities;
}
@Override
public byte getBlockData() {
return blockData;
}
public void setBlockData(byte blockData) {
this.blockData = blockData;
}
@Override
public Location getOrigin() {
return null;
}
public CompoundTag getBlockEntityCompoundTag() {
return blockEntityCompoundTag;
}
public void setBlockEntityCompoundTag(CompoundTag blockEntityCompoundTag) {
this.blockEntityCompoundTag = blockEntityCompoundTag;
}
@Override
public int getBlockId() {
return material.getId();
}
public Location getSourceLoc() {
return sourceLocation;
}
@Override
public List<Message> createSpawnMessage() {
double x = location.getX();
double y = location.getY();
double z = location.getZ();
int yaw = Position.getIntYaw(location);
int pitch = Position.getIntPitch(location);
// Note the shift amount has changed previously,
// if block data doesn't appear to work check this value.
int blockIdData = getBlockId() | getBlockData() << 12;
return Arrays.asList(
new SpawnObjectMessage(id, getUniqueId(), 70, x, y, z, pitch, yaw, blockIdData)
);
}
@Override
protected void pulsePhysics() {
if (location.getY() < 0) {
remove();
return;
}
Location nextBlock = location.clone().add(getVelocity());
if (!nextBlock.getBlock().getType().isSolid()) {
velocity.add(getGravityAccel());
location.add(getVelocity());
velocity.multiply(airDrag);
} else {
if (supportingBlock(location.getBlock().getType())) {
boolean replaceBlock;
switch (location.getBlock().getType()) {
case DEAD_BUSH:
case LONG_GRASS:
case DOUBLE_PLANT:
replaceBlock = true;
break;
default:
replaceBlock = false;
break;
}
if (replaceBlock) {
setDropItem(false);
}
// todo: add event if desired
if (getDropItem()) {
world.dropItemNaturally(location, new ItemStack(material, 1, (short) 0, getBlockData()));
}
if (replaceBlock) {
placeFallingBlock();
}
remove();
} else {
placeFallingBlock();
if (material == Material.ANVIL) {
Random random = new Random();
world.playSound(location, Sound.BLOCK_ANVIL_FALL, 4, (1.0F + (random.nextFloat() - random.nextFloat()) * 0.2F) * 0.7F);
}
remove();
}
}
updateBoundingBox();
}
private void placeFallingBlock() {
location.getBlock().setTypeIdAndData(material.getId(), getBlockData(), true);
if (getBlockEntityCompoundTag() != null) {
if (location.getBlock() instanceof GlowBlock) {
GlowBlock block = (GlowBlock) location.getBlock();
BlockEntity blockEntity = block.getBlockEntity();
if (blockEntity != null) {
blockEntity.loadNbt(getBlockEntityCompoundTag());
}
}
}
}
@Override
public EntityType getType() {
return EntityType.FALLING_BLOCK;
}
private boolean supportingBlock(Material material) {
switch (material) {
case AIR:
case FIRE:
case WATER:
case STATIONARY_WATER:
case LAVA:
case STATIONARY_LAVA:
return false;
}
return true;
}
}