diff --git a/game/client/src/main/resources/assets/minecraft/models/block/layer/height3.json b/game/client/src/main/resources/assets/minecraft/models/block/layer/height3.json index c70e1c9c0..89df3d516 100644 --- a/game/client/src/main/resources/assets/minecraft/models/block/layer/height3.json +++ b/game/client/src/main/resources/assets/minecraft/models/block/layer/height3.json @@ -17,7 +17,7 @@ "faces": { "north": {"uv": [0, 8, 16, 16], "texture": "#side", "cullface": "north"}, "east": {"uv": [0, 8, 16, 16], "texture": "#side", "cullface": "east"}, - "south": {"uv": [0, 10, 16, 16], "texture": "#side", "cullface": "south"}, + "south": {"uv": [0, 8, 16, 16], "texture": "#side", "cullface": "south"}, "west": {"uv": [0, 8, 16, 16], "texture": "#side", "cullface": "west"}, "up": {"uv": [0, 0, 16, 16], "texture": "#top"}, "down": {"uv": [0, 0, 16, 16], "texture": "#bottom", "cullface": "down"} diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBed.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBed.java index bd75af502..32cf8f1b6 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBed.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBed.java @@ -11,6 +11,7 @@ import net.minecraft.core.enums.EnumDropCause; import net.minecraft.core.enums.EnumSleepStatus; import net.minecraft.core.item.Items; import net.minecraft.core.item.ItemStack; +import net.minecraft.core.util.helper.Direction; import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePos; @@ -111,23 +112,50 @@ public class BlockLogicBed @Override public void onNeighborChanged(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Block block) { - this.removeOtherHalf(world, tilePos); + final var state = new State(world, tilePos); + if (!state.hasOtherHalf(world, tilePos)) { + world.setBlockTypeNotify(tilePos, Blocks.AIR); + } } @Override public void onRemoved(final @NotNull World world, final @NotNull TilePosc tilePos, final int data) { - this.removeOtherHalf(world, tilePos); + final var state = new State(data, world, tilePos); + if (state.hasOtherHalf(world, tilePos)) { + // eventhough onNeighborChanged would normally be able to handle the removal of + // the other half, however piston will break this half without emitting neighbor + // update untill it finishes extending, destroying the other half before which + // would result in a dupe. + world.setBlockTypeNotify(state.otherPos(tilePos), Blocks.AIR); + } } - protected void removeOtherHalf(final @NotNull World world, final @NotNull TilePosc tilePos) { - final int data = world.getBlockData(tilePos); - final int direction = getDirection(data); - if (isBlockHeadOfBed(data)) { - if (world.getBlockType(tilePos.sub(headBlockToFootBlockMap[direction].getDirection(), new TilePos())) != this.block) { - world.setBlockTypeNotify(tilePos, Blocks.AIR); - } - } else if (world.getBlockType(tilePos.add(headBlockToFootBlockMap[direction].getDirection(), new TilePos())) != this.block) { - world.setBlockTypeNotify(tilePos, Blocks.AIR); + protected static class State { + final boolean isHead; + final @NotNull Direction h2fDir; + + public State(int data, final @NotNull World world, @NotNull TilePosc tilePos) { + isHead = isBlockHeadOfBed(data); + h2fDir = headBlockToFootBlockMap[getDirection(data)].getDirection(); + } + + public State(final @NotNull World world, @NotNull TilePosc tilePos) { + this(world.getBlockData(tilePos), world, tilePos); + } + + public @NotNull TilePos otherPos(@NotNull TilePosc tilePos) { + return (isHead) + ? tilePos.sub(h2fDir, new TilePos()) + : tilePos.add(h2fDir, new TilePos()); + } + + public boolean hasOtherHalf(final @NotNull World world, @NotNull TilePosc tilePos) { + final var otherPos = otherPos(tilePos); + if (!(world.getBlockType(otherPos).getLogic() instanceof BlockLogicBed)) return false; + final var otherState = new State(world, otherPos); + if (this.isHead == otherState.isHead) return false; + if (this.h2fDir != otherState.h2fDir) return false; + return true; } } @@ -141,12 +169,12 @@ public class BlockLogicBed return Material.PISTON_DESTROY_ON_PUSH; } - public static final int MASK_IS_FOOT = 0b0000_1000; + public static final int MASK_IS_HEAD = 0b0000_1000; public static final int MASK_IS_OCCUPIED = 0b0000_0100; public static final int MASK_DIRECTION = 0b0000_0011; public static boolean isBlockHeadOfBed(final int meta) { - return (meta & MASK_IS_FOOT) != 0; + return (meta & MASK_IS_HEAD) != 0; } public static boolean isBedOccupied(final int meta) { diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java index 025325c56..223ca8dbc 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java @@ -83,7 +83,9 @@ public class BlockLogicDispenser extends BlockLogicVeryRotatable { world.playBlockEvent(tilePos, LevelListener.EVENT_DISPENSER_PROJECTILE, 0); } else { if (itemStack.consumeItem(null)) { - final @NotNull EntityItem item = new EntityItem(world, pos.x(), pos.y() + (direction == Direction.UP ? 0.25d : -0.3D), pos.z(), new ItemStack(itemStack.getItem())); + final var newStack = itemStack.copy(); + newStack.stackSize = 1; + final @NotNull EntityItem item = new EntityItem(world, pos.x(), pos.y() + (direction == Direction.UP ? 0.25d : -0.3D), pos.z(), newStack); final double randOffset = random.nextDouble() * 0.1D + 0.2D; item.xd = (double) xOffset * randOffset; item.yd = (double) yOffset + (direction == Direction.UP ? -0.65D : 0.2D); diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java index b49460db6..15de385de 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java @@ -203,21 +203,35 @@ public class BlockLogicStatue extends BlockLogic { world.dropItem(tilePos, stack); } } + // Piston does not emit neighbor update when begin extending. + // By removing the other half first, this fixes a dupe. + // This is intentionally setBlockType instead of setBlockTypeNotify! + removeOtherHalf(world, tilePos); } - + @Override public void onNeighborChanged(@NotNull World world, @NotNull TilePosc tilePos, final @NotNull Block block) { - final Block otherBlock; - if (!this.isBottom) { - otherBlock = world.getBlockType(tilePos.down(new TilePos())); - } else { - otherBlock = world.getBlockType(tilePos.up(new TilePos())); - } - if (!(otherBlock.getLogic() instanceof BlockLogicStatue)) { + if (!isOtherHalf(world, getOtherHalfPos(tilePos))) { world.setBlockTypeNotify(tilePos, Blocks.AIR); } } + private void removeOtherHalf(@NotNull World world, @NotNull TilePosc tilePos) { + final var otherPos = getOtherHalfPos(tilePos); + if (isOtherHalf(world, otherPos)) { + world.setBlockTypeNotify(otherPos, Blocks.AIR); + } + } + + private boolean isOtherHalf(@NotNull World world, @NotNull TilePosc tilePos) { + return world.getBlockType(tilePos).getLogic() instanceof BlockLogicStatue other + && (other.isBottom != this.isBottom); + } + + private @NotNull TilePos getOtherHalfPos(@NotNull TilePosc tilePos) { + return (this.isBottom) ? tilePos.up(new TilePos()) : tilePos.down(new TilePos()); + } + @Override public @NotNull ItemStack @Nullable [] getBreakResult(@NotNull World world, @NotNull EnumDropCause dropCause, @NotNull TilePosc tilePos, int data, @Nullable TileEntity tileEntity) { if (this.droppedItem == null) return null; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicWireRedstone.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicWireRedstone.java index 48f899f66..ecc469711 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicWireRedstone.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicWireRedstone.java @@ -23,6 +23,8 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.Random; import java.util.Set; +import java.util.function.Predicate; +import java.util.logging.Logger; public class BlockLogicWireRedstone extends BlockLogic implements ISupportable { public static final int SIGNAL_MIN = 0; @@ -73,6 +75,14 @@ public class BlockLogicWireRedstone extends BlockLogic implements ISupportable { } } + private void transmutate(Predicate> condition, @NotNull World world, @NotNull TilePosc curPos, int data) { + final @NotNull Block block = world.getBlockType(curPos); + if (!condition.test(block)) return; + if (world.setBlockData(curPos, data)) { + world.markBlockNeedsUpdate(curPos); + } + } + private void updatePowerStrength(@NotNull World world, @NotNull TilePosc curPos, @NotNull TilePosc lastPos) { int strength = world.getBlockData(curPos); int newStrength = 0; @@ -114,13 +124,10 @@ public class BlockLogicWireRedstone extends BlockLogic implements ISupportable { } } if (strength != newStrength) { - final @NotNull Block block = world.getBlockType(curPos); - if (block == this.block || block == Blocks.FLUID_LAVA_STILL || block == Blocks.FLUID_LAVA_FLOWING) { // Intentionally keeping lava transmutation, do not delete carelessly - world.noNeighborUpdate = true; // only carefully - world.setBlockDataNotify(curPos, newStrength | (world.getBlockData(curPos) & MASK_DIRECTION)); - world.markBlocksDirty(curPos, curPos); - world.noNeighborUpdate = false; - } + transmutate( + b -> b == this.block || b == Blocks.FLUID_LAVA_STILL || b == Blocks.FLUID_LAVA_FLOWING, + world, curPos, newStrength | (world.getBlockData(curPos) & MASK_DIRECTION) + ); for (int i = 0; i < 4; i++) { int checkX = curPos.x(); int checkY = curPos.y() - 1; @@ -225,7 +232,11 @@ public class BlockLogicWireRedstone extends BlockLogic implements ISupportable { TilePos queryPos = new TilePos(); world.notifyBlocksOfNeighborChange(tilePos.up(queryPos), this.block); world.notifyBlocksOfNeighborChange(tilePos.down(queryPos), this.block); -// updatePowerStrength(world, x, y, z); + transmutate( + b -> b == this.block || b == Blocks.FLUID_LAVA_STILL || b == Blocks.FLUID_LAVA_FLOWING, + world, tilePos, data + ); + // updatePowerStrength(world, x, y, z); world.getWireHandler().onWireRemoved(tilePos, new BlockState(this.block, world.getBlockData(tilePos))); checkCornerChangeAt(world, tilePos.west(queryPos)); checkCornerChangeAt(world, tilePos.east(queryPos)); diff --git a/game/core/src/main/java/net/minecraft/core/entity/monster/MobSkeleton.java b/game/core/src/main/java/net/minecraft/core/entity/monster/MobSkeleton.java index 0d0d425ec..21a1d54af 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/monster/MobSkeleton.java +++ b/game/core/src/main/java/net/minecraft/core/entity/monster/MobSkeleton.java @@ -46,7 +46,7 @@ public class MobSkeleton extends MobMonsterArmored @Override protected String getDeathSound() { - return "mob.skeletonhurt"; + return "mob.skeletondeath"; } @Override protected void defineSynchedData() diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemBed.java b/game/core/src/main/java/net/minecraft/core/item/ItemBed.java index 9c4a28593..22efccf38 100644 --- a/game/core/src/main/java/net/minecraft/core/item/ItemBed.java +++ b/game/core/src/main/java/net/minecraft/core/item/ItemBed.java @@ -1,5 +1,6 @@ package net.minecraft.core.item; +import net.minecraft.core.block.BlockLogicBed; import net.minecraft.core.block.Blocks; import net.minecraft.core.entity.player.Player; import net.minecraft.core.enums.EnumBlockSoundEffectType; @@ -28,8 +29,10 @@ public class ItemBed extends Item { if (world.isAirBlock(pos) && world.isAirBlock(pos2) && world.canPlaceOnSurfaceOfBlock(pos.down(new TilePos())) && world.canPlaceOnSurfaceOfBlock(pos2.down(new TilePos()))) { if (world.canBlockIdBePlacedAt(Blocks.BED.id(), pos, false, side) && selfStack.consumeItem(player)) { world.playBlockSoundEffect(player, pos.x() + 0.5F, pos.y() + 0.5F, pos.z() + 0.5F, Blocks.BED, EnumBlockSoundEffectType.PLACE); - world.setBlockTypeDataNotify(pos, Blocks.BED, dir.getHorizontalIndex()); - world.setBlockTypeDataNotify(pos2, Blocks.BED, dir.getHorizontalIndex() | 0b1000); + world.setBlockTypeData(pos, Blocks.BED, dir.getHorizontalIndex()); + world.setBlockTypeData(pos2, Blocks.BED, dir.getHorizontalIndex() | BlockLogicBed.MASK_IS_HEAD); + world.notifyBlockChange(pos, Blocks.BED); + world.notifyBlockChange(pos2, Blocks.BED); return true; } } diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java b/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java index ed98f02db..9418e8ead 100644 --- a/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java +++ b/game/core/src/main/java/net/minecraft/core/item/ItemBucket.java @@ -65,8 +65,11 @@ public class ItemBucket extends Item { if (this.blockToPlace == Blocks.FLUID_WATER_FLOWING) { world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, rayCastPos.x + 0.5F, rayCastPos.y + 0.5F, rayCastPos.z + 0.5F, "liquid.splash", 0.5f, 1.0f); } + final var replacedBlock = world.getBlockType(rayCastPos); + final var replacedMeta = world.getBlockData(rayCastPos); world.setBlockTypeNotify(rayCastPos, this.blockToPlace); - world.getBlockType(rayCastPos).dropWithCause(world, EnumDropCause.WORLD, rayCastPos, world.getBlockData(rayCastPos), null, null); + replacedBlock.dropWithCause(world, EnumDropCause.WORLD, rayCastPos, replacedMeta, null, null); + // is this being called afterwards intentional? player.swingItem(); if (player.getGamemode().hasBlockConsumption()) {