All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.nukkit.block.BlockBigDripleaf 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.*;
import cn.nukkit.entity.Entity;
import cn.nukkit.entity.projectile.EntityProjectile;
import cn.nukkit.event.block.BigDripleafTiltChangeEvent;
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.level.particle.BoneMealParticle;
import cn.nukkit.math.AxisAlignedBB;
import cn.nukkit.math.BlockFace;
import cn.nukkit.math.SimpleAxisAlignedBB;
import cn.nukkit.math.Vector3;
import cn.nukkit.utils.BlockColor;
import cn.nukkit.utils.Faceable;
import org.jetbrains.annotations.NotNull;

import javax.annotation.Nullable;

import static cn.nukkit.block.BlockBigDripleaf.Tilt.*;

@PowerNukkitXOnly
@Since("1.6.0.0-PNX")
public class BlockBigDripleaf extends BlockFlowable implements Faceable {

    @PowerNukkitXOnly
    @Since("1.6.0.0-PNX")
    public static final BlockProperty TILT = new ArrayBlockProperty<>("big_dripleaf_tilt", false, new Tilt[]{Tilt.NONE, PARTIAL_TILT, Tilt.FULL_TILT, Tilt.UNSTABLE});

    @PowerNukkitXOnly
    @Since("1.6.0.0-PNX")
    public static final BooleanBlockProperty HEAD = new BooleanBlockProperty("big_dripleaf_head", false);

    @PowerNukkitXOnly
    @Since("1.6.0.0-PNX")
    public static final BlockProperties PROPERTIES = new BlockProperties(CommonBlockProperties.DIRECTION, TILT, HEAD);

    protected BlockBigDripleaf() {
        super(0);
    }

    @Override
    public String getName() {
        return "Big Dripleaf";
    }

    @Override
    public int getId() {
        return BlockID.BIG_DRIPLEAF;
    }

    @Since("1.6.0.0-PNX")
    @PowerNukkitOnly
    @NotNull
    @Override
    public BlockProperties getProperties() {
        return PROPERTIES;
    }

    @Override
    public BlockFace getBlockFace() {
        return getPropertyValue(CommonBlockProperties.DIRECTION);
    }

    @Since("1.6.0.0-PNX")
    @PowerNukkitOnly
    @Override
    public void setBlockFace(BlockFace face) {
        setPropertyValue(CommonBlockProperties.DIRECTION, face);
    }

    public boolean isHead() {
        return this.getBooleanValue(HEAD);
    }

    public void setHead(boolean isHead) {
        this.setBooleanValue(HEAD, isHead);
    }

    public Tilt getTilt() {
        return this.getPropertyValue(TILT);
    }

    public boolean setTilt(Tilt tilt) {
        BigDripleafTiltChangeEvent event = new BigDripleafTiltChangeEvent(this, this.getTilt(), tilt);
        Server.getInstance().getPluginManager().callEvent(event);
        if (event.isCancelled()) return false;
        this.setPropertyValue(TILT, tilt);
        return true;
    }

    @PowerNukkitOnly
    @Override
    public int getWaterloggingLevel() {
        return 2;
    }

    @Override
    public int getToolType() {
        return ItemTool.TYPE_NONE;
    }

    @Override
    public boolean canBeActivated() {
        return true;
    }

    @Override
    public double getHardness() {
        return 0;
    }

    @Override
    public double getResistance() {
        return 0;
    }

    @Override
    public int getBurnChance() {
        return 15;
    }

    @Override
    public int getBurnAbility() {
        return 100;
    }

    @Override
    public boolean place(@NotNull Item item, @NotNull Block block, @NotNull Block target, @NotNull BlockFace face, double fx, double fy, double fz, @Nullable Player player) {
        Block below = block.down();
        int id = below.getId();
        if (!isValidSupportBlock(id))
            return false;

        if (id == BIG_DRIPLEAF) {
            var b = new BlockBigDripleaf();
            var bf = ((BlockBigDripleaf) below).getBlockFace();
            b.setBlockFace(bf);
            b.setHead(false);
            level.setBlock(below, b, true, false);
            setHead(true);
            setBlockFace(bf);
        } else {
            setBlockFace(player.getHorizontalFacing().getOpposite());
            setHead(true);
        }

        if (block instanceof BlockWater)
            level.setBlock(this, 1, block, true, false);
        return super.place(item, block, target, face, fx, fy, fz, player);
    }

    @Override
    public boolean onActivate(@NotNull Item item, @org.jetbrains.annotations.Nullable Player player) {
        if (item.isFertilizer()) {
            Block head = this;
            Block up;
            while ((up = head.up()).getId() == BIG_DRIPLEAF)
                head = up;
            if (head.getFloorY() + 1 >= level.getMaxHeight())
                return false;
            Block above = head.up();
            if (!(above.getId() == AIR) && !(above instanceof BlockWater))
                return false;
            if (player != null && !player.isCreative())
                item.count--;
            level.addParticle(new BoneMealParticle(this));
            var aboveDownBlock = new BlockBigDripleaf();
            aboveDownBlock.setBlockFace(this.getBlockFace());
            level.setBlock(above.getSideVec(BlockFace.DOWN), aboveDownBlock, true, false);
            if (above instanceof BlockWater)
                level.setBlock(above, 1, above, true, false);
            var aboveBock = new BlockBigDripleaf();
            aboveBock.setBlockFace(this.getBlockFace());
            aboveBock.setHead(true);
            level.setBlock(above, aboveBock, true);
            return true;
        }

        return false;
    }

