cn.nukkit.block.BlockChorusFlower Maven / Gradle / Ivy
package cn.nukkit.block;
import cn.nukkit.Player;
import cn.nukkit.Server;
import cn.nukkit.api.PowerNukkitOnly;
import cn.nukkit.api.Since;
import cn.nukkit.blockproperty.BlockProperties;
import cn.nukkit.blockproperty.IntBlockProperty;
import cn.nukkit.entity.Entity;
import cn.nukkit.entity.projectile.EntityArrow;
import cn.nukkit.entity.projectile.EntitySnowball;
import cn.nukkit.event.block.BlockGrowEvent;
import cn.nukkit.item.Item;
import cn.nukkit.item.ItemTool;
import cn.nukkit.level.Level;
import cn.nukkit.level.Position;
import cn.nukkit.level.Sound;
import cn.nukkit.math.BlockFace;
import cn.nukkit.math.Vector3;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.concurrent.ThreadLocalRandom;
public class BlockChorusFlower extends BlockTransparentMeta {
@PowerNukkitOnly
@Since("1.5.0.0-PN")
public static final IntBlockProperty AGE = new IntBlockProperty("age", false, 5);
@PowerNukkitOnly
@Since("1.5.0.0-PN")
public static final BlockProperties PROPERTIES = new BlockProperties(AGE);
public BlockChorusFlower() {
this(0);
}
public BlockChorusFlower(int meta) {
super(meta);
}
@Override
public int getId() {
return CHORUS_FLOWER;
}
@Since("1.4.0.0-PN")
@PowerNukkitOnly
@Nonnull
@Override
public BlockProperties getProperties() {
return PROPERTIES;
}
@Override
public String getName() {
return "Chorus Flower";
}
@Override
public double getHardness() {
return 0.4;
}
@Override
public double getResistance() {
return 0.4;
}
@Override
public int getToolType() {
return ItemTool.TYPE_AXE;
}
private boolean isPositionValid() {
// Chorus flowers must be above end stone or chorus plant, or be above air and horizontally adjacent to exactly one chorus plant.
// If these conditions are not met, the block breaks without dropping anything.
Block down = down();
if (down.getId() == CHORUS_PLANT || down.getId() == END_STONE) {
return true;
}
if (down.getId() != AIR) {
return false;
}
boolean foundPlant = false;
for (BlockFace face : BlockFace.Plane.HORIZONTAL) {
Block side = getSide(face);
if (side.getId() == CHORUS_PLANT) {
if (foundPlant) {
return false;
}
foundPlant = true;
}
}
return foundPlant;
}
@Override
public int onUpdate(int type) {
if (type == Level.BLOCK_UPDATE_NORMAL) {
if (!isPositionValid()) {
this.getLevel().scheduleUpdate(this, 1);
return type;
}
} else if (type == Level.BLOCK_UPDATE_SCHEDULED) {
this.getLevel().useBreakOn(this, null, null, true);
return type;
} else if (type == Level.BLOCK_UPDATE_RANDOM) {
// Check limit
if (this.up().getId() == AIR && this.up().getY() < level.getMaxHeight()) {
if (!isFullyAged()) {
boolean growUp = false; // Grow upward?
boolean ground = false; // Is on the ground directly?
if (this.down().getId() == AIR || this.down().getId() == END_STONE) {
growUp = true;
} else if (this.down().getId() == CHORUS_PLANT) {
int height = 1;
for (int y = 2; y < 6; y++) {
if (this.down(y).getId() == CHORUS_PLANT) {
height++;
} else {
if (this.down(y).getId() == END_STONE) {
ground = true;
}
break;
}
}
if (height < 2 || height <= ThreadLocalRandom.current().nextInt(ground ? 5 : 4)) {
growUp = true;
}
}
// Grow Upward
if (growUp && this.up(2).getId() == AIR && isHorizontalAir(this.up())) {
BlockChorusFlower block = (BlockChorusFlower) this.clone();
block.y = this.y + 1;
BlockGrowEvent ev = new BlockGrowEvent(this, block);
Server.getInstance().getPluginManager().callEvent(ev);
if (!ev.isCancelled()) {
this.getLevel().setBlock(this, Block.get(CHORUS_PLANT));
this.getLevel().setBlock(block, ev.getNewState());
this.getLevel().addSound(this.add(0.5, 0.5, 0.5), Sound.BLOCK_CHORUSFLOWER_GROW);
} else {
return Level.BLOCK_UPDATE_RANDOM;
}
// Grow Horizontally
} else if (!isFullyAged()) {
for (int i = 0; i < ThreadLocalRandom.current().nextInt(ground ? 5 : 4); i++) {
BlockFace face = BlockFace.Plane.HORIZONTAL.random();
Block check = this.getSide(face);
if (check.getId() == AIR && check.down().getId() == AIR && isHorizontalAirExcept(check, face.getOpposite())) {
BlockChorusFlower block = (BlockChorusFlower) this.clone();
block.x = check.x;
block.y = check.y;
block.z = check.z;
block.setAge(getAge() + 1);
BlockGrowEvent ev = new BlockGrowEvent(this, block);
Server.getInstance().getPluginManager().callEvent(ev);
if (!ev.isCancelled()) {
this.getLevel().setBlock(this, Block.get(CHORUS_PLANT));
this.getLevel().setBlock(block, ev.getNewState());
this.getLevel().addSound(this.add(0.5, 0.5, 0.5), Sound.BLOCK_CHORUSFLOWER_GROW);
} else {
return Level.BLOCK_UPDATE_RANDOM;
}
}
}
// Death
} else {
BlockChorusFlower block = (BlockChorusFlower) this.clone();
block.setAge(getMaxAge());
BlockGrowEvent ev = new BlockGrowEvent(this, block);
Server.getInstance().getPluginManager().callEvent(ev);
if (!ev.isCancelled()) {
this.getLevel().setBlock(block, ev.getNewState());
this.getLevel().addSound(this.add(0.5, 0.5, 0.5), Sound.BLOCK_CHORUSFLOWER_DEATH);
} else {
return Level.BLOCK_UPDATE_RANDOM;
}
}
}
} else {
return Level.BLOCK_UPDATE_RANDOM;
}
}
return 0;
}
@Override
public boolean place(@Nonnull Item item, @Nonnull Block block, @Nonnull Block target, @Nonnull BlockFace face, double fx, double fy, double fz, @Nullable Player player) {
if (!isPositionValid()) {
return false;
}
return super.place(item, block, target, face, fx, fy, fz, player);
}
@Override
public Item[] getDrops(Item item) {
return new Item[]{ this.toItem() };
}
@Override
@PowerNukkitOnly
public boolean breaksWhenMoved() {
return true;
}
@Override
@PowerNukkitOnly
public boolean sticksToPiston() {
return false;
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
@Override
public boolean onProjectileHit(@Nonnull Entity projectile, @Nonnull Position position, @Nonnull Vector3 motion) {
if (projectile instanceof EntityArrow || projectile instanceof EntitySnowball) { // TODO: Check Fire Charge too
this.getLevel().useBreakOn(this);
projectile.kill();
return true;
}
return super.onProjectileHit(projectile, position, motion);
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
public int getMaxAge() {
return AGE.getMaxValue();
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
public int getAge() {
return getIntValue(AGE);
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
public void setAge(int age) {
setIntValue(AGE, age);
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
public boolean isFullyAged() {
return getAge() >= getMaxAge();
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
private boolean isHorizontalAir(Block block) {
for (BlockFace face : BlockFace.Plane.HORIZONTAL) {
if (block.getSide(face).getId() != AIR) {
return false;
}
}
return true;
}
@PowerNukkitOnly
@Since("1.4.0.0-PN")
private boolean isHorizontalAirExcept(Block block, BlockFace except) {
for (BlockFace face : BlockFace.Plane.HORIZONTAL) {
if (face != except) {
if (block.getSide(face).getId() != AIR) {
return false;
}
}
}
return true;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy