cn.nukkit.block.BlockPointedDripstone Maven / Gradle / Ivy
package cn.nukkit.block;
import cn.nukkit.Player;
import cn.nukkit.Server;
import cn.nukkit.api.PowerNukkitOnly;
import cn.nukkit.api.PowerNukkitXOnly;
import cn.nukkit.api.Since;
import cn.nukkit.blockproperty.ArrayBlockProperty;
import cn.nukkit.blockproperty.BlockProperties;
import cn.nukkit.blockproperty.IntBlockProperty;
import cn.nukkit.blockproperty.value.CauldronLiquid;
import cn.nukkit.blockstate.BlockState;
import cn.nukkit.entity.Entity;
import cn.nukkit.event.block.BlockFallEvent;
import cn.nukkit.event.block.CauldronFilledByDrippingLiquidEvent;
import cn.nukkit.event.entity.EntityDamageEvent;
import cn.nukkit.item.Item;
import cn.nukkit.item.ItemTool;
import cn.nukkit.level.GameRule;
import cn.nukkit.level.Level;
import cn.nukkit.level.Sound;
import cn.nukkit.math.BlockFace;
import cn.nukkit.nbt.tag.CompoundTag;
import cn.nukkit.potion.Effect;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Random;
import static cn.nukkit.potion.Effect.getEffect;
/**
* @author CoolLoong
* @since 02.13.2022
*/
@PowerNukkitOnly
@Since("FUTURE")
public class BlockPointedDripstone extends BlockFallableMeta {
@PowerNukkitXOnly
@Since("1.6.0.0-PNX")
private static final ArrayBlockProperty DRIPSTONE_THICKNESS = new ArrayBlockProperty<>("dripstone_thickness", false,
new String[]{
"base",
"frustum",
"merge",
"middle",
"tip"
}
);
@PowerNukkitXOnly
@Since("1.6.0.0-PNX")
private static final IntBlockProperty HANGING = new IntBlockProperty("hanging", false, 1, 0);
@PowerNukkitXOnly
@Since("1.6.0.0-PNX")
public static final BlockProperties PROPERTIES = new BlockProperties(DRIPSTONE_THICKNESS, HANGING);
@PowerNukkitXOnly
@Since("1.6.0.0-PNX")
public int isHanging(){
return getPropertyValue(HANGING);
}
@PowerNukkitXOnly
@Since("1.6.0.0-PNX")
public void setHanging(int value){
setPropertyValue(HANGING, value);
}
@PowerNukkitXOnly
@Since("1.6.0.0-PNX")
public void setThickness(String value){
setPropertyValue(DRIPSTONE_THICKNESS, value);
}
@PowerNukkitXOnly
@Since("1.6.0.0-PNX")
public String getThickness(){
return getPropertyValue(DRIPSTONE_THICKNESS);
}
public BlockPointedDripstone() {
}
public BlockPointedDripstone(int meta) {
super(meta);
}
@Override
public int getId() {
return POINTED_DRIPSTONE;
}
@Override
public String getName() {
return "Pointed Drip Stone";
}
@PowerNukkitXOnly
@Since("1.6.0.0-PNX")
@Nonnull
@Override
public BlockProperties getProperties() {
return PROPERTIES;
}
@Override
public boolean canBeActivated() {
return true;
}
@Override
public double getHardness() {
return 1.5;
}
@Override
public int getToolType() {
return ItemTool.TYPE_PICKAXE;
}
@Override
public double getResistance() {
return 3;
}
@PowerNukkitOnly
@Override
public int getWaterloggingLevel() {
return 1;
}
@Override
public boolean canBePushed() {
return false;
}
@PowerNukkitOnly
@Override
public boolean canBePulled() {
return false;
}
@Override
public int onUpdate(int type) {
if (type == Level.BLOCK_UPDATE_RANDOM && this.getThickness().equals("tip")){
Random rand = new Random();
double nextDouble = rand.nextDouble();
if (nextDouble <= 0.011377778){
this.grow();
}
drippingLiquid();
}
int hanging = getPropertyValue(HANGING);
if (hanging == 0) {
Block down = down();
if (!down.isSolid()) {
this.getLevel().useBreakOn(this);
}
}
tryDrop(hanging);
return 0;
}
@PowerNukkitOnly
public void tryDrop(int hanging) {
if (hanging == 0) return;
boolean AirUp = false;
Block blockUp = this.getBlock();
while (blockUp.getSide(BlockFace.UP).getId() == POINTED_DRIPSTONE) {
blockUp = blockUp.getSide(BlockFace.UP);
}
if (!blockUp.getSide(BlockFace.UP).isSolid())
AirUp = true;
if (AirUp) {
BlockFallEvent event = new BlockFallEvent(this);
Server.getInstance().getPluginManager().callEvent(event);
if (event.isCancelled()){
return;
}
BlockPointedDripstone block = (BlockPointedDripstone) blockUp;
block.drop(new CompoundTag().putBoolean("BreakOnGround", true));
while (block.getSide(BlockFace.DOWN).getId() == POINTED_DRIPSTONE) {
block = (BlockPointedDripstone) block.getSide(BlockFace.DOWN);
block.drop(new CompoundTag().putBoolean("BreakOnGround", true));
}
}
}
@Override
public boolean place(@Nullable Item item, @Nonnull Block block, @Nullable Block target, @Nonnull BlockFace face, double fx, double fy, double fz, Player player) {
int placeX = block.getFloorX();
int placeY = block.getFloorY();
int placeZ = block.getFloorZ();
int upBlockID = level.getBlockIdAt(placeX, placeY + 1, placeZ);
int downBlockID = level.getBlockIdAt(placeX, placeY - 1, placeZ);
if (upBlockID == AIR && downBlockID == AIR) return false;
/* "up" define is exist drip stone in block above,"down" is Similarly.
up down
1 yes yes
2 yes no
3 no no
4 no yes
*/
int state = (upBlockID == POINTED_DRIPSTONE) ? (downBlockID == POINTED_DRIPSTONE ? 1 : 2) : (downBlockID != POINTED_DRIPSTONE ? 3 : 4);
int hanging = 0;
switch (state) {
case 1 -> {
setMergeBlock(placeX, placeY, placeZ, 0);
setBlockThicknessStateAt(placeX, placeY + 1, placeZ, 1, "merge");
}
case 2 -> {
if (level.getBlockIdAt(placeX, placeY - 1, placeZ) != AIR) {
if (face.equals(BlockFace.UP)) {
setBlockThicknessStateAt(placeX, placeY + 1, placeZ, 1, "merge");
setMergeBlock(placeX, placeY, placeZ, 0);
} else {
setTipBlock(placeX, placeY, placeZ, 1);
setAddChange(placeX, placeY, placeZ, 1);
}
return true;
}
hanging = 1;
}
case 3 -> {
if (downBlockID != AIR) {
setTipBlock(placeX, placeY, placeZ, 0);
} else {
setTipBlock(placeX, placeY, placeZ, 1);
}
return true;
}
case 4 -> {
if (level.getBlockIdAt(placeX, placeY + 1, placeZ) != AIR) {
if (face.equals(BlockFace.DOWN)) {
setMergeBlock(placeX, placeY, placeZ, 1);
setBlockThicknessStateAt(placeX, placeY - 1, placeZ, 0, "merge");
} else {
setTipBlock(placeX, placeY, placeZ, 0);
setAddChange(placeX, placeY, placeZ, 0);
}
return true;
}
}
}
setAddChange(placeX, placeY, placeZ, hanging);
if (state == 1) return true;
setTipBlock(placeX, placeY, placeZ, hanging);
return true;
}
@Override
public boolean onBreak(Item item) {
int x = this.getFloorX();
int y = this.getFloorY();
int z = this.getFloorZ();
level.setBlock(x, y, z, Block.get(AIR), true, true);
int hanging = getPropertyValue(HANGING);
String thickness = getPropertyValue(DRIPSTONE_THICKNESS);
if (thickness.equals("merge")) {
if (hanging == 0) {
setBlockThicknessStateAt(x, y + 1, z, 1, "tip");
} else setBlockThicknessStateAt(x, y - 1, z, 0, "tip");
}
if (hanging == 0) {
int length = getPointedDripStoneLength(x, y, z, 0);
if (length > 0) {
Block downBlock = down();
for (int i = 0; i <= length - 1; ++i) {
level.setBlock(downBlock.down(i), Block.get(AIR), false, false);
}
for (int i = length - 1; i >= 0; --i) {
place(null, downBlock.down(i), null, BlockFace.DOWN, 0, 0, 0, null);
}
}
}
if (hanging == 1) {
int length = getPointedDripStoneLength(x, y, z, 1);
if (length > 0) {
Block upBlock = up();
for (int i = 0; i <= length - 1; ++i) {
level.setBlock(upBlock.up(i), Block.get(AIR), false, false);
}
for (int i = length - 1; i >= 0; --i) {
place(null, upBlock.up(i), null, BlockFace.DOWN, 0, 0, 0, null);
}
}
}
return true;
}
@Override
public void onEntityFallOn(Entity entity, float fallDistance) {
if (this.level.gameRules.getBoolean(GameRule.FALL_DAMAGE) && this.getPropertyValue(DRIPSTONE_THICKNESS).equals("tip") && this.getPropertyValue(HANGING) == 0) {
int jumpBoost = entity.hasEffect(Effect.JUMP_BOOST) ? (getEffect(Effect.JUMP_BOOST).getAmplifier() + 1) : 0;
float damage = (fallDistance - jumpBoost) * 2 - 2;
if (damage > 0)
entity.attack(new EntityDamageEvent(entity, EntityDamageEvent.DamageCause.FALL, damage));
}
}
@Since("1.6.0.0-PNX")
@PowerNukkitOnly
@Override
public boolean useDefaultFallDamage() {
return false;
}
@PowerNukkitXOnly
@Since("1.6.0.0-PNX")
protected void setTipBlock(int x, int y, int z, int hanging) {
this.setPropertyValue(DRIPSTONE_THICKNESS, "tip");
this.setPropertyValue(HANGING, hanging);
this.getLevel().setBlock(x, y, z, this, true, true);
}
@PowerNukkitXOnly
@Since("1.6.0.0-PNX")
protected void setMergeBlock(int x, int y, int z, int hanging) {
this.setPropertyValue(DRIPSTONE_THICKNESS, "merge");
this.setPropertyValue(HANGING, hanging);
this.getLevel().setBlock(x, y, z, this, true, true);
}
@PowerNukkitXOnly
@Since("1.6.0.0-PNX")
protected void setBlockThicknessStateAt(int x, int y, int z, int hanging, String thickness) {
BlockState blockState;
this.setPropertyValue(DRIPSTONE_THICKNESS, thickness);
this.setPropertyValue(HANGING, hanging);
blockState = this.getCurrentState();
level.setBlockStateAt(x, y, z, blockState);
}
@PowerNukkitXOnly
@Since("1.6.0.0-PNX")
protected int getPointedDripStoneLength(int x, int y, int z, int hanging) {
if (hanging == 1) {
for (int j = y + 1; j < 320; ++j) {
int blockId = level.getBlockIdAt(x, j, z);
if (blockId != POINTED_DRIPSTONE) {
return j - y - 1;
}
}
} else {
for (int j = y - 1; j > -64; --j) {
int blockId = level.getBlockIdAt(x, j, z);
if (blockId != POINTED_DRIPSTONE) {
return y - j - 1;
}
}
}
return 0;
}
@PowerNukkitXOnly
@Since("1.6.0.0-PNX")
protected void setAddChange(int x, int y, int z, int hanging) {
int length = getPointedDripStoneLength(x, y, z, hanging);
int k2 = (hanging == 0) ? -2 : 2;
int k1 = (hanging == 0) ? -1 : 1;
if (length == 1) {
setBlockThicknessStateAt(x, y + k1, z, hanging, "frustum");
}
if (length == 2) {
setBlockThicknessStateAt(x, y + k2, z, hanging, "base");
setBlockThicknessStateAt(x, y + k1, z, hanging, "frustum");
}
if (length >= 3) {
setBlockThicknessStateAt(x, y + k2, z, hanging, "middle");
setBlockThicknessStateAt(x, y + k1, z, hanging, "frustum");
}
}
@PowerNukkitXOnly
@Since("1.6.0.0-PNX")
public void grow() {
BlockFace face = this.isHanging() == 1 ? BlockFace.DOWN : BlockFace.UP;
Block target = this.getSide(face);
if (target.getId() == Block.AIR) {
this.place(null, target, null, face, 0, 0, 0, null);
}
}
@PowerNukkitXOnly
@Since("1.6.0.0-PNX")
public void drippingLiquid(){//features according to https://minecraft.fandom.com/zh/wiki/%E6%BB%B4%E6%B0%B4%E7%9F%B3%E9%94%A5
if (this.getBlock(this,1) instanceof BlockLiquid || !this.getThickness().equals("tip") || this.isHanging() != 1) {
return;
}
Block highestPDS = this;
int height = 1;
while(highestPDS.getSide(BlockFace.UP) instanceof BlockPointedDripstone){
highestPDS = highestPDS.getSide(BlockFace.UP);
height++;
}
boolean isWaterloggingBlock = false;
if (height >= 11 ||
!(highestPDS.getSide(BlockFace.UP,2) instanceof BlockLiquid ||
highestPDS.getSide(BlockFace.UP,2).getLevelBlockAtLayer(1).getId() == BlockID.FLOWING_WATER)
){
return;
}
if (highestPDS.getSide(BlockFace.UP,2).getLevelBlockAtLayer(1).getId() == BlockID.FLOWING_WATER){
isWaterloggingBlock = true;
}
Block tmp = this;
BlockCauldron cauldron;
while(tmp.getSide(BlockFace.DOWN) instanceof BlockAir){
tmp = tmp.getSide(BlockFace.DOWN);
}
if (tmp.getSide(BlockFace.DOWN) instanceof BlockCauldron){
cauldron = (BlockCauldron) tmp.getSide(BlockFace.DOWN);
}else{
return;
}
Random rand = new Random();
double nextDouble;
Block filledWith = isWaterloggingBlock ? highestPDS.getSideAtLayer(1,BlockFace.UP,2) : highestPDS.getSide(BlockFace.UP,2);
switch (filledWith.getId()){
case FLOWING_LAVA:
nextDouble = rand.nextDouble();
if ((cauldron.getCauldronLiquid() == CauldronLiquid.LAVA || cauldron.isEmpty()) && cauldron.getFillLevel() < 6 && nextDouble <= 15.0 / 256.0) {
CauldronFilledByDrippingLiquidEvent event = new CauldronFilledByDrippingLiquidEvent(cauldron, CauldronLiquid.LAVA,1);
Server.getInstance().getPluginManager().callEvent(event);
if(event.isCancelled())
return;
cauldron.setCauldronLiquid(event.getLiquid());
cauldron.setFillLevel(cauldron.getFillLevel() + event.getLiquidLevelIncrement());
cauldron.level.setBlock(cauldron,cauldron,true,true);
this.getLevel().addSound(this.add(0.5, 1, 0.5), Sound.CAULDRON_DRIP_LAVA_POINTED_DRIPSTONE);
}
break;
case FLOWING_WATER:
nextDouble = rand.nextDouble();
if ((cauldron.getCauldronLiquid() == CauldronLiquid.WATER || cauldron.isEmpty()) && cauldron.getFillLevel() < 6 && nextDouble <= 45.0 / 256.0) {
CauldronFilledByDrippingLiquidEvent event = new CauldronFilledByDrippingLiquidEvent(cauldron, CauldronLiquid.WATER,1);
Server.getInstance().getPluginManager().callEvent(event);
if(event.isCancelled())
return;
cauldron.setCauldronLiquid(event.getLiquid());
cauldron.setFillLevel(cauldron.getFillLevel() + event.getLiquidLevelIncrement());
cauldron.level.setBlock(cauldron,cauldron,true,true);
this.getLevel().addSound(this.add(0.5, 1, 0.5), Sound.CAULDRON_DRIP_WATER_POINTED_DRIPSTONE);
}
break;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy