From 538c819c7651c7670815fdd487de0e4487548f48 Mon Sep 17 00:00:00 2001 From: CreeperFace Date: Fri, 16 Aug 2019 11:52:17 +0200 Subject: [PATCH] Broken pistons implementation --- src/main/java/cn/nukkit/Server.java | 1 + src/main/java/cn/nukkit/block/Block.java | 7 +- src/main/java/cn/nukkit/block/BlockID.java | 2 +- src/main/java/cn/nukkit/block/BlockLever.java | 1 + .../java/cn/nukkit/block/BlockMoving.java | 34 +++ .../java/cn/nukkit/block/BlockPistonBase.java | 197 +++++++++++------- .../java/cn/nukkit/block/BlockPistonHead.java | 14 +- .../cn/nukkit/block/BlockRedstoneDiode.java | 7 + .../cn/nukkit/block/BlockRedstoneWire.java | 13 +- .../cn/nukkit/blockentity/BlockEntity.java | 7 +- .../blockentity/BlockEntityMovingBlock.java | 44 ++-- .../blockentity/BlockEntityPistonArm.java | 170 ++++++++++++--- .../blockentity/BlockEntitySpawnable.java | 22 +- .../cn/nukkit/level/GlobalBlockPalette.java | 16 +- src/main/java/cn/nukkit/level/Level.java | 1 + .../java/cn/nukkit/nbt/tag/CompoundTag.java | 13 +- src/main/java/cn/nukkit/nbt/tag/Tag.java | 4 +- src/main/java/cn/nukkit/network/Network.java | 5 +- 18 files changed, 404 insertions(+), 154 deletions(-) create mode 100644 src/main/java/cn/nukkit/block/BlockMoving.java diff --git a/src/main/java/cn/nukkit/Server.java b/src/main/java/cn/nukkit/Server.java index 631d6e1954b..b5db3136613 100644 --- a/src/main/java/cn/nukkit/Server.java +++ b/src/main/java/cn/nukkit/Server.java @@ -2329,6 +2329,7 @@ private void registerBlockEntities() { BlockEntity.registerBlockEntity(BlockEntity.BANNER, BlockEntityBanner.class); BlockEntity.registerBlockEntity(BlockEntity.MUSIC, BlockEntityMusic.class); BlockEntity.registerBlockEntity(BlockEntity.DISPENSER, BlockEntityDispenser.class); + BlockEntity.registerBlockEntity(BlockEntity.MOVING_BLOCK, BlockEntityMovingBlock.class); } public boolean isNetherAllowed() { diff --git a/src/main/java/cn/nukkit/block/Block.java b/src/main/java/cn/nukkit/block/Block.java index f0e38669b50..8246d3eba8a 100644 --- a/src/main/java/cn/nukkit/block/Block.java +++ b/src/main/java/cn/nukkit/block/Block.java @@ -296,8 +296,7 @@ public static void init() { list[GLOWING_OBSIDIAN] = BlockObsidianGlowing.class; //246 //list[NETHER_REACTOR] = BlockNetherReactor.class; //247 Should not be removed - //TODO: list[PISTON_EXTENSION] = BlockPistonExtension.class; //250 - + list[MOVING_BLOCK] = BlockMoving.class; //250 list[OBSERVER] = BlockObserver.class; //251 for (int id = 0; id < 256; id++) { @@ -691,6 +690,10 @@ public Block getSide(BlockFace face) { } public Block getSide(BlockFace face, int step) { + if (step == 0) { + return this; + } + if (this.isValid()) { if (step == 1) { return this.getLevel().getBlock((int) x + face.getXOffset(), (int) y + face.getYOffset(), (int) z + face.getZOffset()); diff --git a/src/main/java/cn/nukkit/block/BlockID.java b/src/main/java/cn/nukkit/block/BlockID.java index 9673b523c7d..2df1d9b9a04 100644 --- a/src/main/java/cn/nukkit/block/BlockID.java +++ b/src/main/java/cn/nukkit/block/BlockID.java @@ -302,7 +302,7 @@ public interface BlockID { int GLOWING_OBSIDIAN = 246; int NETHER_REACTOR = 247; //Should not be removed - int PISTON_EXTENSION = 250; + int MOVING_BLOCK = 250; int OBSERVER = 251; } diff --git a/src/main/java/cn/nukkit/block/BlockLever.java b/src/main/java/cn/nukkit/block/BlockLever.java index 32a858fadd5..9556ca13545 100644 --- a/src/main/java/cn/nukkit/block/BlockLever.java +++ b/src/main/java/cn/nukkit/block/BlockLever.java @@ -75,6 +75,7 @@ public boolean onActivate(Item item, Player player) { Block target = this.getSide(face.getOpposite()); target.onUpdate(Level.BLOCK_UPDATE_REDSTONE); + this.level.updateAroundRedstone(this.getLocation(), isPowerOn() ? face.getOpposite() : null); this.level.updateAroundRedstone(target.getLocation(), isPowerOn() ? face : null); return true; } diff --git a/src/main/java/cn/nukkit/block/BlockMoving.java b/src/main/java/cn/nukkit/block/BlockMoving.java new file mode 100644 index 00000000000..c693449632b --- /dev/null +++ b/src/main/java/cn/nukkit/block/BlockMoving.java @@ -0,0 +1,34 @@ +package cn.nukkit.block; + +import cn.nukkit.item.Item; + +public class BlockMoving extends Block { + + public BlockMoving() { + this(0); + } + + public BlockMoving(int meta) { + super(); + } + + @Override + public String getName() { + return "MovingBlock"; + } + + @Override + public int getId() { + return BlockID.MOVING_BLOCK; + } + + @Override + public boolean canBePushed() { + return false; + } + + @Override + public boolean isBreakable(Item item) { + return false; + } +} diff --git a/src/main/java/cn/nukkit/block/BlockPistonBase.java b/src/main/java/cn/nukkit/block/BlockPistonBase.java index 3fc7ed0616d..64be0c5a547 100644 --- a/src/main/java/cn/nukkit/block/BlockPistonBase.java +++ b/src/main/java/cn/nukkit/block/BlockPistonBase.java @@ -2,10 +2,12 @@ import cn.nukkit.Player; import cn.nukkit.blockentity.BlockEntity; +import cn.nukkit.blockentity.BlockEntityMovingBlock; import cn.nukkit.blockentity.BlockEntityPistonArm; import cn.nukkit.event.block.BlockPistonChangeEvent; import cn.nukkit.item.Item; import cn.nukkit.item.ItemBlock; +import cn.nukkit.level.GlobalBlockPalette; import cn.nukkit.level.Level; import cn.nukkit.math.BlockFace; import cn.nukkit.math.Vector3; @@ -14,14 +16,16 @@ import cn.nukkit.utils.Faceable; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; /** * @author CreeperFace */ public abstract class BlockPistonBase extends BlockSolidMeta implements Faceable { - public boolean sticky; + public boolean sticky = false; public BlockPistonBase() { this(0); @@ -56,18 +60,19 @@ public boolean place(Item item, Block block, Block target, BlockFace face, doubl } else { this.setDamage(player.getHorizontalFacing().getIndex()); } - this.level.setBlock(block, this, true, false); + this.level.setBlock(block, this, true, true); CompoundTag nbt = new CompoundTag("") .putString("id", BlockEntity.PISTON_ARM) .putInt("x", (int) this.x) .putInt("y", (int) this.y) .putInt("z", (int) this.z) + .putInt("facing", this.getBlockFace().getIndex()) .putBoolean("Sticky", this.sticky); - BlockEntityPistonArm be = new BlockEntityPistonArm(this.level.getChunk(getChunkX(), getChunkZ()), nbt); + new BlockEntityPistonArm(this.level.getChunk(getChunkX(), getChunkZ()), nbt); - //this.checkState(); + this.checkState(null); return true; } @@ -75,34 +80,40 @@ public boolean place(Item item, Block block, Block target, BlockFace face, doubl public boolean onBreak(Item item) { this.level.setBlock(this, new BlockAir(), true, true); - Block block = this.getSide(getFacing()); + Block block = this.getSide(getBlockFace()); - if (block instanceof BlockPistonHead && ((BlockPistonHead) block).getFacing() == this.getFacing()) { + if (block instanceof BlockPistonHead && ((BlockPistonHead) block).getBlockFace() == this.getBlockFace()) { block.onBreak(item); } return true; } public boolean isExtended() { - BlockFace face = getFacing(); + BlockFace face = getBlockFace(); Block block = getSide(face); - return block instanceof BlockPistonHead && ((BlockPistonHead) block).getFacing() == face; + + return block instanceof BlockPistonHead && ((BlockPistonHead) block).getBlockFace() == face; } @Override public int onUpdate(int type) { - if (type != 6 && type != 1) { + if (type != Level.BLOCK_UPDATE_NORMAL && type != Level.BLOCK_UPDATE_REDSTONE && type != Level.BLOCK_UPDATE_SCHEDULED) { return 0; } else { BlockEntity blockEntity = this.level.getBlockEntity(this); if (blockEntity instanceof BlockEntityPistonArm) { BlockEntityPistonArm arm = (BlockEntityPistonArm) blockEntity; boolean powered = this.isPowered(); + if (arm.powered != powered) { this.level.getServer().getPluginManager().callEvent(new BlockPistonChangeEvent(this, powered ? 0 : 15, powered ? 15 : 0)); - arm.powered = !arm.powered; - if (arm.chunk != null) { - arm.chunk.setChanged(); + + if (checkState(powered)) { + arm.powered = powered; + + if (arm.chunk != null) { + arm.chunk.setChanged(); + } } } } @@ -111,46 +122,46 @@ public int onUpdate(int type) { } } - private void checkState() { - BlockFace facing = getFacing(); - boolean isPowered = this.isPowered(); + private boolean checkState(Boolean isPowered) { + BlockFace facing = getBlockFace(); + if (isPowered == null) { + isPowered = this.isPowered(); + } if (isPowered && !isExtended()) { - if ((new BlocksCalculator(this.level, this, facing, true)).canMove()) { + if ((new BlocksCalculator(true)).canMove()) { if (!this.doMove(true)) { - return; + return false; } this.getLevel().addLevelSoundEvent(this, LevelSoundEventPacket.SOUND_PISTON_OUT); - } else { + return true; } } else if (!isPowered && isExtended()) { - //this.level.setBlock() TODO: set piston extension? - if (this.sticky) { - Vector3 pos = this.add(facing.getXOffset() * 2, facing.getYOffset() * 2, facing.getZOffset() * 2); + Vector3 pos = this.add(0).getSide(facing, 2); Block block = this.level.getBlock(pos); - if (block.getId() == AIR) { - this.level.setBlock(this.getLocation().getSide(facing), new BlockAir(), true, true); - } if (canPush(block, facing.getOpposite(), false) && (!(block instanceof BlockFlowable) || block.getId() == PISTON || block.getId() == STICKY_PISTON)) { - this.doMove(false); + if (!this.doMove(false)) { + return false; + } + } else { + return false; } - } else { - this.level.setBlock(getLocation().getSide(facing), new BlockAir(), true, false); + } else if (!this.doMove(false)) { + return false; } this.getLevel().addLevelSoundEvent(this, LevelSoundEventPacket.SOUND_PISTON_IN); + return true; } - } - public BlockFace getFacing() { - return BlockFace.fromIndex(this.getDamage()).getOpposite(); + return false; } private boolean isPowered() { - BlockFace face = getFacing(); + BlockFace face = getBlockFace(); for (BlockFace side : BlockFace.values()) { if (side != face && this.level.isSidePowered(this.getLocation().getSide(side), side)) { @@ -174,47 +185,69 @@ private boolean isPowered() { } private boolean doMove(boolean extending) { - Vector3 pos = this.getLocation(); - BlockFace direction = getFacing(); - - if (!extending) { - this.level.setBlock(pos.getSide(direction), new BlockAir(), true, false); - } - - BlocksCalculator calculator = new BlocksCalculator(this.level, this, direction, extending); + BlockFace direction = getBlockFace(); + BlocksCalculator calculator = new BlocksCalculator(extending); if (!calculator.canMove()) { return false; } else { - List blocks = calculator.getBlocksToMove(); + List attached = Collections.emptyList(); - List newBlocks = new ArrayList<>(blocks); + if (this.sticky || extending) { + List destroyBlocks = calculator.getBlocksToDestroy(); + for (int i = destroyBlocks.size() - 1; i >= 0; --i) { + Block block = destroyBlocks.get(i); + this.level.useBreakOn(block, null, null, false); + } - List destroyBlocks = calculator.getBlocksToDestroy(); - BlockFace side = extending ? direction : direction.getOpposite(); + List newBlocks = calculator.getBlocksToMove(); + attached = newBlocks.stream().map(b -> b.add(0)).collect(Collectors.toList()); - for (int i = destroyBlocks.size() - 1; i >= 0; --i) { - Block block = destroyBlocks.get(i); - this.level.useBreakOn(block); - } + BlockFace side = extending ? direction : direction.getOpposite(); - for (int i = blocks.size() - 1; i >= 0; --i) { - Block block = blocks.get(i); - this.level.setBlock(block, new BlockAir()); - Vector3 newPos = block.getLocation().getSide(side); + for (Block newBlock : newBlocks) { + Vector3 oldPos = newBlock.add(0); + newBlock.position(newBlock.add(0).getSide(side)); - //TODO: change this to block entity - this.level.setBlock(newPos, newBlocks.get(i)); - } + BlockEntity blockEntity = this.level.getBlockEntity(oldPos); - Vector3 pistonHead = pos.getSide(direction); + this.level.setBlock(newBlock, Block.get(BlockID.MOVING_BLOCK)); - if (extending) { - //extension block entity + CompoundTag nbt = BlockEntity.getDefaultCompound(newBlock, BlockEntity.MOVING_BLOCK) + .putInt("pistonPosX", this.getFloorX()) + .putInt("pistonPosY", this.getFloorY()) + .putInt("pistonPosZ", this.getFloorZ()) + .putCompound("movingBlock", new CompoundTag() + .putInt("id", newBlock.getId()) //only for nukkit purpose + .putInt("meta", newBlock.getDamage()) //only for nukkit purpose + .putShort("val", newBlock.getDamage()) + .putString("name", GlobalBlockPalette.getName(newBlock.getId(), newBlock.getDamage())) + ); + + if (blockEntity != null) { + blockEntity.saveNBT(); + + CompoundTag t = new CompoundTag(blockEntity.namedTag.getTags()); + t.print(System.out); + + nbt.putCompound("movingEntity", t); + blockEntity.close(); + } + + new BlockEntityMovingBlock(this.level.getChunk(newBlock.getChunkX(), newBlock.getChunkZ()), nbt); - this.level.setBlock(pistonHead, new BlockPistonHead(this.getDamage())); + if (this.level.getBlockIdAt(oldPos.getFloorX(), oldPos.getFloorY(), oldPos.getFloorZ()) != BlockID.MOVING_BLOCK) { + this.level.setBlock(oldPos, Block.get(BlockID.AIR)); + } + } } + if (extending) { + this.level.setBlock(this.getSide(direction), new BlockPistonHead(this.getDamage())); + } + + BlockEntityPistonArm blockEntity = (BlockEntityPistonArm) this.level.getBlockEntity(this); + blockEntity.move(extending, attached); return true; } } @@ -222,38 +255,42 @@ private boolean doMove(boolean extending) { public static boolean canPush(Block block, BlockFace face, boolean destroyBlocks) { if (block.canBePushed() && block.getY() >= 0 && (face != BlockFace.DOWN || block.getY() != 0) && block.getY() <= 255 && (face != BlockFace.UP || block.getY() != 255)) { - if (!(block instanceof BlockPistonBase)) { - if (block instanceof BlockFlowable) { - return destroyBlocks; - } - } else return !((BlockPistonBase) block).isExtended(); - return true; + if (block instanceof BlockFlowable) { + return destroyBlocks; + } + + BlockEntity be = block.level.getBlockEntity(block); + return be == null || be.isMovable(); } - return false; + return false; } public class BlocksCalculator { - private final Level level; private final Vector3 pistonPos; + private Vector3 armPos; private final Block blockToMove; private final BlockFace moveDirection; private final List toMove = new ArrayList<>(); private final List toDestroy = new ArrayList<>(); - public BlocksCalculator(Level level, Block pos, BlockFace facing, boolean extending) { - this.level = level; - this.pistonPos = pos.getLocation(); + public BlocksCalculator(boolean extending) { + this.pistonPos = getLocation(); + + BlockFace face = getBlockFace(); + if (!extending) { + this.armPos = pistonPos.getSide(face); + } if (extending) { - this.moveDirection = facing; - this.blockToMove = pos.getSide(facing); + this.moveDirection = face; + this.blockToMove = getSide(face); } else { - this.moveDirection = facing.getOpposite(); - this.blockToMove = pos.getSide(facing, 2); + this.moveDirection = face.getOpposite(); + this.blockToMove = getSide(face, 2); } } @@ -272,7 +309,7 @@ public boolean canMove() { } else if (!this.addBlockLine(this.blockToMove)) { return false; } else { - for (Block b : this.toMove) { + for (Block b : new ArrayList<>(this.toMove)) { if (b.getId() == SLIME_BLOCK && !this.addBranchingBlocks(b)) { return false; } @@ -315,15 +352,15 @@ private boolean addBlockLine(Block origin) { int blockCount = 0; - for (int step = count - 1; step >= 0; --step) { - this.toMove.add(block.getSide(this.moveDirection.getOpposite(), step)); + for (int step = count - 1; step >= 0; step--) { + this.toMove.add(origin.getSide(this.moveDirection.getOpposite(), step)); ++blockCount; } int steps = 1; while (true) { - Block nextBlock = block.getSide(this.moveDirection, steps); + Block nextBlock = origin.getSide(this.moveDirection, steps); int index = this.toMove.indexOf(nextBlock); if (index > -1) { @@ -340,7 +377,7 @@ private boolean addBlockLine(Block origin) { return true; } - if (nextBlock.getId() == AIR) { + if (nextBlock.getId() == AIR || nextBlock.equals(armPos)) { return true; } @@ -401,6 +438,8 @@ public Item toItem() { @Override public BlockFace getBlockFace() { - return BlockFace.fromHorizontalIndex(this.getDamage() & 0x07); + BlockFace face = BlockFace.fromIndex(this.getDamage()); + + return face.getHorizontalIndex() >= 0 ? face.getOpposite() : face; } } diff --git a/src/main/java/cn/nukkit/block/BlockPistonHead.java b/src/main/java/cn/nukkit/block/BlockPistonHead.java index 444ade01612..064d9d3cfdd 100644 --- a/src/main/java/cn/nukkit/block/BlockPistonHead.java +++ b/src/main/java/cn/nukkit/block/BlockPistonHead.java @@ -3,11 +3,12 @@ import cn.nukkit.item.Item; import cn.nukkit.item.ItemBlock; import cn.nukkit.math.BlockFace; +import cn.nukkit.utils.Faceable; /** * @author CreeperFace */ -public class BlockPistonHead extends BlockTransparentMeta { +public class BlockPistonHead extends BlockTransparentMeta implements Faceable { public BlockPistonHead() { this(0); @@ -45,16 +46,19 @@ public Item[] getDrops(Item item) { @Override public boolean onBreak(Item item) { this.level.setBlock(this, new BlockAir(), true, true); - Block piston = getSide(getFacing().getOpposite()); + Block piston = getSide(getBlockFace().getOpposite()); - if (piston instanceof BlockPistonBase && ((BlockPistonBase) piston).getFacing() == this.getFacing()) { + if (piston instanceof BlockPistonBase && ((BlockPistonBase) piston).getBlockFace() == this.getBlockFace()) { piston.onBreak(item); } return true; } - public BlockFace getFacing() { - return BlockFace.fromIndex(this.getDamage()).getOpposite(); + @Override + public BlockFace getBlockFace() { + BlockFace face = BlockFace.fromIndex(this.getDamage()); + + return face.getHorizontalIndex() >= 0 ? face.getOpposite() : face; } @Override diff --git a/src/main/java/cn/nukkit/block/BlockRedstoneDiode.java b/src/main/java/cn/nukkit/block/BlockRedstoneDiode.java index c0ea26af643..795d5752ca6 100644 --- a/src/main/java/cn/nukkit/block/BlockRedstoneDiode.java +++ b/src/main/java/cn/nukkit/block/BlockRedstoneDiode.java @@ -4,7 +4,9 @@ import cn.nukkit.event.redstone.RedstoneUpdateEvent; import cn.nukkit.item.Item; import cn.nukkit.level.Level; +import cn.nukkit.math.AxisAlignedBB; import cn.nukkit.math.BlockFace; +import cn.nukkit.math.SimpleAxisAlignedBB; import cn.nukkit.math.Vector3; import cn.nukkit.utils.Faceable; @@ -199,6 +201,11 @@ public boolean isFacingTowardsRepeater() { return block instanceof BlockRedstoneDiode && ((BlockRedstoneDiode) block).getFacing() != side; } + @Override + protected AxisAlignedBB recalculateBoundingBox() { + return new SimpleAxisAlignedBB(this.x, this.y, this.z, this.x + 1, this.y + 0.125, this.z + 1); + } + @Override public BlockFace getBlockFace() { return BlockFace.fromHorizontalIndex(this.getDamage() & 0x07); diff --git a/src/main/java/cn/nukkit/block/BlockRedstoneWire.java b/src/main/java/cn/nukkit/block/BlockRedstoneWire.java index d407381f4ba..b3f10b312f2 100644 --- a/src/main/java/cn/nukkit/block/BlockRedstoneWire.java +++ b/src/main/java/cn/nukkit/block/BlockRedstoneWire.java @@ -44,7 +44,12 @@ public int getId() { @Override public boolean place(Item item, Block block, Block target, BlockFace face, double fx, double fy, double fz, Player player) { - if (face != BlockFace.UP || !canBePlacedOn(target)) { + if (target.canBeReplaced()) { + block = target; + target = target.down(); + } + + if (!canBePlacedOn(target)) { return false; } @@ -207,7 +212,7 @@ public int onUpdate(int type) { return 0; } - if (type == Level.BLOCK_UPDATE_NORMAL && !this.canBePlacedOn(this.getLocation().down())) { + if (type == Level.BLOCK_UPDATE_NORMAL && !this.canBePlacedOn(this.down())) { this.getLevel().useBreakOn(this); return Level.BLOCK_UPDATE_NORMAL; } @@ -217,9 +222,7 @@ public int onUpdate(int type) { return Level.BLOCK_UPDATE_NORMAL; } - public boolean canBePlacedOn(Vector3 v) { - Block b = this.level.getBlock(v); - + public boolean canBePlacedOn(Block b) { return b.isSolid() && !b.isTransparent() && b.getId() != Block.GLOWSTONE; } diff --git a/src/main/java/cn/nukkit/blockentity/BlockEntity.java b/src/main/java/cn/nukkit/blockentity/BlockEntity.java index 41a2587d9e7..b86775a48fe 100644 --- a/src/main/java/cn/nukkit/blockentity/BlockEntity.java +++ b/src/main/java/cn/nukkit/blockentity/BlockEntity.java @@ -77,7 +77,12 @@ public BlockEntity(FullChunk chunk, CompoundTag nbt) { this.x = this.namedTag.getInt("x"); this.y = this.namedTag.getInt("y"); this.z = this.namedTag.getInt("z"); - this.movable = this.namedTag.getBoolean("isMovable"); + + if (namedTag.contains("isMovable")) { + this.movable = this.namedTag.getBoolean("isMovable"); + } else { + this.movable = true; + } this.initBlockEntity(); diff --git a/src/main/java/cn/nukkit/blockentity/BlockEntityMovingBlock.java b/src/main/java/cn/nukkit/blockentity/BlockEntityMovingBlock.java index 564a9649fb4..eec12f3412f 100644 --- a/src/main/java/cn/nukkit/blockentity/BlockEntityMovingBlock.java +++ b/src/main/java/cn/nukkit/blockentity/BlockEntityMovingBlock.java @@ -1,6 +1,7 @@ package cn.nukkit.blockentity; import cn.nukkit.block.Block; +import cn.nukkit.block.BlockID; import cn.nukkit.level.format.FullChunk; import cn.nukkit.math.BlockVector3; import cn.nukkit.nbt.tag.CompoundTag; @@ -10,10 +11,10 @@ */ public class BlockEntityMovingBlock extends BlockEntitySpawnable { - public Block block; + protected String blockString; + protected Block block; - public BlockVector3 piston; - public int progress; + protected BlockVector3 piston; public BlockEntityMovingBlock(FullChunk chunk, CompoundTag nbt) { super(chunk, nbt); @@ -21,8 +22,11 @@ public BlockEntityMovingBlock(FullChunk chunk, CompoundTag nbt) { @Override protected void initBlockEntity() { - if (namedTag.contains("movingBlockData") && namedTag.contains("movingBlockId")) { - this.block = Block.get(namedTag.getInt("movingBlockId"), namedTag.getInt("movingBlockData")); + if (namedTag.contains("movingBlock")) { + CompoundTag blockData = namedTag.getCompound("movingBlock"); + + this.blockString = blockData.getString("name"); + this.block = Block.get(blockData.getInt("id"), blockData.getInt("meta")); } else { this.close(); } @@ -30,28 +34,34 @@ protected void initBlockEntity() { if (namedTag.contains("pistonPosX") && namedTag.contains("pistonPosY") && namedTag.contains("pistonPosZ")) { this.piston = new BlockVector3(namedTag.getInt("pistonPosX"), namedTag.getInt("pistonPosY"), namedTag.getInt("pistonPosZ")); } else { - this.close(); + this.piston = new BlockVector3(0, -1, 0); } super.initBlockEntity(); } - public Block getBlock() { + public CompoundTag getBlockEntity() { + if (this.namedTag.contains("movingEntity")) { + return this.namedTag.getCompound("movingEntity"); + } + + return null; + } + + public Block getMovingBlock() { return this.block; } - @Override - public boolean isBlockEntityValid() { - return true; + public String getMovingBlockString() { + return this.blockString; + } + + public void moveCollidedEntities(BlockEntityPistonArm piston) { + } @Override - public CompoundTag getSpawnCompound() { - return getDefaultCompound(this, MOVING_BLOCK) - .putFloat("movingBlockId", this.block.getId()) - .putFloat("movingBlockData", this.block.getDamage()) - .putInt("pistonPosX", this.piston.x) - .putInt("pistonPosY", this.piston.y) - .putInt("pistonPosZ", this.piston.z); + public boolean isBlockEntityValid() { + return this.level.getBlockIdAt(getFloorX(), getFloorY(), getFloorZ()) == BlockID.MOVING_BLOCK; } } diff --git a/src/main/java/cn/nukkit/blockentity/BlockEntityPistonArm.java b/src/main/java/cn/nukkit/blockentity/BlockEntityPistonArm.java index 4fb4a2d2658..24cafd3c1a2 100644 --- a/src/main/java/cn/nukkit/blockentity/BlockEntityPistonArm.java +++ b/src/main/java/cn/nukkit/blockentity/BlockEntityPistonArm.java @@ -1,30 +1,35 @@ package cn.nukkit.blockentity; -import cn.nukkit.entity.Entity; +import cn.nukkit.block.Block; +import cn.nukkit.block.BlockAir; +import cn.nukkit.block.BlockID; import cn.nukkit.level.format.FullChunk; -import cn.nukkit.math.AxisAlignedBB; import cn.nukkit.math.BlockFace; -import cn.nukkit.math.SimpleAxisAlignedBB; import cn.nukkit.math.Vector3; import cn.nukkit.nbt.tag.CompoundTag; import cn.nukkit.nbt.tag.IntTag; import cn.nukkit.nbt.tag.ListTag; +import cn.nukkit.utils.Faceable; + +import java.util.ArrayList; +import java.util.List; /** * @author CreeperFace */ public class BlockEntityPistonArm extends BlockEntitySpawnable { + public static final float MOVE_STEP = Float.valueOf(0.5f); + public float progress; public float lastProgress = 1.0F; public BlockFace facing; - public boolean extending = false; - public boolean sticky = false; - public byte state; - public byte newState = 1; - public Vector3 attachedBlock = null; - public boolean isMovable = true; - public boolean powered = false; + public boolean extending; + public boolean sticky; + public int state; + public int newState = 1; + public List attachedBlocks; + public boolean powered; public BlockEntityPistonArm(FullChunk chunk, CompoundTag nbt) { super(chunk, nbt); @@ -40,45 +45,128 @@ protected void initBlockEntity() { this.lastProgress = (float) namedTag.getInt("LastProgress"); } - if (namedTag.contains("Sticky")) { - this.sticky = namedTag.getBoolean("Sticky"); - } + this.sticky = namedTag.getBoolean("Sticky"); + this.extending = namedTag.getBoolean("Extending"); + this.powered = namedTag.getBoolean("powered"); - if (namedTag.contains("Extending")) { - this.extending = namedTag.getBoolean("Extending"); - } - if (namedTag.contains("powered")) { - this.powered = namedTag.getBoolean("powered"); + if (namedTag.contains("facing")) { + this.facing = BlockFace.fromIndex(namedTag.getInt("facing")); + } else { + Block b = this.getLevelBlock(); + + if (b instanceof Faceable) { + this.facing = ((Faceable) b).getBlockFace(); + } } + attachedBlocks = new ArrayList<>(); + if (namedTag.contains("AttachedBlocks")) { ListTag blocks = namedTag.getList("AttachedBlocks", IntTag.class); if (blocks != null && blocks.size() > 0) { - this.attachedBlock = new Vector3((double) ((IntTag) blocks.get(0)).getData(), (double) ((IntTag) blocks.get(1)).getData(), (double) ((IntTag) blocks.get(2)).getData()); + for (int i = 0; i < blocks.size(); i += 3) { + this.attachedBlocks.add(new Vector3( + ((IntTag) blocks.get(i)).data, + ((IntTag) blocks.get(i + 1)).data, + ((IntTag) blocks.get(i + 1)).data + )); + } } } else { - namedTag.putList(new ListTag("AttachedBlocks")); + namedTag.putList(new ListTag<>("AttachedBlocks")); } super.initBlockEntity(); } - private void pushEntities() { - float lastProgress = this.getExtendedProgress(this.lastProgress); - double x = (double) (lastProgress * (float) this.facing.getXOffset()); - double y = (double) (lastProgress * (float) this.facing.getYOffset()); - double z = (double) (lastProgress * (float) this.facing.getZOffset()); - AxisAlignedBB bb = new SimpleAxisAlignedBB(x, y, z, x + 1.0D, y + 1.0D, z + 1.0D); - Entity[] entities = this.level.getCollidingEntities(bb); - if (entities.length != 0) { + private void moveCollidedEntities() { +// float lastProgress = this.getExtendedProgress(this.lastProgress); +// double x = (double) (lastProgress * (float) this.facing.getXOffset()); +// double y = (double) (lastProgress * (float) this.facing.getYOffset()); +// double z = (double) (lastProgress * (float) this.facing.getZOffset()); +// AxisAlignedBB bb = new SimpleAxisAlignedBB(x, y, z, x + 1.0D, y + 1.0D, z + 1.0D); +// Entity[] entities = this.level.getCollidingEntities(bb); +// if (entities.length != 0) { +// +// } + + BlockFace pushDir = this.extending ? facing : facing.getOpposite(); + for (Vector3 pos : this.attachedBlocks) { + BlockEntity blockEntity = this.level.getBlockEntity(pos.getSide(pushDir)); + + if (blockEntity instanceof BlockEntityMovingBlock) { + ((BlockEntityMovingBlock) blockEntity).moveCollidedEntities(this); + } + } + } + + public void move(boolean extending, List attachedBlocks) { + this.extending = extending; + this.lastProgress = this.progress = extending ? 0 : 1; + this.state = this.newState = extending ? 1 : 3; + this.attachedBlocks = attachedBlocks; + + this.level.addChunkPacket(getChunkX(), getChunkZ(), getSpawnPacket()); + this.lastProgress = extending ? -MOVE_STEP : 1 + MOVE_STEP; + this.moveCollidedEntities(); + this.scheduleUpdate(); + } + + @Override + public boolean onUpdate() { + boolean hasUpdate = true; + + if (this.extending) { + this.progress = Math.min(1, this.progress + MOVE_STEP); + this.lastProgress = Math.min(1, this.lastProgress + MOVE_STEP); + } else { + this.progress = Math.max(0, this.progress - MOVE_STEP); + this.lastProgress = Math.max(0, this.lastProgress - MOVE_STEP); + } + + this.level.addChunkPacket(getChunkX(), getChunkZ(), getSpawnPacket()); + this.moveCollidedEntities(); + + if (this.progress == this.lastProgress) { + this.state = this.newState = extending ? 2 : 0; + + BlockFace pushDir = this.extending ? facing : facing.getOpposite(); + + for (Vector3 pos : this.attachedBlocks) { + BlockEntity movingBlock = this.level.getBlockEntity(pos.getSide(pushDir)); + + if (movingBlock instanceof BlockEntityMovingBlock) { + movingBlock.close(); + Block moved = ((BlockEntityMovingBlock) movingBlock).getMovingBlock(); + + this.level.setBlock(movingBlock, moved); + + CompoundTag blockEntity = ((BlockEntityMovingBlock) movingBlock).getBlockEntity(); + if (blockEntity != null) { + blockEntity.putInt("x", movingBlock.getFloorX()); + blockEntity.putInt("y", movingBlock.getFloorY()); + blockEntity.putInt("z", movingBlock.getFloorZ()); + BlockEntity.createBlockEntity(blockEntity.getString("id"), this.level.getChunk(movingBlock.getChunkX(), movingBlock.getChunkZ()), blockEntity); + } + } + } + + if (!extending && this.level.getBlock(getSide(facing)).getId() == BlockID.PISTON_HEAD) { + this.level.setBlock(getSide(facing), new BlockAir()); + } + + this.level.scheduleUpdate(this.getLevelBlock(), 1); + this.attachedBlocks.clear(); + hasUpdate = false; } + return super.onUpdate() || hasUpdate; } private float getExtendedProgress(float progress) { - return this.extending ? progress - 1.0F : 1.0F - progress; + return this.extending ? progress - 1 : 1 - progress; } public boolean isBlockEntityValid() { @@ -87,21 +175,39 @@ public boolean isBlockEntityValid() { public void saveNBT() { super.saveNBT(); - this.namedTag.putBoolean("isMovable", this.isMovable); this.namedTag.putByte("State", this.state); this.namedTag.putByte("NewState", this.newState); this.namedTag.putFloat("Progress", this.progress); this.namedTag.putFloat("LastProgress", this.lastProgress); this.namedTag.putBoolean("powered", this.powered); + this.namedTag.putList(getAttachedBlocks()); + this.namedTag.putInt("facing", this.facing.getIndex()); } public CompoundTag getSpawnCompound() { return new CompoundTag() - .putString("id", "PistonArm") + .putString("id", BlockEntity.PISTON_ARM) .putInt("x", (int) this.x) .putInt("y", (int) this.y) .putInt("z", (int) this.z) .putFloat("Progress", this.progress) - .putByte("State", this.state); + .putFloat("LastProgress", this.lastProgress) + .putBoolean("isMovable", this.movable) + .putList(getAttachedBlocks()) + .putList(new ListTag<>("BreakBlocks")) + .putBoolean("Sticky", this.sticky) + .putByte("State", this.state) + .putByte("NewState", this.newState); + } + + private ListTag getAttachedBlocks() { + ListTag attachedBlocks = new ListTag<>("AttachedBlocks"); + for (Vector3 block : this.attachedBlocks) { + attachedBlocks.add(new IntTag("", block.getFloorX())); + attachedBlocks.add(new IntTag("", block.getFloorY())); + attachedBlocks.add(new IntTag("", block.getFloorZ())); + } + + return attachedBlocks; } } \ No newline at end of file diff --git a/src/main/java/cn/nukkit/blockentity/BlockEntitySpawnable.java b/src/main/java/cn/nukkit/blockentity/BlockEntitySpawnable.java index e0d8651346d..7ac3146ec35 100644 --- a/src/main/java/cn/nukkit/blockentity/BlockEntitySpawnable.java +++ b/src/main/java/cn/nukkit/blockentity/BlockEntitySpawnable.java @@ -26,24 +26,38 @@ protected void initBlockEntity() { this.spawnToAll(); } - public abstract CompoundTag getSpawnCompound(); + public CompoundTag getSpawnCompound() { + return this.namedTag; + } public void spawnTo(Player player) { if (this.closed) { return; } - CompoundTag tag = this.getSpawnCompound(); + player.dataPacket(getSpawnPacket()); + } + + public BlockEntityDataPacket getSpawnPacket() { + return getSpawnPacket(null); + } + + public BlockEntityDataPacket getSpawnPacket(CompoundTag nbt) { + if (nbt == null) { + nbt = this.getSpawnCompound(); + } + BlockEntityDataPacket pk = new BlockEntityDataPacket(); pk.x = (int) this.x; pk.y = (int) this.y; pk.z = (int) this.z; try { - pk.namedTag = NBTIO.write(tag, ByteOrder.LITTLE_ENDIAN, true); + pk.namedTag = NBTIO.write(nbt, ByteOrder.LITTLE_ENDIAN, true); } catch (IOException e) { throw new RuntimeException(e); } - player.dataPacket(pk); + + return pk; } public void spawnToAll() { diff --git a/src/main/java/cn/nukkit/level/GlobalBlockPalette.java b/src/main/java/cn/nukkit/level/GlobalBlockPalette.java index 4d96f182d8f..69e36467073 100644 --- a/src/main/java/cn/nukkit/level/GlobalBlockPalette.java +++ b/src/main/java/cn/nukkit/level/GlobalBlockPalette.java @@ -5,6 +5,8 @@ import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import it.unimi.dsi.fastutil.ints.Int2IntArrayMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import java.io.InputStream; import java.io.InputStreamReader; @@ -12,12 +14,16 @@ import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; import java.util.Collection; +import java.util.HashMap; +import java.util.Map; import java.util.NoSuchElementException; import java.util.concurrent.atomic.AtomicInteger; public class GlobalBlockPalette { private static final Int2IntArrayMap legacyToRuntimeId = new Int2IntArrayMap(); private static final Int2IntArrayMap runtimeIdToLegacy = new Int2IntArrayMap(); + private static final Int2ObjectMap legacyIdToString = new Int2ObjectOpenHashMap<>(); + private static final Map stringToLegacyId = new HashMap<>(); private static final AtomicInteger runtimeIdAllocator = new AtomicInteger(0); private static final byte[] compiledPalette; @@ -40,7 +46,7 @@ public class GlobalBlockPalette { table.putUnsignedVarInt(entries.size()); for (TableEntry entry : entries) { - registerMapping((entry.id << 4) | entry.data); + registerMapping((entry.id << 4) | entry.data, entry.name); table.putString(entry.name); table.putLShort(entry.data); table.putLShort(entry.id); @@ -62,9 +68,15 @@ public static int getOrCreateRuntimeId(int legacyId) throws NoSuchElementExcepti return runtimeId; } - private static int registerMapping(int legacyId) { + public static String getName(int id, int meta) { + return legacyIdToString.get((id << 4) | meta); + } + + private static int registerMapping(int legacyId, String name) { int runtimeId = runtimeIdAllocator.getAndIncrement(); runtimeIdToLegacy.put(runtimeId, legacyId); + legacyIdToString.put(legacyId, name); + stringToLegacyId.put(name, legacyId); legacyToRuntimeId.put(legacyId, runtimeId); return runtimeId; } diff --git a/src/main/java/cn/nukkit/level/Level.java b/src/main/java/cn/nukkit/level/Level.java index 6d075cd20e9..b3ba0aa4187 100644 --- a/src/main/java/cn/nukkit/level/Level.java +++ b/src/main/java/cn/nukkit/level/Level.java @@ -2105,6 +2105,7 @@ public Item useItemOn(Vector3 vector, Item item, BlockFace face, float fx, float return null; } + MainLogger.getLogger().info("place: " + block + " loc: " + block.getLocationHash()); if (player != null) { if (!player.isCreative()) { item.setCount(item.getCount() - 1); diff --git a/src/main/java/cn/nukkit/nbt/tag/CompoundTag.java b/src/main/java/cn/nukkit/nbt/tag/CompoundTag.java index 52d187f9fdb..9abe4883ee6 100644 --- a/src/main/java/cn/nukkit/nbt/tag/CompoundTag.java +++ b/src/main/java/cn/nukkit/nbt/tag/CompoundTag.java @@ -12,14 +12,23 @@ import java.util.StringJoiner; public class CompoundTag extends Tag implements Cloneable { - private final Map tags = new HashMap<>(); + private final Map tags; public CompoundTag() { - super(""); + this(""); } public CompoundTag(String name) { + this(name, new HashMap<>()); + } + + public CompoundTag(Map tags) { + this("", tags); + } + + public CompoundTag(String name, Map tags) { super(name); + this.tags = tags; } @Override diff --git a/src/main/java/cn/nukkit/nbt/tag/Tag.java b/src/main/java/cn/nukkit/nbt/tag/Tag.java index 3b66e063b2b..2f33f67ed71 100644 --- a/src/main/java/cn/nukkit/nbt/tag/Tag.java +++ b/src/main/java/cn/nukkit/nbt/tag/Tag.java @@ -60,7 +60,9 @@ public void print(String prefix, PrintStream out) { out.print("(\"" + name + "\")"); } out.print(": "); - out.println(toString()); + if (getId() != TAG_Compound && getId() != TAG_List) { + out.println(parseValue()); + } } public Tag setName(String name) { diff --git a/src/main/java/cn/nukkit/network/Network.java b/src/main/java/cn/nukkit/network/Network.java index fe632730d55..0c5d13c2377 100644 --- a/src/main/java/cn/nukkit/network/Network.java +++ b/src/main/java/cn/nukkit/network/Network.java @@ -5,6 +5,7 @@ import cn.nukkit.Server; import cn.nukkit.network.protocol.*; import cn.nukkit.utils.BinaryStream; +import cn.nukkit.utils.MainLogger; import cn.nukkit.utils.Utils; import cn.nukkit.utils.Zlib; import io.netty.buffer.ByteBufUtil; @@ -179,9 +180,7 @@ public void processBatch(BatchPacket packet, Player player) { processPackets(player, packets); } catch (Exception e) { - if (log.isDebugEnabled()) { - log.debug("Error whilst decoding batch packet", e); - } + MainLogger.getLogger().error("Error whilst decoding batch packet", e); } }