    @Override
    public int onUpdate(int type) {
        if (type == Level.BLOCK_UPDATE_NORMAL) {
            level.scheduleUpdate(this, 1);
            return Level.BLOCK_UPDATE_NORMAL;
        }

        if (type == Level.BLOCK_UPDATE_SCHEDULED) {
            if (!canSurvive()) {
                level.useBreakOn(this);
                return Level.BLOCK_UPDATE_NORMAL;
            }

            if (!isHead()) {
                if (up().getId() == BIG_DRIPLEAF) {
                    return 0;
                }

                level.useBreakOn(this);
                return Level.BLOCK_UPDATE_NORMAL;
            }

            var tilt = getTilt();
            if (tilt == Tilt.NONE) {
                return 0;
            }

            if (level.isBlockPowered(this)) {
                setTilt(Tilt.NONE);
                level.setBlock(this, this, true, false);
                return Level.BLOCK_UPDATE_SCHEDULED;
            }

            switch (tilt) {
                case UNSTABLE -> setTiltAndScheduleTick(PARTIAL_TILT);
                case PARTIAL_TILT -> setTiltAndScheduleTick(FULL_TILT);
                case FULL_TILT -> {
                    level.addSound(this, Sound.TILT_UP_BIG_DRIPLEAF);
                    setTilt(NONE);
                    level.setBlock(this, this, true, false);
                }
            }
            return Level.BLOCK_UPDATE_SCHEDULED;
        }

        if (type == Level.BLOCK_UPDATE_REDSTONE) {
            if (!isHead())
                return 0;
            var tilt = getTilt();
            if (tilt == NONE)
                return 0;
            if (!level.isBlockPowered(this))
                return 0;
            if (tilt != UNSTABLE)
                level.addSound(this, Sound.TILT_UP_BIG_DRIPLEAF);
            setTilt(NONE);
            level.setBlock(this, this, true, false);

            level.cancelSheduledUpdate(this, this);
            return Level.BLOCK_UPDATE_SCHEDULED;
        }

        return 0;
    }

    @Override
    public boolean hasEntityCollision() {
        return true;
    }

    @Override
    public void onEntityCollide(Entity entity) {
        if (!isHead() || getTilt() != NONE || entity instanceof EntityProjectile) return;
        setTiltAndScheduleTick(UNSTABLE);
    }

    @Override
    public Item[] getDrops(Item item) {
        return new Item[]{new BlockSmallDripleaf().toItem()};
    }

    @Since("1.4.0.0-PN")
    @PowerNukkitOnly
    @Override
    public boolean onProjectileHit(@NotNull Entity projectile, @NotNull Position position, @NotNull Vector3 motion) {
        setTiltAndScheduleTick(FULL_TILT);
        return true;
    }

    @Override
    public boolean canPassThrough() {
        return !isHead() || getTilt() == FULL_TILT;
    }

    @Override
    protected AxisAlignedBB recalculateBoundingBox() {
        if (!isHead()) {
            //杆没有碰撞箱
//            var face = this.getBlockFace().getOpposite();
            return /*new SimpleAxisAlignedBB(
                    0.3125,
                    0,
                    0.3125,
                    0.6875,
                    1,
                    0.6875)
                    .offset(
                            this.x + face.getXOffset() * 0.1875,
                            this.y,
                            this.z + face.getZOffset() * 0.1875
                    );*/null;
        } else {
            return new SimpleAxisAlignedBB(
                    this.x,
                    this.y + 0.6875,
                    this.z,
                    this.x + 1,
                    this.y + (getTilt() == PARTIAL_TILT ? 0.8125 : 0.9375),
                    this.z + 1
            );
        }
    }

    @Override
    protected AxisAlignedBB recalculateCollisionBoundingBox() {
        var bb = getBoundingBox();
        //使方块碰撞检测箱的maxY向上取整,使当实体站在方块上面的时候可以触发碰撞
        if (isHead())
            bb.setMaxY(Math.ceil(bb.getMaxY()));
        return bb;
    }

    @Since("1.3.0.0-PN")
    @PowerNukkitOnly
    @Override
    public boolean isSolid(BlockFace side) {
        return false;
    }

    @Override
    public BlockColor getColor() {
        return BlockColor.FOLIAGE_BLOCK_COLOR;
    }

    private boolean canSurvive() {
        return isValidSupportBlock(down().getId());
    }

    private boolean isValidSupportBlock(int id) {
        return id == BIG_DRIPLEAF || id == GRASS || id == DIRT || id == MYCELIUM || id == PODZOL || id == FARMLAND || id == DIRT_WITH_ROOTS || id == MOSS_BLOCK || id == CLAY_BLOCK;
    }

    private boolean setTiltAndScheduleTick(Tilt tilt) {
        if (!setTilt(tilt))
            return false;
        level.setBlock(this, this, true, false);

        switch (tilt) {
            case NONE -> level.scheduleUpdate(this, 1);
            case UNSTABLE -> {
                level.scheduleUpdate(this, 15);
                return true;
            }
            case PARTIAL_TILT -> level.scheduleUpdate(this, 15);
            case FULL_TILT -> level.scheduleUpdate(this, 100);
        }

        level.addSound(this, Sound.TILT_DOWN_BIG_DRIPLEAF);
        return true;
    }

    public enum Tilt {
        NONE,
        UNSTABLE,
        PARTIAL_TILT,
        FULL_TILT
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy