blob: 97bb4224841849a24fab5e257639b5eb875f3ff3 [file] [log] [blame] [raw]
package net.glowstone.entity.objects;
import com.flowpowered.network.Message;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import lombok.Getter;
import lombok.Setter;
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.nbt.CompoundTag;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.FallingBlock;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
public class GlowFallingBlock extends GlowEntity implements FallingBlock {
private static final double VERTICAL_GRAVITY_ACCEL = -0.04;
@Getter
private BlockData blockData;
private boolean canHurtEntities;
@Setter
private boolean dropItem;
private Location sourceLocation;
@Getter
@Setter
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, BlockData data) {
this(location, data, null);
}
/**
* Creates an instance for the given entity.
*
* @param location the falling block's location
* @param blockData the falling block's BlockData
* @param blockEntity the entity
*/
public GlowFallingBlock(Location location, BlockData 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);
setAirDrag(0.98);
setGravityAccel(new Vector(0, VERTICAL_GRAVITY_ACCEL, 0));
setDropItem(true);
setHurtEntities(true);
this.blockData = blockData;
}
@Override
public boolean canHurtEntities() {
return canHurtEntities;
}
@Override
public void setHurtEntities(boolean canHurtEntities) {
this.canHurtEntities = canHurtEntities;
}
@Override
public Material getMaterial() {
return getBlockData().getMaterial();
}
@Override
public boolean getDropItem() {
return dropItem;
}
@Override
public List<Message> createSpawnMessage() {
// TODO: 1.13: Flatten BlockData to integer
// return Collections.singletonList(
// new SpawnObjectMessage(entityId, getUniqueId(), 70, location, blockIdData)
// );
return Collections.emptyList();
}
@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 TALL_GRASS: // TODO: 1.13, DOUBLE_PLANT
replaceBlock = true;
break;
default:
replaceBlock = false;
break;
}
if (replaceBlock) {
setDropItem(false);
}
// todo: add event if desired
if (getDropItem()) {
// TODO: 1.13, convert BlockData to MaterialData
world.dropItemNaturally(location,
new ItemStack(getMaterial()));
}
if (replaceBlock) {
placeFallingBlock();
}
remove();
} else {
placeFallingBlock();
remove();
}
}
updateBoundingBox();
}
private void placeFallingBlock() {
location.getBlock().setBlockData(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());
}
}
}
// TODO: damaged anvils too
if (getBlockData().getMaterial() == Material.ANVIL) {
ThreadLocalRandom random = ThreadLocalRandom.current();
world.playSound(location, Sound.BLOCK_ANVIL_FALL, 4, (1.0F
+ (random.nextFloat() - random.nextFloat()) * 0.2F) * 0.7F);
}
}
@Override
public EntityType getType() {
return EntityType.FALLING_BLOCK;
}
private boolean supportingBlock(Material material) {
switch (material) {
case AIR:
case FIRE:
case WATER:
case LAVA:
return false;
default:
return true;
}
}
}