diff --git a/game/client/src/main/java/net/minecraft/client/gui/TooltipElement.java b/game/client/src/main/java/net/minecraft/client/gui/TooltipElement.java index 5940c6dc8..a8a760262 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/TooltipElement.java +++ b/game/client/src/main/java/net/minecraft/client/gui/TooltipElement.java @@ -7,7 +7,9 @@ import com.google.gson.JsonParser; import com.google.gson.stream.JsonReader; import com.mojang.logging.LogUtils; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.guidebook.SlotGuidebook; import net.minecraft.client.option.GameSettings; +import net.minecraft.client.option.enums.DescriptionPromptEnum; import net.minecraft.client.render.font.FontRenderer; import net.minecraft.client.render.renderer.BlendFactor; import net.minecraft.client.render.renderer.CompareFunc; @@ -17,20 +19,18 @@ import net.minecraft.client.render.texture.stitcher.IconCoordinate; import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.client.render.texturepack.TexturePack; import net.minecraft.client.render.texturepack.TexturePackList; -import net.minecraft.client.option.enums.DescriptionPromptEnum; import net.minecraft.core.WeightedRandomBag; -import net.minecraft.core.data.registry.recipe.entry.RecipeEntryTrommel; import net.minecraft.core.data.registry.recipe.RecipeSymbol; +import net.minecraft.core.data.registry.recipe.entry.RecipeEntryTrommel; import net.minecraft.core.item.ItemStack; -import net.minecraft.core.player.inventory.slot.Slot; -import net.minecraft.core.player.inventory.slot.SlotResult; import net.minecraft.core.lang.I18n; import net.minecraft.core.net.command.TextFormatting; -import net.minecraft.client.gui.guidebook.SlotGuidebook; +import net.minecraft.core.player.inventory.slot.Slot; +import net.minecraft.core.player.inventory.slot.SlotResult; import net.minecraft.core.util.helper.MathHelper; +import net.minecraft.core.util.helper.NBTFormatHelper; import org.jetbrains.annotations.NotNull; import org.lwjgl.input.Keyboard; - import org.slf4j.Logger; import java.io.IOException; @@ -51,54 +51,61 @@ public class TooltipElement extends Gui { Minecraft mc; FontRenderer fontRenderer; - public TooltipElement(Minecraft mc) { + private static final int SCREEN_MARGIN = 12; + + public TooltipElement(@NotNull Minecraft mc) { this.mc = mc; this.fontRenderer = mc.font; } - public static final int BASE_PADDING = 3; - public static final int LINE_SPACING = 3; - public void render(final CharSequence string, final int x, final int y, final int offsetX, final int offsetY) { render(string, x, y, offsetX, offsetY, -1, -1, true); } - public void render(final CharSequence chars, int x, int y, int offsetX, int offsetY, int maxWidth, int maxHeight, boolean canOffset) { - GLRenderer.pushFrame(); - GLRenderer.setDepthFunc(CompareFunc.ALWAYS); + public void render(final CharSequence chars, int mouseX, int mouseY, int offsetX, int offsetY, int maxWidth, int maxHeight, boolean canOffset) { maxWidth = maxWidth == -1 ? Integer.MAX_VALUE : maxWidth; - maxHeight = maxHeight == -1 ? Integer.MAX_VALUE : maxHeight; - final List lines = new ArrayList<>(); this.fontRenderer.splitCharsIntoLines(chars, maxWidth, lines); - int width = 0; - for (final String line : lines) { - width = Math.max(width, this.fontRenderer.stringWidth(line) - 1); - } - final int height = MathHelper.ceil(this.fontRenderer.heightOfLines(lines, maxWidth) - 1); + if (lines.isEmpty()) return; - // Flip tooltip X if it goes offscreen to the right - if (canOffset && x + offsetX + width > this.mc.resolution.getScaledWidthScreenCoords()) { - offsetX = -offsetX - width; + // raw dimensions + int rawWidth = 0; + for (final String line : lines) { + rawWidth = Math.max(rawWidth, this.fontRenderer.stringWidth(line) - 1); } + int rawHeight = MathHelper.ceil(this.fontRenderer.heightOfLines(lines, maxWidth) - 1); + int padding = getPadding(); - if (canOffset) { - // Move tooltip up when it goes offscreen to the bottom - offsetY -= Math.max(0, y + height + offsetY - this.mc.resolution.getScaledHeightScreenCoords()); - } + // screen bounds + int screenW = this.mc.resolution.getScaledWidthScreenCoords(); + int screenH = this.mc.resolution.getScaledHeightScreenCoords(); + int finalX = mouseX + offsetX; + int finalY = mouseY + offsetY; - x += offsetX; - y += offsetY; + if (canOffset) { + if (finalX + rawWidth > screenW - SCREEN_MARGIN) { + finalX = mouseX - rawWidth - offsetX; + } + if (finalY + rawHeight > screenH - SCREEN_MARGIN) { + finalY = screenH - rawHeight - SCREEN_MARGIN; + } - final int padding = getPadding(); + finalX = MathHelper.clamp(finalX, SCREEN_MARGIN, screenW - rawWidth - SCREEN_MARGIN); + finalY = MathHelper.clamp(finalY, SCREEN_MARGIN, screenH - rawHeight - SCREEN_MARGIN); + } - drawBackground(x, y, x + width, y + height); -// drawRect(x, y, x + width, y + height, 0xFFFFFFFF); + // render + GLRenderer.pushFrame(); + try { + GLRenderer.setDepthFunc(CompareFunc.ALWAYS); + drawBackground(finalX, finalY, finalX + rawWidth, finalY + rawHeight); - this.fontRenderer.renderWidthConstrained(chars, x + padding, y + padding, maxWidth).call(); - GLRenderer.popFrame(); + this.fontRenderer.renderWidthConstrained(chars, finalX + padding, finalY + padding, maxWidth).call(); + } finally { + GLRenderer.popFrame(); + } } public int getPadding() { @@ -123,7 +130,7 @@ public class TooltipElement extends Gui { return drawBackground(x, y, x + width, y + height); } - private int[] drawBackground(final int minX, final int minY, final int maxX, final int maxY) { + private int @NotNull [] drawBackground(final int minX, final int minY, final int maxX, final int maxY) { final Style style = styleMap.getOrDefault(GameSettings.TOOLTIP_STYLE.value, defaultStyle); if (style != null) { GLRenderer.pushFrame(); @@ -150,21 +157,23 @@ public class TooltipElement extends Gui { return new int[]{minX, minY}; } + public String getTooltipText(ItemStack itemStack, boolean showDescription) { + return getTooltipText(itemStack, showDescription, null); + } + public String getTooltipText(ItemStack itemStack, boolean showDescription, Slot slot) { I18n trans = I18n.getInstance(); StringBuilder text = new StringBuilder(); + boolean discovered = true; - boolean ctrlPressed = false; - boolean shiftPressed = false; + boolean ctrlPressed = Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL); + boolean shiftPressed = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT); boolean debug = GameSettings.SHOW_ITEM_DEBUG_INFO.value; if (slot != null) { discovered = slot.getIsDiscovered(this.mc.thePlayer); if (slot instanceof SlotResult) { - ctrlPressed = Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL); - shiftPressed = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT); - showDescription = false; if (GameSettings.SWAP_CRAFTING_BUTTONS.value) { boolean temp = shiftPressed; @@ -175,42 +184,49 @@ public class TooltipElement extends Gui { } if (discovered) { - text.append(TextFormatting.get(itemStack.getDisplayColor())); - text.append(itemStack.getDisplayName()); - if (itemStack.getData().containsKey("tileEntityData")) - text.append(" ").append(TextFormatting.MAGENTA).append(TextFormatting.ITALIC).append("+NBT").append(TextFormatting.RESET).append(TextFormatting.get(itemStack.getDisplayColor())); - + text.append(TextFormatting.get(itemStack.getDisplayColor())) + .append(itemStack.getDisplayName()) + .append(TextFormatting.RESET); + + if (itemStack.getData().containsKey("tileEntityData")) { + if (debug) { + text.append(" ") + .append(TextFormatting.MAGENTA) + .append(TextFormatting.ITALIC) + .append("+NBT") + .append(TextFormatting.RESET) + .append(TextFormatting.get(itemStack.getDisplayColor())); + } else { + text.append(" ") + .append(TextFormatting.MAGENTA) + .append("•") + .append(TextFormatting.RESET); + } + } if (debug) { text.append(" #").append(itemStack.itemID).append(":").append(itemStack.getMetadata()); } - if (slot instanceof SlotGuidebook) { - if (((SlotGuidebook) slot).recipe != null) { - if (((SlotGuidebook) slot).recipe instanceof RecipeEntryTrommel) { - RecipeSymbol input = (RecipeSymbol) ((SlotGuidebook) slot).recipe.getInput(); - if (!input.matches(slot.getItemStack())) { - WeightedRandomBag bag = (WeightedRandomBag) ((SlotGuidebook) slot).recipe.getOutput(); - double percent = bag.getAsPercentage(slot.getItemStack()); - text.append('\n').append(TextFormatting.LIGHT_GRAY).append(String.format("%.2f", percent)).append("%"); - } - } + if (slot instanceof SlotGuidebook slotGuidebook && slotGuidebook.recipe instanceof RecipeEntryTrommel) { + RecipeSymbol input = (RecipeSymbol) slotGuidebook.recipe.getInput(); + if (!input.matches(slot.getItemStack())) { + WeightedRandomBag bag = (WeightedRandomBag) slotGuidebook.recipe.getOutput(); + double percent = bag.getAsPercentage(slot.getItemStack()); + text.append('\n').append(TextFormatting.LIGHT_GRAY).append(String.format("%.2f", percent)).append("%"); } } if (debug) { text.append('\n').append(TextFormatting.LIGHT_GRAY).append(itemStack.getItem().namespaceID); text.append('\n').append(TextFormatting.LIGHT_GRAY).append(itemStack.getItemKey()); - text.append('\n').append(TextFormatting.LIGHT_GRAY).append("NBT: ").append(itemStack.getData().getValue().size()).append(" Tags"); if (slot instanceof SlotGuidebook slotGuidebook) { if (slotGuidebook.recipe != null) { text.append('\n').append(TextFormatting.GRAY).append(slotGuidebook.recipe); } - if (slotGuidebook.symbol != null) { - if (slotGuidebook.symbol.getItemGroup() != null) { - text.append('\n').append(TextFormatting.GRAY).append("Accepts any: ").append(slotGuidebook.symbol.getItemGroup()); - } + if (slotGuidebook.symbol != null && slotGuidebook.symbol.getItemGroup() != null) { + text.append('\n').append(TextFormatting.GRAY).append("Accepts any: ").append(slotGuidebook.symbol.getItemGroup()); } } } @@ -222,23 +238,32 @@ public class TooltipElement extends Gui { text.append('\n').append(TextFormatting.LIGHT_GRAY).append(remainingUses + 1).append(" / ").append(durability + 1); } - if (showDescription) { - text.append('\n').append(formatDescription(itemStack.getItemDescription(), 16)); + if (showDescription && !debug) { + text.append('\n').append(formatDescription(itemStack.getItemDescription())); } else if (!(slot instanceof SlotResult) && GameSettings.ITEM_DESCRIPTIONS.value != DescriptionPromptEnum.NEVER_PROMPT) { - text.append('\n').append(formatDescription(trans.translateKeyAndFormat("gui.tooltip.prompt.description", GameSettings.KEY_DESCRIPTION.getKeyName()), 16)); + text.append('\n').append(formatDescription(trans.translateKeyAndFormat("gui.tooltip.prompt.description", GameSettings.KEY_DESCRIPTION.getKeyName()))); } if (slot instanceof SlotResult) { if (shiftPressed && !ctrlPressed) { text.append('\n').append(TextFormatting.LIGHT_GRAY).append("Craft Stack"); - } - if (ctrlPressed && !shiftPressed) { + } else if (ctrlPressed && !shiftPressed) { text.append('\n').append(TextFormatting.LIGHT_GRAY).append("Craft Once"); - } - if (ctrlPressed && shiftPressed) { + } else if (ctrlPressed) { text.append('\n').append(TextFormatting.LIGHT_GRAY).append("Craft All"); } } + + if (debug && !itemStack.getData().getValue().isEmpty()) { + if (ctrlPressed) { + text.append('\n').append(NBTFormatHelper.formatNbtTooltip(itemStack.getData().toString())); + } else { + int tagCount = itemStack.getData().getValue().size(); + String tagWord = tagCount == 1 ? " Tag" : " Tags"; + text.append('\n').append(TextFormatting.GRAY).append(tagCount).append(tagWord).append(" "); + } + } + } else { String translatedName = itemStack.getDisplayName(); for (char c : translatedName.toCharArray()) { @@ -258,21 +283,15 @@ public class TooltipElement extends Gui { return text.toString(); } - public String getTooltipText(ItemStack itemStack, boolean showDescription) { - return getTooltipText(itemStack, showDescription, null); - } - - private static String formatDescription(String description, int preferredLineLength) { + private static @NotNull String formatDescription(@NotNull String description) { StringBuilder string = new StringBuilder(); string.append(TextFormatting.LIGHT_GRAY); int lineLength = 0; - for (int i = 0; i < description.length(); i++) { - char c = description.charAt(i); - + for (char c : description.toCharArray()) { if (c == ' ') { - if (lineLength > preferredLineLength) { + if (lineLength > 16) { lineLength = 0; string.append("\n").append(TextFormatting.LIGHT_GRAY); } else { diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentDynamicTooltip.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentDynamicTooltip.java index df19902d8..897b8b483 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentDynamicTooltip.java +++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentDynamicTooltip.java @@ -9,9 +9,9 @@ import net.minecraft.client.option.Option; import net.minecraft.client.render.renderer.BlendFactor; import net.minecraft.client.render.renderer.GLRenderer; import net.minecraft.client.render.renderer.State; -import net.minecraft.core.entity.Mob; import net.minecraft.core.item.ItemStack; import net.minecraft.client.util.helper.Colors; +import net.minecraft.core.net.command.TextFormatting; import net.minecraft.core.util.helper.Time; import org.jetbrains.annotations.NotNull; @@ -23,6 +23,7 @@ public class HudComponentDynamicTooltip extends HudComponentMovable { private String itemString; private int itemColor; private double itemTime = 0.0; + private boolean itemHasNbt = false; private String systemString; private int systemColor; @@ -58,7 +59,11 @@ public class HudComponentDynamicTooltip extends HudComponentMovable { @Override public int getTrueXSize() { - return mc.font.stringWidth(getDisplayText()); + int width = mc.font.stringWidth(getDisplayText()); + if (this.itemTime > 0.0 && this.itemHasNbt) { + width += mc.font.stringWidth(" •"); + } + return width; } private String getDisplayText() { @@ -107,7 +112,7 @@ public class HudComponentDynamicTooltip extends HudComponentMovable { activeTime = this.itemTime; } - if (activeString == null || activeTime <= 0.0) return; + if (activeString == null) return; double alpha = (activeTime < this.fadeTime) ? (activeTime / this.fadeTime) : 1.0; int a = (int) (alpha * 255); @@ -125,6 +130,15 @@ public class HudComponentDynamicTooltip extends HudComponentMovable { mc.font.render(activeString, x, y).setShadow().setColor(rgb).call(); + if (activeString.equals(this.itemString) && this.itemHasNbt) { + int nameWidth = mc.font.stringWidth(activeString); + + int magenta = Colors.allChatColors[TextFormatting.MAGENTA.id].getARGB(); + int bulletColor = (magenta & 0x00FFFFFF) | (a << 24); + + mc.font.render(" •", x + nameWidth, y).setShadow().setColor(bulletColor).call(); + } + GLRenderer.disableState(State.BLEND); } @@ -142,10 +156,12 @@ public class HudComponentDynamicTooltip extends HudComponentMovable { private void updateItemString(ItemStack item) { if (item == null) { this.itemString = null; + this.itemHasNbt = false; return; } this.itemString = item.getDisplayName(); this.itemColor = Colors.allChatColors[item.getDisplayColor()].getARGB(); + this.itemHasNbt = item.getData().containsKey("tileEntityData"); } private int getItemID(ItemStack stack) { diff --git a/game/client/src/main/java/net/minecraft/client/player/controller/PlayerController.java b/game/client/src/main/java/net/minecraft/client/player/controller/PlayerController.java index 2c6b86736..118ad0166 100644 --- a/game/client/src/main/java/net/minecraft/client/player/controller/PlayerController.java +++ b/game/client/src/main/java/net/minecraft/client/player/controller/PlayerController.java @@ -20,6 +20,7 @@ import net.minecraft.core.item.Item; import net.minecraft.core.item.ItemStack; import net.minecraft.core.item.tag.ItemTags; import net.minecraft.core.util.helper.Side; +import net.minecraft.core.world.ICarrySource; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; @@ -279,12 +280,8 @@ public abstract class PlayerController { final @NotNull Block block = world.getBlockType(tilePos); if (player.getHeldObject() == null) { - if (player.isSneaking() && itemStack == null) { // If crouched and hand empty try to pickup block entity - final @Nullable TileEntity tileEntity = world.getTileEntity(tilePos); - if (tileEntity != null && tileEntity.canBeCarried(world, player)) { - player.setHeldObject(tileEntity.pickup(world, player)); - return true; - } + if (player.isSneaking() && itemStack == null) { + if (ICarrySource.tryPickUpFromWorld(world, player, tilePos) != null) return true; } if (!player.isSneaking() || itemStack == null) { // If standing or hand empty perform block right click method if (block.onInteracted(world, tilePos, player, side, xPlaced, yPlaced)) { diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericBed.java b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericBed.java index b97790131..da3036cf0 100644 --- a/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericBed.java +++ b/game/client/src/main/java/net/minecraft/client/render/block/model/generic/BlockModelGenericBed.java @@ -21,7 +21,7 @@ public class BlockModelGenericBed extends BlockModelGeneri @Override public boolean renderAttached(@NotNull TessellatorGeneral tessellator, @NotNull WorldSource worldSource, @NotNull TilePosc tilePos, boolean cullFaces, @Nullable IconCoordinate overrideTexture) { - int direction = BlockLogicBed.getDirection(worldSource.getBlockData(tilePos)); + int direction = BlockLogicBed.DIRECTION.get(worldSource.getBlockData(tilePos)); return switch (direction) { case 0 -> getModel(worldSource, tilePos).renderAttached(this, tessellator, worldSource, tilePos, 0, 3, 0, 0, 0, 0, false, cullFaces, overrideTexture); case 1 -> getModel(worldSource, tilePos).renderAttached(this, tessellator, worldSource, tilePos, 0, 2, 0, 0, 0, 0, false, cullFaces, overrideTexture); @@ -32,6 +32,6 @@ public class BlockModelGenericBed extends BlockModelGeneri @Override public @NotNull StaticBlockModel getModelFromData(int data) { - return BlockLogicBed.isBlockHeadOfBed(data) ? this.head : this.staticModel; + return BlockLogicBed.IS_HEAD.bool(data) ? this.head : this.staticModel; } } diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPlayer.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPlayer.java index af1e997ee..271270fd2 100644 --- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPlayer.java +++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPlayer.java @@ -16,7 +16,7 @@ import net.minecraft.client.render.tessellator.TessellatorGeneral; import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.client.render.tileentity.TileEntityRenderer; import net.minecraft.core.block.entity.TileEntity; -import net.minecraft.core.block.motion.CarriedBlock; +import net.minecraft.core.block.motion.ICarriedBlock; import net.minecraft.core.entity.player.Player; import net.minecraft.core.player.gamemode.Gamemodes; import net.minecraft.core.util.helper.MathHelper; @@ -68,7 +68,7 @@ public class MobRendererPlayer extends MobRendererBipedArmored { } public void drawHeldObject(final Player player, final float partialTick) { - if (player.getHeldObject() instanceof CarriedBlock carriedBlock) { + if (player.getHeldObject() instanceof ICarriedBlock carriedBlock) { if (this.container == null || this.container.world != player.world) { this.container = new BlocksContainer(player.world); } @@ -91,18 +91,18 @@ public class MobRendererPlayer extends MobRendererBipedArmored { this.container.setLightReferenceEntity(player); this.container.partialTick = partialTick; - this.container.setBlock(blockPos.x, blockPos.y, blockPos.z, carriedBlock.blockId, carriedBlock.metadata, carriedBlock.entity); + this.container.setBlock(blockPos.x, blockPos.y, blockPos.z, carriedBlock.block().id(), carriedBlock.metadata(), carriedBlock.entity()); BlockModelDispatcher.getInstance().getDispatch(carriedBlock.block()).renderNoCulling(GLRenderer.getTessellator(), this.container, blockPos); tessellator.draw(); tessellator.setTranslation(0, 0, 0); this.container.setLightReferenceEntity(null); this.container.clear(); - final TileEntityRenderer renderer = TileEntityRenderDispatcher.instance.getRenderer(carriedBlock.entity); + final TileEntityRenderer renderer = TileEntityRenderDispatcher.instance.getRenderer(carriedBlock.entity()); if (renderer != null) { - carriedBlock.entity.worldObj = player.world; - renderer.doRender(tessellator, carriedBlock.entity, -0.5, -0.5, -0.5, partialTick); - carriedBlock.entity.worldObj = null; + carriedBlock.entity().worldObj = player.world; + renderer.doRender(tessellator, carriedBlock.entity(), -0.5, -0.5, -0.5, partialTick); + carriedBlock.entity().worldObj = null; } GLRenderer.popFrame(); 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 32cf8f1b6..e8f021467 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.PackedField; import net.minecraft.core.util.helper.Direction; import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.World; @@ -38,58 +39,50 @@ public class BlockLogicBed int data = world.getBlockData(tilePos); final @NotNull TilePosc headPos; final @NotNull TilePosc footPos; - if (!isBlockHeadOfBed(data)) { - final int dir = getDirection(data); + if (!IS_HEAD.bool(data)) { + final int dir = DIRECTION.get(data); headPos = tilePos; footPos = tilePos.add(headBlockToFootBlockMap[dir].getDirection(), new TilePos()); + if (world.getBlockType(footPos) != this.block) return true; } else { - final int dir = getDirection(data); - headPos = tilePos.sub(headBlockToFootBlockMap[dir].getDirection(), new TilePos()); + final int dir = DIRECTION.get(data); footPos = tilePos; - } - - // Check if bed is not complete - if (!isBlockHeadOfBed(data)) { - if (world.getBlockType(footPos) != this.block) { - return true; - } - data = world.getBlockData(tilePos); + headPos = tilePos.sub(headBlockToFootBlockMap[dir].getDirection(), new TilePos()); + if (world.getBlockType(headPos) != this.block) return true; } // Explode in invalid dimensions if (!world.getWorldType().mayRespawn()) { - world.setBlockTypeNotify(tilePos, Blocks.AIR); - if (world.getBlockType(footPos) == this.block) { - world.setBlockTypeNotify(footPos, Blocks.AIR); - } + world.setBlockType(headPos, Blocks.AIR); + assert world.getBlockType(footPos) == this.block; // made sure from above + world.setBlockType(footPos, Blocks.AIR); + + // prevents dupe... tho the dupe would need to be pretty funny to work + world.notifyBlockChange(headPos, Blocks.AIR); + world.notifyBlockChange(footPos, Blocks.AIR); + player.addStat(Achievements.SLEEP_NETHER, 1); world.createExplosion(null, tilePos.x() + 0.5F, tilePos.y() + 0.5F, tilePos.z() + 0.5F, 5F, true, false); return true; } // Check if bed is occupied, and set occupied - if (isBedOccupied(data)) { - @Nullable Player sleepingPlayer = null; + if (IS_OCCUPIED.bool(data)) { + // @Nullable Player sleepingPlayer = null; for (final @NotNull Player p : world.players) { - if (p.isPlayerSleeping()) { - final @NotNull TilePos pos = Objects.requireNonNull(p.bedTilePos); - if (pos.equals(footPos)) { - sleepingPlayer = p; - } + if (!p.isPlayerSleeping()) continue; + final var otherBedPos = Objects.requireNonNull(p.bedTilePos); + if (otherBedPos.equals(footPos)) { + player.sendTranslatedChatMessage("bed.occupied"); + return true; } } - if (sleepingPlayer == null) { - setBedOccupied(world, footPos, false); - } else { - player.sendTranslatedChatMessage("bed.occupied"); - return true; - } + world.setBlockData(footPos, IS_OCCUPIED.set(data, 0)); } - + // Sleep if (player.sleepInBedAt(footPos.x(), footPos.y(), footPos.z()) == EnumSleepStatus.OK) { - setBedOccupied(world, footPos, true); - return true; + world.setBlockData(footPos, IS_OCCUPIED.set(data, 1)); } return true; @@ -112,51 +105,41 @@ public class BlockLogicBed @Override public void onNeighborChanged(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Block block) { - final var state = new State(world, tilePos); - if (!state.hasOtherHalf(world, tilePos)) { + final var otherHalf = otherHalf(world, tilePos, world.getBlockData(tilePos)); + if (otherHalf == null) { world.setBlockTypeNotify(tilePos, Blocks.AIR); } } @Override public void onRemoved(final @NotNull World world, final @NotNull TilePosc tilePos, final int data) { - final var state = new State(data, world, tilePos); - if (state.hasOtherHalf(world, tilePos)) { + final var otherHalf = otherHalf(world, tilePos, data); + if (otherHalf != null) { // 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); + world.setBlockTypeNotify(otherHalf, Blocks.AIR); } } - protected static class State { - final boolean isHead; - final @NotNull Direction h2fDir; + public static final PackedField DIRECTION = new PackedField(0, 2); + public static final PackedField IS_OCCUPIED = new PackedField(2, 1); + public static final PackedField IS_HEAD = new PackedField(3, 1); - 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 static @Nullable TilePos otherHalf(final @NotNull World world, @NotNull TilePosc tilePos, int data) { + final var isHead = IS_HEAD.bool(data); + final var dir = DIRECTION.get(data); + final var direction = headBlockToFootBlockMap[DIRECTION.get(data)].getDirection(); + final var otherPos = (isHead) + ? tilePos.sub(direction, new TilePos()) + : tilePos.add(direction, 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; - } + if (!(world.getBlockType(otherPos).getLogic() instanceof BlockLogicBed)) return null; + final int otherData = world.getBlockData(otherPos); + if (isHead == IS_HEAD.bool(otherData)) return null; + if (dir != DIRECTION.get(otherData)) return null; + return otherPos; } @Override @@ -169,35 +152,8 @@ public class BlockLogicBed return Material.PISTON_DESTROY_ON_PUSH; } - 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_HEAD) != 0; - } - - public static boolean isBedOccupied(final int meta) { - return (meta & MASK_IS_OCCUPIED) != 0; - } - - public static int getDirection(final int meta) { - return meta & MASK_DIRECTION; - } - - public static void setBedOccupied(final @NotNull World world, final @NotNull TilePosc tilePos, final boolean flag) { - int l = world.getBlockData(tilePos); - if (flag) { - l |= MASK_IS_OCCUPIED; - } else { - l &= ~MASK_IS_OCCUPIED; - } - world.setBlockDataNotify(tilePos, l); - } - public static @Nullable TilePos getNearestEmptyTilePos(final @NotNull World world, final @NotNull TilePos tilePos, int attempts) { - final int data = world.getBlockData(tilePos); - final int direction = getDirection(data); + final int direction = DIRECTION.get(world.getBlockData(tilePos)); for (int d = 0; d <= 1; d++) { final @NotNull TilePos minPos = new TilePos( @@ -230,29 +186,10 @@ public class BlockLogicBed return null; } - public static final int[] headOfBedMap = { - 3, 4, 2, 5 + public static final @NotNull Side @NotNull [] headBlockToFootBlockMap = { + Side.SOUTH, + Side.WEST, + Side.NORTH, + Side.EAST }; - public static final int[] footToHeadMap = { - 2, 3, 0, 1 - }; - public static final int[][] bedDirection = { - { - 1, 0, 3, 2, 5, 4 - }, { - 1, 0, 5, 4, 2, 3 - }, { - 1, 0, 2, 3, 4, 5 - }, { - 1, 0, 4, 5, 3, 2 - } - }; - - public static final @NotNull Side @NotNull [] headBlockToFootBlockMap = - { - Side.SOUTH, - Side.WEST, - Side.NORTH, - Side.EAST - }; } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDoor.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDoor.java index a64af88db..d7163bb7e 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDoor.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDoor.java @@ -27,6 +27,7 @@ import org.joml.primitives.AABBdc; import java.util.function.Supplier; +// TODO this needs massive refactor public class BlockLogicDoor extends BlockLogic implements IPaintable { diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDoorPainted.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDoorPainted.java index 84b830ae8..7e8b34df3 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDoorPainted.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDoorPainted.java @@ -42,22 +42,24 @@ public class BlockLogicDoorPainted @Override public void removeDye(final @NotNull World world, final @NotNull TilePosc tilePos) { final int data = world.getBlockData(tilePos); - world.setBlockTypeDataNotify(tilePos, this.isTop ? Blocks.DOOR_PLANKS_OAK_TOP : Blocks.DOOR_PLANKS_OAK_BOTTOM, data & 0xF); + world.setBlockTypeData(tilePos, this.isTop ? Blocks.DOOR_PLANKS_OAK_TOP : Blocks.DOOR_PLANKS_OAK_BOTTOM, data & 0xF); if (this.isTop) { world.setBlockTypeDataNotify(tilePos.down(new TilePos()), Blocks.DOOR_PLANKS_OAK_BOTTOM, data & 0xF); } else { world.setBlockTypeDataNotify(tilePos.up(new TilePos()), Blocks.DOOR_PLANKS_OAK_TOP, data & 0xF); } + world.notifyBlockChange(tilePos, this.block); } - + @Override public void setColor(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull DyeColor color) { final int data = world.getBlockData(tilePos); - world.setBlockDataNotify(tilePos, data & 0xF | this.toMetadata(color)); + world.setBlockData(tilePos, data & 0xF | this.toMetadata(color)); if (this.isTop) { world.setBlockDataNotify(tilePos.down(new TilePos()), data & 0xF | this.toMetadata(color)); } else { world.setBlockDataNotify(tilePos.up(new TilePos()), data & 0xF | this.toMetadata(color)); } + world.notifyBlockChange(tilePos, this.block); } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java index 558b84a1c..89f9f5c6c 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java @@ -41,7 +41,7 @@ public abstract class BlockLogicFluid extends BlockLogic { return (float) (data + 1) / 8F; } - protected int getDepth(final WorldSource worldSource, final @NotNull TilePosc tilePos) { + public int getDepth(final WorldSource worldSource, final @NotNull TilePosc tilePos) { if (worldSource.getBlockMaterial(tilePos) != this.material) { return -1; } else { diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluidFlowing.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluidFlowing.java index d8ac4e7b0..5a927c736 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluidFlowing.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluidFlowing.java @@ -48,13 +48,11 @@ public class BlockLogicFluidFlowing extends BlockLogicFluid { if (newFlowDecay >= 8 || surroundingFlowDecay < 0) { newFlowDecay = -1; } - if (getDepth(world, tilePos.up(queryPos)) >= 0) { - int flowDecayAbove = getDepth(world, tilePos.up(queryPos)); - if (flowDecayAbove >= 8) { - newFlowDecay = flowDecayAbove; - } else { - newFlowDecay = flowDecayAbove + 8; - } + int flowDecayAbove = getDepth(world, tilePos.up(queryPos)); + if (flowDecayAbove >= 8) { + newFlowDecay = flowDecayAbove; + } else if (flowDecayAbove >= 0) { + newFlowDecay = flowDecayAbove + 8; } // Become source block if (this.maxCount >= 2 && this.fluid.canBecomeSource(this, world, tilePos, rand)) { @@ -71,7 +69,7 @@ public class BlockLogicFluidFlowing extends BlockLogicFluid { } else { world.setBlockDataNotify(tilePos, localFlowDecay); world.scheduleBlockUpdate(tilePos, this.block, tickDelay()); - world.notifyBlocksOfNeighborChange(tilePos, this.block); + world.notifyBlocksOfNeighborChange(tilePos, this.block); // ? } } else { setFluidStill(world, tilePos); diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFurnace.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFurnace.java index d85e55d52..1b9e33702 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFurnace.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFurnace.java @@ -20,7 +20,6 @@ import java.util.Random; public class BlockLogicFurnace extends BlockLogicRotatable { private static final Logger LOGGER = LogUtils.getLogger(); - public static boolean keepFurnaceInventory = false; protected final boolean isActive; @@ -78,9 +77,7 @@ public class BlockLogicFurnace extends BlockLogicRotatable { } public static void updateFurnaceBlockState(@NotNull World world, @NotNull TilePos tilePos, boolean lit) { - int meta = world.getBlockData(tilePos); - TileEntity tileEntity = world.getTileEntity(tilePos); - if (tileEntity == null) { + if (!(world.getTileEntity(tilePos) instanceof TileEntityFurnace)) { String msg = "Furnace is missing Tile Entity at " + tilePos + ", block will be removed!"; if (Global.BUILD_CHANNEL.isUnstableBuild()) { throw new RuntimeException(msg); @@ -89,16 +86,11 @@ public class BlockLogicFurnace extends BlockLogicRotatable { LOGGER.warn(msg); return; } - keepFurnaceInventory = true; - if (lit) { - world.setBlockTypeNotify(tilePos, Blocks.FURNACE_STONE_ACTIVE); - } else { - world.setBlockTypeNotify(tilePos, Blocks.FURNACE_STONE_IDLE); - } - keepFurnaceInventory = false; - world.setBlockDataNotify(tilePos, meta); - tileEntity.validate(); - world.setTileEntity(tilePos, tileEntity); + final int meta = world.getBlockData(tilePos); + final var block = (lit) + ? Blocks.FURNACE_STONE_ACTIVE + : Blocks.FURNACE_STONE_IDLE; + world.setBlockTypeDataRaw(tilePos, block, meta); + world.notifyBlockChange(tilePos, block); } - } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFurnaceBlast.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFurnaceBlast.java index 211ee3511..d5610e1ea 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFurnaceBlast.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFurnaceBlast.java @@ -23,7 +23,6 @@ public class BlockLogicFurnaceBlast extends BlockLogicRotatable private static final Logger LOGGER = LogUtils.getLogger(); protected final boolean isActive; - public static boolean keepFurnaceInventory = false; public BlockLogicFurnaceBlast(Block block, boolean active) { @@ -81,27 +80,21 @@ public class BlockLogicFurnaceBlast extends BlockLogicRotatable } public static void updateFurnaceBlockState(@NotNull World world, @NotNull TilePos tilePos, boolean lit) { - int meta = world.getBlockData(tilePos); - TileEntity tileEntity = world.getTileEntity(tilePos); - if(tileEntity == null) { - String msg = "Blast Furnace is missing Tile Entity at " + tilePos + ", block will be removed!"; + if(!(world.getTileEntity(tilePos) instanceof TileEntityFurnaceBlast)) { + String msg = "Blast Furnace is missing Tile Entity at " + tilePos + ", block will be removed!"; if(Global.BUILD_CHANNEL.isUnstableBuild()) { - throw new RuntimeException(msg); + throw new RuntimeException(msg); } world.setBlockTypeNotify(tilePos, Blocks.AIR); LOGGER.warn(msg); return; } - keepFurnaceInventory = true; - if(lit) { - world.setBlockTypeNotify(tilePos, Blocks.FURNACE_BLAST_ACTIVE); - } else { - world.setBlockTypeNotify(tilePos, Blocks.FURNACE_BLAST_IDLE); - } - keepFurnaceInventory = false; - world.setBlockDataNotify(tilePos, meta); - tileEntity.validate(); - world.setTileEntity(tilePos, tileEntity); + final int meta = world.getBlockData(tilePos); + final var block = (lit) + ? Blocks.FURNACE_BLAST_ACTIVE + : Blocks.FURNACE_BLAST_IDLE; + world.setBlockTypeDataRaw(tilePos, block, meta); + world.notifyBlockChange(tilePos, block); } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicJukebox.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicJukebox.java index a546093c9..d21de68de 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicJukebox.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicJukebox.java @@ -44,13 +44,10 @@ public class BlockLogicJukebox extends BlockLogic { } } - public void ejectRecord(@NotNull World world, @NotNull TilePosc tilePos) - { - if(world.isClientSide) - { - return; + public void ejectRecord(@NotNull World world, @NotNull TilePosc tilePos) { + if(world.isClientSide) return; + if (world.getTileEntity(tilePos) instanceof TileEntityJukebox jukebox) { + jukebox.dropContents(world, tilePos.x(), tilePos.y(), tilePos.z()); } - TileEntity tileEntity = world.getTileEntity(tilePos); - if (tileEntity != null) tileEntity.dropContents(world, tilePos.x(), tilePos.y(), tilePos.z()); } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLadder.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLadder.java index a6371b971..7969695e9 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLadder.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLadder.java @@ -12,6 +12,7 @@ import net.minecraft.core.world.WorldSource; import net.minecraft.core.world.pos.TilePos; import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.joml.primitives.AABBd; import org.joml.primitives.AABBdc; @@ -74,7 +75,7 @@ public class BlockLogicLadder extends BlockLogic implements ISupportable { return true; } - public Side getSideForPlacement(@NotNull World world, @NotNull TilePos tilePos, @NotNull Side clickedSide) { + public @Nullable Side getSideForPlacement(@NotNull World world, @NotNull TilePos tilePos, @NotNull Side clickedSide) { TilePosc p = tilePos; if (!world.canPlaceInsideBlock(tilePos)) { p = p.add(clickedSide.getDirection(), new TilePos()); @@ -97,7 +98,7 @@ public class BlockLogicLadder extends BlockLogic implements ISupportable { /** * Returns the side of the block the ladder is attached to */ - public Side getSideFromMeta(int meta) { + public @NotNull Side getSideFromMeta(int meta) { if (meta == 2) return Side.NORTH; if (meta == 3) return Side.SOUTH; if (meta == 4) return Side.WEST; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPressurePlate.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPressurePlate.java index 5a0ab3cdd..32902034e 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPressurePlate.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPressurePlate.java @@ -135,13 +135,13 @@ public class BlockLogicPressurePlate extends BlockLogic implem } if (isSteppedOn && !isPressed) { world.setBlockDataNotify(tilePos, meta | MASK_POWERED); - world.notifyBlocksOfNeighborChange(tilePos, this.block); + // world.notifyBlocksOfNeighborChange(tilePos, this.block); world.notifyBlocksOfNeighborChange(tilePos.add(dir, new TilePos()), this.block); world.markBlocksDirty(tilePos, tilePos); world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (double) tilePos.x() + 0.5D, (double) tilePos.y() + 0.1D, (double) tilePos.z() + 0.5D, "random.click", 0.3F, 0.6F); } else if (!isSteppedOn && isPressed) { world.setBlockDataNotify(tilePos, meta & ~MASK_POWERED); - world.notifyBlocksOfNeighborChange(tilePos, this.block); + // world.notifyBlocksOfNeighborChange(tilePos, this.block); world.notifyBlocksOfNeighborChange(tilePos.add(dir, new TilePos()), this.block); world.markBlocksDirty(tilePos, tilePos); world.playSoundEffect(null, SoundCategory.WORLD_SOUNDS, (double) tilePos.x() + 0.5D, (double) tilePos.y() + 0.1D, (double) tilePos.z() + 0.5D, "random.click", 0.3F, 0.5F); diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRailDetector.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRailDetector.java index 0276813f0..c20b3a53b 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRailDetector.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRailDetector.java @@ -13,6 +13,7 @@ import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; import org.joml.primitives.AABBd; +// TODO detector rail has some freaky behaviors, investigate and fix public class BlockLogicRailDetector extends BlockLogicRail { public BlockLogicRailDetector(@NotNull Block block) { super(block, true); diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSponge.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSponge.java index facc4d952..171e60515 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSponge.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSponge.java @@ -31,22 +31,23 @@ public class BlockLogicSponge extends BlockLogic { world.spawnParticle("largesmoke", (double) tilePos.x() + Math.random(), (double) tilePos.y() + Math.random(), (double) tilePos.z() + Math.random(), 0.0D, 0.0D, 0.0D, 0, false); } } - final byte radius = 2; + // TODO this sends far more updates than needed if (!this.isWet && inWater(world, tilePos)) { + world.setBlockTypeNotify(tilePos, Blocks.SPONGE_WET); TilePos queryPos = new TilePos(); - for (queryPos.x = tilePos.x() - radius; queryPos.x <= tilePos.x() + radius; queryPos.x++) { - for (queryPos.y = tilePos.y() - radius; queryPos.y <= tilePos.y() + radius; queryPos.y++) { - for (queryPos.z = tilePos.z() - radius; queryPos.z <= tilePos.z() + radius; queryPos.z++) { + for (queryPos.x = tilePos.x() - RADIUS; queryPos.x <= tilePos.x() + RADIUS; queryPos.x++) { + for (queryPos.y = tilePos.y() - RADIUS; queryPos.y <= tilePos.y() + RADIUS; queryPos.y++) { + for (queryPos.z = tilePos.z() - RADIUS; queryPos.z <= tilePos.z() + RADIUS; queryPos.z++) { if (world.getBlockType(queryPos).hasTag(BlockTags.IS_WATER)) { world.setBlockTypeNotify(queryPos, Blocks.AIR); } } } } - world.setBlockTypeNotify(tilePos, Blocks.SPONGE_WET); } } + private static final int RADIUS = 2; public boolean inWater(@NotNull World world, @NotNull TilePosc tilePos) { TilePos queryPos = new TilePos(); @@ -71,11 +72,10 @@ public class BlockLogicSponge extends BlockLogic { @Override public void onRemoved(@NotNull World world, @NotNull TilePosc tilePos, int data) { if (!this.isWet) { - byte radius = 2; TilePos queryPos = new TilePos(tilePos); - for (queryPos.x = tilePos.x() - radius; queryPos.x <= tilePos.x() + radius; queryPos.x++) { - for (queryPos.y = tilePos.y() - radius; queryPos.y <= tilePos.y() + radius; queryPos.y++) { - for (queryPos.z = tilePos.z() - radius; queryPos.z <= tilePos.z() + radius; queryPos.z++) { + for (queryPos.x = tilePos.x() - RADIUS; queryPos.x <= tilePos.x() + RADIUS; queryPos.x++) { + for (queryPos.y = tilePos.y() - RADIUS; queryPos.y <= tilePos.y() + RADIUS; queryPos.y++) { + for (queryPos.z = tilePos.z() - RADIUS; queryPos.z <= tilePos.z() + RADIUS; queryPos.z++) { world.notifyBlocksOfNeighborChange(queryPos, world.getBlockType(queryPos)); } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrommel.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrommel.java index 37191017c..b48bc5088 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrommel.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrommel.java @@ -18,10 +18,11 @@ import org.slf4j.Logger; import java.util.Random; +// TODO refactor reuse + public class BlockLogicTrommel extends BlockLogicRotatable { private static final Logger LOGGER = LogUtils.getLogger(); - public static boolean keepTrommelInventory = false; private final boolean isActive; public BlockLogicTrommel(@NotNull Block block, @NotNull Material material, boolean isActive) @@ -62,9 +63,7 @@ public class BlockLogicTrommel extends BlockLogicRotatable public static void updateTrommelBlockState(@NotNull World world, @NotNull TilePos tilepos, boolean lit) { - int data = world.getBlockData(tilepos); - TileEntity tileEntity = world.getTileEntity(tilepos); - if(tileEntity == null) { + if(!(world.getTileEntity(tilepos) instanceof TileEntityTrommel)) { String msg = "Trommel is missing Tile Entity at " + tilepos + ", block will be removed!"; if(Global.BUILD_CHANNEL.isUnstableBuild()) { throw new RuntimeException(msg); @@ -73,17 +72,9 @@ public class BlockLogicTrommel extends BlockLogicRotatable LOGGER.warn(msg); return; } - keepTrommelInventory = true; - if(lit) - { - world.setBlockTypeNotify(tilepos, Blocks.TROMMEL_ACTIVE); - } else - { - world.setBlockTypeNotify(tilepos, Blocks.TROMMEL_IDLE); - } - keepTrommelInventory = false; - world.setBlockDataNotify(tilepos, data); - tileEntity.validate(); - world.setTileEntity(tilepos, tileEntity); + final int data = world.getBlockData(tilepos); + final var block = (lit) ? Blocks.TROMMEL_ACTIVE : Blocks.TROMMEL_IDLE; + world.setBlockTypeDataRaw(tilepos, block, data); + world.notifyBlockChange(tilepos, block); } } diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntity.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntity.java index df435d221..b7a2a0605 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntity.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntity.java @@ -15,6 +15,8 @@ import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.ICarriable; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; + import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -133,6 +135,7 @@ public abstract class TileEntity implements ICarriable } + // TODO TilePos refactor public void dropContents(World world, int x, int y, int z) { } @@ -185,13 +188,7 @@ public abstract class TileEntity implements ICarriable carriedBlock.block().dropBlockWithCause(world, EnumDropCause.WORLD, holderX, holderY, holderZ, carriedBlock.metadata, this, null); // TODO this might be scuffed since the position won't have correlated to a real block } - @Override - public boolean canBeCarried(World world, Entity potentialHolder) { - return false; - } - - @Override - public ICarriable pickup(World world, Entity holder) { + protected @NotNull ICarriable pickup(@NotNull World world, @NotNull Entity holder, @NotNull TilePosc tilePos_) { Block currentBlock = world.getBlock(tilePos.x, tilePos.y, tilePos.z); int currentMeta = world.getBlockMetadata(tilePos.x, tilePos.y, tilePos.z); world.removeBlockTileEntity(tilePos.x, tilePos.y, tilePos.z); diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityActivator.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityActivator.java index 247dc4f2f..374e034f4 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityActivator.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityActivator.java @@ -11,13 +11,17 @@ import net.minecraft.core.entity.player.Player; import net.minecraft.core.item.ItemStack; import net.minecraft.core.player.inventory.container.Container; import net.minecraft.core.util.helper.Direction; +import net.minecraft.core.world.ICarriable; +import net.minecraft.core.world.ICarrySource; import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePosc; + import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Random; -public class TileEntityActivator extends TileEntity implements Container { +public class TileEntityActivator extends TileEntity implements Container, ICarrySource { public static final int CONTAINER_SIZE = 9; private ItemStack[] dispenserContents; private final Random random; @@ -228,10 +232,11 @@ public class TileEntityActivator extends TileEntity implements Container { } @Override - public boolean canBeCarried(World world, Entity potentialHolder) { - return true; + public @NotNull ICarriable pickup(@NotNull World world, @NotNull Entity holder, @NotNull TilePosc tilePos_) { + return super.pickup(world, holder, tilePos_); } + @Override public CarriedBlock getCarriedEntry(World world, Entity holder, Block currentBlock, int currentMeta) { return super.getCarriedEntry(world, holder, currentBlock, BlockLogicRotatable.setDirection(currentMeta, Direction.NORTH) /*Reset rotation, primarily to make it render in hand properly*/); diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityBasket.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityBasket.java index 67bee6f83..67f4f074d 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityBasket.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityBasket.java @@ -8,21 +8,24 @@ import net.minecraft.core.block.Blocks; import net.minecraft.core.entity.Entity; import net.minecraft.core.entity.EntityItem; import net.minecraft.core.entity.player.Player; -import net.minecraft.core.world.save.conversion.ItemConverters; import net.minecraft.core.item.Item; import net.minecraft.core.item.ItemStack; import com.mojang.nbt.tags.CompoundTag; import com.mojang.nbt.tags.ListTag; import net.minecraft.core.net.packet.Packet; import net.minecraft.core.net.packet.PacketTileEntityData; +import net.minecraft.core.world.ICarriable; +import net.minecraft.core.world.ICarrySource; import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePosc; + import org.jetbrains.annotations.NotNull; import org.joml.primitives.AABBd; import org.joml.primitives.AABBdc; import static net.minecraft.core.world.save.conversion.ItemConverters.legacyBucketConverter; -public class TileEntityBasket extends TileEntity { +public class TileEntityBasket extends TileEntity implements ICarrySource { private int numUnitsInside = 0; private final Object2IntMap contents = new Object2IntArrayMap<>(); @@ -239,8 +242,8 @@ public class TileEntityBasket extends TileEntity { } @Override - public boolean canBeCarried(final World world, final Entity potentialHolder) { - return true; + public @NotNull ICarriable pickup(@NotNull World world, @NotNull Entity holder, @NotNull TilePosc tilePos_) { + return super.pickup(world, holder, tilePos_); } private static final class BasketEntry { diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityChest.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityChest.java index 3102e18bd..4b05280a8 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityChest.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityChest.java @@ -13,13 +13,17 @@ import com.mojang.nbt.tags.CompoundTag; import com.mojang.nbt.tags.ListTag; import net.minecraft.core.player.inventory.InventorySorter; import net.minecraft.core.util.helper.Direction; +import net.minecraft.core.world.ICarriable; +import net.minecraft.core.world.ICarrySource; import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePosc; + import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; public class TileEntityChest extends TileEntity - implements Container + implements Container, ICarrySource { private static final Logger LOGGER = LogUtils.getLogger(); @@ -152,8 +156,8 @@ public class TileEntityChest extends TileEntity } @Override - public boolean canBeCarried(World world, Entity potentialHolder) { - return true; + public @NotNull ICarriable pickup(@NotNull World world, @NotNull Entity holder, @NotNull TilePosc tilePos_) { + return super.pickup(world, holder, tilePos_); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityDispenser.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityDispenser.java index ffb16000b..91bdcd264 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityDispenser.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityDispenser.java @@ -12,14 +12,18 @@ import net.minecraft.core.player.inventory.container.Container; import com.mojang.nbt.tags.CompoundTag; import com.mojang.nbt.tags.ListTag; import net.minecraft.core.util.helper.Direction; +import net.minecraft.core.world.ICarriable; +import net.minecraft.core.world.ICarrySource; import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePosc; + import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Random; public class TileEntityDispenser extends TileEntity - implements Container + implements Container, ICarrySource { public TileEntityDispenser() @@ -215,8 +219,8 @@ public class TileEntityDispenser extends TileEntity } @Override - public boolean canBeCarried(World world, Entity potentialHolder) { - return true; + public @NotNull ICarriable pickup(@NotNull World world, @NotNull Entity holder, @NotNull TilePosc tilePos_) { + return super.pickup(world, holder, tilePos_); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnace.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnace.java index 8e56b16a6..006d87b58 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnace.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnace.java @@ -13,13 +13,15 @@ import net.minecraft.core.entity.Entity; import net.minecraft.core.entity.EntityItem; import net.minecraft.core.entity.player.Player; import net.minecraft.core.item.ItemBucket; -import net.minecraft.core.item.Items; import net.minecraft.core.item.ItemStack; import net.minecraft.core.net.packet.PacketTileEntityData; import net.minecraft.core.net.packet.Packet; import net.minecraft.core.player.inventory.container.Container; import net.minecraft.core.util.helper.Side; +import net.minecraft.core.world.ICarriable; +import net.minecraft.core.world.ICarrySource; import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,7 +29,7 @@ import java.util.List; import java.util.Random; public class TileEntityFurnace extends TileEntity - implements Container + implements Container, ICarrySource { public static final int SLOT_INGREDIENT = 0; public static final int SLOT_FUEL = 1; @@ -333,40 +335,36 @@ public class TileEntityFurnace extends TileEntity @Override public void dropContents(World world, int x, int y, int z) { super.dropContents(world, x, y, z); - if(!BlockLogicFurnace.keepFurnaceInventory) + label0: + for(int l = 0; l < this.getContainerSize(); l++) { - label0: - for(int l = 0; l < this.getContainerSize(); l++) + ItemStack itemstack = this.getItem(l); + if(itemstack == null) { - ItemStack itemstack = this.getItem(l); - if(itemstack == null) + continue; + } + float f = random.nextFloat() * 0.8F + 0.1F; + float f1 = random.nextFloat() * 0.8F + 0.1F; + float f2 = random.nextFloat() * 0.8F + 0.1F; + do + { + if(itemstack.stackSize <= 0) { - continue; + continue label0; } - float f = random.nextFloat() * 0.8F + 0.1F; - float f1 = random.nextFloat() * 0.8F + 0.1F; - float f2 = random.nextFloat() * 0.8F + 0.1F; - do + int i1 = random.nextInt(21) + 10; + if(i1 > itemstack.stackSize) { - if(itemstack.stackSize <= 0) - { - continue label0; - } - int i1 = random.nextInt(21) + 10; - if(i1 > itemstack.stackSize) - { - i1 = itemstack.stackSize; - } - itemstack.stackSize -= i1; - EntityItem entityItem = new EntityItem(world, (float) x + f, (float) y + f1, (float) z + f2, new ItemStack(itemstack.itemID, i1, itemstack.getMetadata())); - float f3 = 0.05F; - entityItem.xd = (float)random.nextGaussian() * f3; - entityItem.yd = (float)random.nextGaussian() * f3 + 0.2F; - entityItem.zd = (float)random.nextGaussian() * f3; - world.entityJoinedWorld(entityItem); - } while(true); - } - + i1 = itemstack.stackSize; + } + itemstack.stackSize -= i1; + EntityItem entityItem = new EntityItem(world, (float) x + f, (float) y + f1, (float) z + f2, new ItemStack(itemstack.itemID, i1, itemstack.getMetadata())); + float f3 = 0.05F; + entityItem.xd = (float)random.nextGaussian() * f3; + entityItem.yd = (float)random.nextGaussian() * f3 + 0.2F; + entityItem.zd = (float)random.nextGaussian() * f3; + world.entityJoinedWorld(entityItem); + } while(true); } } @@ -398,8 +396,8 @@ public class TileEntityFurnace extends TileEntity } @Override - public boolean canBeCarried(World world, Entity potentialHolder) { - return true; + public @NotNull ICarriable pickup(@NotNull World world, @NotNull Entity holder, @NotNull TilePosc tilePos_) { + return super.pickup(world, holder, tilePos_); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnaceBlast.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnaceBlast.java index 5414b53e6..61cfb1c7b 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnaceBlast.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnaceBlast.java @@ -17,8 +17,12 @@ import net.minecraft.core.net.packet.Packet; import net.minecraft.core.net.packet.PacketTileEntityData; import net.minecraft.core.player.inventory.container.Container; import net.minecraft.core.util.helper.Side; +import net.minecraft.core.world.ICarriable; +import net.minecraft.core.world.ICarrySource; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.pos.TilePosc; + import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -26,7 +30,7 @@ import java.util.List; import java.util.Random; public class TileEntityFurnaceBlast extends TileEntity - implements Container + implements Container, ICarrySource { public static final int SLOT_LEFT = 0; public static final int SLOT_RIGHT = 1; @@ -295,32 +299,30 @@ public class TileEntityFurnaceBlast extends TileEntity @Override public void dropContents(final World world, final int x, final int y, final int z) { super.dropContents(world, x, y, z); - if (!BlockLogicFurnaceBlast.keepFurnaceInventory) { -slotLoop: for (int slot = 0; slot < this.getContainerSize(); slot++) { - final ItemStack item = this.getItem(slot); - if (item == null) { - continue; - } - final float rx = this.random.nextFloat() * 0.8F + 0.1F; - final float ry = this.random.nextFloat() * 0.8F + 0.1F; - final float rz = this.random.nextFloat() * 0.8F + 0.1F; - do { - if (item.stackSize <= 0) { - continue slotLoop; - } - int stackSize = this.random.nextInt(21) + 10; - if (stackSize > item.stackSize) { - stackSize = item.stackSize; - } - item.stackSize -= stackSize; - final EntityItem entityItem = new EntityItem(world, (float) x + rx, (float) y + ry, (float) z + rz, new ItemStack(item.itemID, stackSize, item.getMetadata())); - final float velocityScale = 0.05F; - entityItem.xd = (float) this.random.nextGaussian() * velocityScale; - entityItem.yd = (float) this.random.nextGaussian() * velocityScale + 0.2F; - entityItem.zd = (float) this.random.nextGaussian() * velocityScale; - world.entityJoinedWorld(entityItem); - } while (true); + slotLoop: for (int slot = 0; slot < this.getContainerSize(); slot++) { + final ItemStack item = this.getItem(slot); + if (item == null) { + continue; } + final float rx = this.random.nextFloat() * 0.8F + 0.1F; + final float ry = this.random.nextFloat() * 0.8F + 0.1F; + final float rz = this.random.nextFloat() * 0.8F + 0.1F; + do { + if (item.stackSize <= 0) { + continue slotLoop; + } + int stackSize = this.random.nextInt(21) + 10; + if (stackSize > item.stackSize) { + stackSize = item.stackSize; + } + item.stackSize -= stackSize; + final EntityItem entityItem = new EntityItem(world, (float) x + rx, (float) y + ry, (float) z + rz, new ItemStack(item.itemID, stackSize, item.getMetadata())); + final float velocityScale = 0.05F; + entityItem.xd = (float) this.random.nextGaussian() * velocityScale; + entityItem.yd = (float) this.random.nextGaussian() * velocityScale + 0.2F; + entityItem.zd = (float) this.random.nextGaussian() * velocityScale; + world.entityJoinedWorld(entityItem); + } while (true); } } @@ -352,8 +354,8 @@ slotLoop: for (int slot = 0; slot < this.getContainerSize(); slot++) { } @Override - public boolean canBeCarried(final World world, final Entity potentialHolder) { - return true; + public @NotNull ICarriable pickup(@NotNull World world, @NotNull Entity holder, @NotNull TilePosc tilePos_) { + return super.pickup(world, holder, tilePos_); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityJukebox.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityJukebox.java index 8151eceaf..1e6c941c6 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityJukebox.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityJukebox.java @@ -39,19 +39,25 @@ public class TileEntityJukebox extends TileEntity { @Override public void dropContents(World world, int x, int y, int z) { - if (record != 0) { - float f = 0.7F; - double d = (double) (world.rand.nextFloat() * f) + (double) (1.0F - f) * 0.5D; - double d1 = (double) (world.rand.nextFloat() * f) + (double) (1.0F - f) * 0.2D + 0.6D; - double d2 = (double) (world.rand.nextFloat() * f) + (double) (1.0F - f) * 0.5D; - EntityItem item = new EntityItem(world, (double) x + d, (double) y + d1, (double) z + d2, new ItemStack(record, 1, 0)); - item.pickupDelay = 10; - world.entityJoinedWorld(item); - - world.playBlockEvent(LevelListener.EVENT_JUKEBOX_TOGGLE, x, y, z, 0); - world.playRecord(null, null, x, y, z); - record = 0; - setChanged(); + if (this.record == 0) return; + final float scale = 0.7F; + final double dx,dy,dz; + dx = (double) (world.rand.nextFloat() * scale) + (double) (1.0F - scale) * 0.5D; + dy = (double) (world.rand.nextFloat() * scale) + (double) (1.0F - scale) * 0.2D + 0.6D; + dz = (double) (world.rand.nextFloat() * scale) + (double) (1.0F - scale) * 0.5D; + final var item = new EntityItem( + world, + (double) x + dx, (double) y + dy, (double) z + dz, + new ItemStack(this.record, 1, 0) + ); + item.pickupDelay = 10; + world.entityJoinedWorld(item); + world.playBlockEvent(LevelListener.EVENT_JUKEBOX_TOGGLE, x, y, z, 0); + world.playRecord(null, null, x, y, z); + this.record = 0; + setChanged(); + if (this.worldObj != null) { + // fix falling block mutating data of other blocks world.setBlockMetadataWithNotify(x, y, z, 0); } } diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntitySensor.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntitySensor.java index c9fa51b5b..b22191f02 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntitySensor.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntitySensor.java @@ -150,16 +150,11 @@ public class TileEntitySensor extends TileEntity { this.carriedBlock.blockId = Blocks.MOTION_SENSOR_IDLE.id(); } } else { - int meta = world.getBlockMetadata(this.tilePos.x, this.tilePos.y, this.tilePos.z); - int blockId; - if (active) { - blockId = Blocks.MOTION_SENSOR_ACTIVE.id(); - } else { - blockId = Blocks.MOTION_SENSOR_IDLE.id(); - } - world.setBlock(this.tilePos.x, this.tilePos.y, this.tilePos.z, blockId); - world.setBlockMetadata(this.tilePos.x, this.tilePos.y, this.tilePos.z, meta); - world.notifyBlockChange(this.tilePos.x, this.tilePos.y, this.tilePos.z, blockId); + int meta = world.getBlockData(this.tilePos); + final var block = (active) + ? Blocks.MOTION_SENSOR_ACTIVE + : Blocks.MOTION_SENSOR_IDLE; + world.setBlockTypeDataNotify(this.tilePos, block, meta); } } } diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityTrommel.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityTrommel.java index 2c305f854..21f4555e3 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityTrommel.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityTrommel.java @@ -19,13 +19,15 @@ import net.minecraft.core.entity.monster.MobSlime; import net.minecraft.core.entity.player.Player; import net.minecraft.core.item.Item; import net.minecraft.core.item.ItemBucket; -import net.minecraft.core.item.Items; import net.minecraft.core.item.ItemStack; import net.minecraft.core.player.inventory.container.Container; import net.minecraft.core.util.helper.Direction; import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePos; +import net.minecraft.core.world.ICarriable; +import net.minecraft.core.world.ICarrySource; +import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -36,7 +38,7 @@ import java.util.Map; import java.util.Random; public class TileEntityTrommel extends TileEntity - implements Container + implements Container, ICarrySource { private static final Logger LOGGER = LogUtils.getLogger(); @@ -432,37 +434,34 @@ public class TileEntityTrommel extends TileEntity @Override public void dropContents(World world, int x, int y, int z) { super.dropContents(world, x, y, z); - if (!BlockLogicTrommel.keepTrommelInventory) + if(world.getTileEntity(x, y, z) != null) { - if(world.getTileEntity(x, y, z) != null) + label0: + for (int l = 0; l < getContainerSize(); l++) { - label0: - for (int l = 0; l < getContainerSize(); l++) - { - ItemStack itemstack = getItem(l); - if (itemstack == null) { - continue; - } - float f = this.random.nextFloat() * 0.8F + 0.1F; - float f1 = this.random.nextFloat() * 0.8F + 0.1F; - float f2 = this.random.nextFloat() * 0.8F + 0.1F; - do { - if (itemstack.stackSize <= 0) { - continue label0; - } - int i1 = this.random.nextInt(21) + 10; - if (i1 > itemstack.stackSize) { - i1 = itemstack.stackSize; - } - itemstack.stackSize -= i1; - EntityItem item = new EntityItem(world, (float) x + f, (float) y + f1, (float) z + f2, new ItemStack(itemstack.itemID, i1, itemstack.getMetadata())); - float f3 = 0.05F; - item.xd = (float) this.random.nextGaussian() * f3; - item.yd = (float) this.random.nextGaussian() * f3 + 0.2F; - item.zd = (float) this.random.nextGaussian() * f3; - world.entityJoinedWorld(item); - } while (true); + ItemStack itemstack = getItem(l); + if (itemstack == null) { + continue; } + float f = this.random.nextFloat() * 0.8F + 0.1F; + float f1 = this.random.nextFloat() * 0.8F + 0.1F; + float f2 = this.random.nextFloat() * 0.8F + 0.1F; + do { + if (itemstack.stackSize <= 0) { + continue label0; + } + int i1 = this.random.nextInt(21) + 10; + if (i1 > itemstack.stackSize) { + i1 = itemstack.stackSize; + } + itemstack.stackSize -= i1; + EntityItem item = new EntityItem(world, (float) x + f, (float) y + f1, (float) z + f2, new ItemStack(itemstack.itemID, i1, itemstack.getMetadata())); + float f3 = 0.05F; + item.xd = (float) this.random.nextGaussian() * f3; + item.yd = (float) this.random.nextGaussian() * f3 + 0.2F; + item.zd = (float) this.random.nextGaussian() * f3; + world.entityJoinedWorld(item); + } while (true); } } } @@ -573,8 +572,8 @@ public class TileEntityTrommel extends TileEntity } @Override - public boolean canBeCarried(World world, Entity potentialHolder) { - return true; + public @NotNull ICarriable pickup(@NotNull World world, @NotNull Entity holder, @NotNull TilePosc tilePos_) { + return super.pickup(world, holder, tilePos_); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/motion/CarriedBlock.java b/game/core/src/main/java/net/minecraft/core/block/motion/CarriedBlock.java index 316bef176..88391617f 100644 --- a/game/core/src/main/java/net/minecraft/core/block/motion/CarriedBlock.java +++ b/game/core/src/main/java/net/minecraft/core/block/motion/CarriedBlock.java @@ -13,10 +13,12 @@ import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.ICarriable; import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePosc; + import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class CarriedBlock implements ICarriable { +public class CarriedBlock implements ICarriable, ICarriedBlock { public int blockId; // TODO replace with direct block ref public int metadata; public @Nullable TileEntity entity; @@ -64,12 +66,13 @@ public class CarriedBlock implements ICarriable { Block currentBlock = world.getBlock(x, y, z); if (currentBlock != null && !currentBlock.hasTag(BlockTags.PLACE_OVERWRITES)) return false; - world.setBlockAndMetadataWithNotify(x, y, z, blockId, metadata); + world.setBlockAndMetadata(x, y, z, blockId, metadata); Block b = world.getBlock(x, y, z); if (b != null && holder instanceof Mob) { b.onBlockPlacedByMob(world, x, y, z, side, (Mob) holder, xPlaced, yPlaced); } + world.notifyBlockChange(x, y, z, blockId); return true; } } @@ -96,16 +99,6 @@ public class CarriedBlock implements ICarriable { } } - @Override - public boolean canBeCarried(World world, Entity potentialHolder) { - return true; - } - - @Override - public ICarriable pickup(World world, Entity holder) { - return this; - } - @Override public void writeToNBT(CompoundTag tag) { if (entity != null) { @@ -135,4 +128,14 @@ public class CarriedBlock implements ICarriable { carriedBlock.readFromNBT(tag); return carriedBlock; } + + @Override + public int metadata() { + return metadata; + } + + @Override + public @Nullable TileEntity entity() { + return entity; + } } diff --git a/game/core/src/main/java/net/minecraft/core/block/motion/ICarriedBlock.java b/game/core/src/main/java/net/minecraft/core/block/motion/ICarriedBlock.java new file mode 100644 index 000000000..15551993c --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/block/motion/ICarriedBlock.java @@ -0,0 +1,15 @@ +package net.minecraft.core.block.motion; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import net.minecraft.core.block.Block; +import net.minecraft.core.block.entity.TileEntity; + +public interface ICarriedBlock { + @NotNull Block block(); + int metadata(); + default @Nullable TileEntity entity() { + return null; + } +} diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/TileEntityMovingPistonBlock.java b/game/core/src/main/java/net/minecraft/core/block/piston/TileEntityMovingPistonBlock.java index c4dfde503..0b7d5745b 100644 --- a/game/core/src/main/java/net/minecraft/core/block/piston/TileEntityMovingPistonBlock.java +++ b/game/core/src/main/java/net/minecraft/core/block/piston/TileEntityMovingPistonBlock.java @@ -216,10 +216,4 @@ public class TileEntityMovingPistonBlock extends TileEntity compoundTag.putFloat("progress", this.progressO); compoundTag.putBoolean("extending", this.extending); } - - @Override - public boolean canBeCarried(World world, Entity potentialHolder) { - // Explicitly defined as false since the MovingPistonBlock should *never* be carried - return false; - } } diff --git a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java index 6a57f5029..b5ba3bd35 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java +++ b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java @@ -1141,7 +1141,7 @@ public abstract class Player setSize(0.2F, 0.2F); if (this.world.isBlockLoaded(x, y, z)) { int meta = this.world.getBlockMetadata(x, y, z); - int dir = BlockLogicBed.getDirection(meta); + int dir = BlockLogicBed.DIRECTION.get(meta); float xOff = 0.5F; float zOff = 0.5F; @@ -1197,7 +1197,8 @@ public abstract class Player TilePos bedPos = this.bedTilePos; Block b; if (bedPos != null && (b = this.world.getBlockType(bedPos)) != null && b.getLogic() instanceof BlockLogicBed) { - BlockLogicBed.setBedOccupied(this.world, bedPos, false); + final var data = this.world.getBlockData(bedPos); + this.world.setBlockData(bedPos, BlockLogicBed.IS_OCCUPIED.set(data, 0)); TilePos emptyPos = BlockLogicBed.getNearestEmptyTilePos(this.world, bedPos, 0); if (emptyPos == null) { emptyPos = bedPos.up(new TilePos()); @@ -1236,9 +1237,8 @@ public abstract class Player public float getBedOrientationInDegrees() { if (this.bedTilePos != null) { - int i = this.world.getBlockMetadata(this.bedTilePos.x, this.bedTilePos.y, this.bedTilePos.z); - int j = BlockLogicBed.getDirection(i); - switch (j) { + int data = this.world.getBlockData(this.bedTilePos); + switch (BlockLogicBed.DIRECTION.get(data)) { case 0: // '\0' return 90F; 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 22efccf38..23cdecf3c 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 @@ -20,22 +20,38 @@ public class ItemBed extends Item { @Override public boolean onUseOnBlock(@NotNull ItemStack selfStack, @NotNull World world, @Nullable Player player, @NotNull TilePosc blockPos, @NotNull Side side, double xHit, double yHit) { - TilePosc pos = blockPos; - if (!world.canPlaceInsideBlock(pos)) { - pos = pos.add(side.getDirection(), new TilePos()); + if (selfStack.stackSize <= 0) return false; + TilePosc pos1 = blockPos; + if (!world.canPlaceInsideBlock(pos1)) { + pos1 = new TilePos(pos1).add(side.getDirection()); } Direction dir = player == null ? Direction.NORTH : player.getHorizontalPlacementDirection(null).getOpposite(); - TilePos pos2 = pos.sub(dir, new TilePos()); - 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.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; - } + final TilePos pos2 = new TilePos(pos1).sub(dir); + + if (!world.canPlaceInsideBlock(pos1) || !world.canPlaceInsideBlock(pos2)) return false; + + final TilePos qpos = new TilePos(); + if (!world.canPlaceOnSurfaceOfBlock(qpos.set(pos1).down())) return false; + if (!world.canPlaceOnSurfaceOfBlock(qpos.set(pos2).down())) return false; + + if (!world.canBlockIdBePlacedAt(Blocks.BED.id(), pos1, false, side)) return false; + // if (!world.canBlockIdBePlacedAt(Blocks.BED.id(), pos2, false, side)) return false; + + + final boolean isPlaced1 = + world.setBlockTypeData(pos1, Blocks.BED, dir.getHorizontalIndex()); + final boolean isPlaced2 = isPlaced1 && + world.setBlockTypeData(pos2, Blocks.BED, dir.getHorizontalIndex() | BlockLogicBed.IS_HEAD.set(0, 1)); + if (!isPlaced2) { + if (isPlaced1) world.setBlockType(pos1, Blocks.AIR); + return false; } - return false; + selfStack.consumeItem(player); + + world.notifyBlockChange(pos1, Blocks.BED); + world.notifyBlockChange(pos2, Blocks.BED); + + world.playBlockSoundEffect(player, pos1.x() + 0.5F, pos1.y() + 0.5F, pos1.z() + 0.5F, Blocks.BED, EnumBlockSoundEffectType.PLACE); + return true; } } diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemDoor.java b/game/core/src/main/java/net/minecraft/core/item/ItemDoor.java index aa381176a..d6fb92c73 100644 --- a/game/core/src/main/java/net/minecraft/core/item/ItemDoor.java +++ b/game/core/src/main/java/net/minecraft/core/item/ItemDoor.java @@ -65,16 +65,17 @@ public class ItemDoor extends Item { return false; } - world.noNeighborUpdate = true; - world.setBlockTypeDataNotify(blockPos, this.doorBlockBottom, meta); - world.setBlockTypeDataNotify(blockPos.up(new TilePos()), this.doorBlockTop, meta); - world.noNeighborUpdate = false; - world.notifyBlocksOfNeighborChange(blockPos, this.doorBlockBottom); - world.notifyBlocksOfNeighborChange(blockPos.up(new TilePos()), this.doorBlockTop); - world.playBlockSoundEffect(player, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, this.doorBlockBottom, EnumBlockSoundEffectType.PLACE); + world.setBlockTypeData(blockPos, this.doorBlockBottom, meta); + world.setBlockTypeData(blockPos.up(new TilePos()), this.doorBlockTop, meta); + selfStack.consumeItem(player); + this.doorBlockBottom.onPlacedByMob(world, blockPos, side, player, xHit, yHit); this.doorBlockTop.onPlacedByMob(world, blockPos.up(new TilePos()), side, player, xHit, yHit); - selfStack.consumeItem(player); + + world.notifyBlockChange(blockPos, this.doorBlockBottom); + world.notifyBlockChange(blockPos.up(new TilePos()), this.doorBlockTop); + + world.playBlockSoundEffect(player, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, this.doorBlockBottom, EnumBlockSoundEffectType.PLACE); return true; } @@ -118,15 +119,16 @@ public class ItemDoor extends Item { return; } - world.noNeighborUpdate = true; - world.setBlockTypeDataNotify(blockPos, this.doorBlockBottom, meta); - world.setBlockTypeDataNotify(blockPos.up(new TilePos()), this.doorBlockTop, meta); - world.noNeighborUpdate = false; - world.notifyBlocksOfNeighborChange(blockPos, this.doorBlockBottom); - world.notifyBlocksOfNeighborChange(blockPos.up(new TilePos()), this.doorBlockTop); - world.playBlockSoundEffect(null, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, this.doorBlockBottom, EnumBlockSoundEffectType.PLACE); + world.setBlockTypeData(blockPos, this.doorBlockBottom, meta); + world.setBlockTypeData(blockPos.up(new TilePos()), this.doorBlockTop, meta); + selfStack.consumeItem(null); + this.doorBlockBottom.onPlacedOnSide(world, blockPos, direction.getSide(), 0.5, 0.5); this.doorBlockTop.onPlacedOnSide(world, blockPos.up(new TilePos()), direction.getSide(), 0.5, 0.5); - selfStack.consumeItem(null); + + world.notifyBlockChange(blockPos, this.doorBlockBottom); + world.notifyBlockChange(blockPos.up(new TilePos()), this.doorBlockTop); + + world.playBlockSoundEffect(null, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, this.doorBlockBottom, EnumBlockSoundEffectType.PLACE); } } diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemFlag.java b/game/core/src/main/java/net/minecraft/core/item/ItemFlag.java index fb4726bc3..c00177e8f 100644 --- a/game/core/src/main/java/net/minecraft/core/item/ItemFlag.java +++ b/game/core/src/main/java/net/minecraft/core/item/ItemFlag.java @@ -67,7 +67,7 @@ public class ItemFlag extends Item { } world.playBlockSoundEffect(player, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, Blocks.FLAG, EnumBlockSoundEffectType.PLACE); - world.setBlockTypeNotify(blockPos, Blocks.FLAG); + world.setBlockType(blockPos, Blocks.FLAG); selfStack.consumeItem(player); if (world.getTileEntity(blockPos) instanceof TileEntityFlag flag) { @@ -80,6 +80,7 @@ public class ItemFlag extends Item { player.displayFlagEditorScreen(flag); } } + world.notifyBlockChange(blockPos, Blocks.FLAG); return true; } diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemPlaceable.java b/game/core/src/main/java/net/minecraft/core/item/ItemPlaceable.java index bc5ba2bdb..bbe148998 100644 --- a/game/core/src/main/java/net/minecraft/core/item/ItemPlaceable.java +++ b/game/core/src/main/java/net/minecraft/core/item/ItemPlaceable.java @@ -38,7 +38,7 @@ public class ItemPlaceable extends Item { return false; } if (world.canBlockIdBePlacedAt(this.blockToPlace.id(), blockPos, false, side) && selfStack.consumeItem(player)) { - if (world.setBlockTypeNotify(blockPos, this.blockToPlace)) { + if (world.setBlockType(blockPos, this.blockToPlace)) { if (player == null) { this.blockToPlace.onPlacedOnSide(world, blockPos, side, xHit, yHit); } else { @@ -50,6 +50,10 @@ public class ItemPlaceable extends Item { tileEntity.readAdditionalData(selfStack.getData().getCompound("tileEntityData")); } } + // notify self change after onPlacedByMob + // this should fix almost all bugs related to piston intercepting placement logic, + // with out change to individual onPlaced<_> logics. + world.notifyBlockChange(blockPos, this.blockToPlace); world.playBlockSoundEffect(player, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, this.blockToPlace, EnumBlockSoundEffectType.PLACE); return true; } diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemRope.java b/game/core/src/main/java/net/minecraft/core/item/ItemRope.java index a4f2f8511..53bf94e5f 100644 --- a/game/core/src/main/java/net/minecraft/core/item/ItemRope.java +++ b/game/core/src/main/java/net/minecraft/core/item/ItemRope.java @@ -48,12 +48,13 @@ public class ItemRope extends ItemPlaceable { return false; } if (world.canBlockIdBePlacedAt(this.blockToPlace.id(), bp, false, side) && selfStack.consumeItem(player)) { - if (world.setBlockTypeDataNotify(bp, this.blockToPlace, placeOnSide ? BlockLogicRope.MASK_ROPE_CONNECT : 0)) { + if (world.setBlockTypeData(bp, this.blockToPlace, placeOnSide ? BlockLogicRope.MASK_ROPE_CONNECT : 0)) { if (player == null) { this.blockToPlace.onPlacedOnSide(world, bp, side, xHit, yHit); } else { this.blockToPlace.onPlacedByMob(world, bp, side, player, xHit, yHit); } + world.notifyBlockChange(bp, this.blockToPlace); world.playBlockSoundEffect(player, bp.x + 0.5F, bp.y + 0.5F, bp.z + 0.5F, this.blockToPlace, EnumBlockSoundEffectType.PLACE); return true; } diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemSign.java b/game/core/src/main/java/net/minecraft/core/item/ItemSign.java index 36a62aa52..66a35f6c4 100644 --- a/game/core/src/main/java/net/minecraft/core/item/ItemSign.java +++ b/game/core/src/main/java/net/minecraft/core/item/ItemSign.java @@ -1,6 +1,7 @@ package net.minecraft.core.item; +import net.minecraft.core.block.Block; import net.minecraft.core.block.Blocks; import net.minecraft.core.block.entity.TileEntitySign; import net.minecraft.core.entity.player.Player; @@ -33,14 +34,16 @@ public class ItemSign extends Item { return false; } + final Block blockPlaced; if (side == Side.TOP) { - world.playBlockSoundEffect(player, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, Blocks.SIGN_POST_PLANKS_OAK, EnumBlockSoundEffectType.PLACE); - world.setBlockTypeDataNotify(blockPos, Blocks.SIGN_POST_PLANKS_OAK, MathHelper.floor((double) (((player.yRot + 180F) * 16F) / 360F) + 0.5D) & 0xf); + blockPlaced = Blocks.SIGN_POST_PLANKS_OAK; + world.setBlockTypeData(blockPos, blockPlaced, MathHelper.floor((double) (((player.yRot + 180F) * 16F) / 360F) + 0.5D) & 0xf); } else { - world.playBlockSoundEffect(player, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, Blocks.SIGN_WALL_PLANKS_OAK, EnumBlockSoundEffectType.PLACE); - world.setBlockTypeDataNotify(blockPos, Blocks.SIGN_WALL_PLANKS_OAK, side.getId()); + blockPlaced = Blocks.SIGN_WALL_PLANKS_OAK; + world.setBlockTypeData(blockPos, blockPlaced, side.getId()); } selfStack.consumeItem(player); + world.playBlockSoundEffect(player, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, blockPlaced, EnumBlockSoundEffectType.PLACE); if (world.getTileEntity(blockPos) instanceof TileEntitySign sign) { if (selfStack.getData().containsKey("tileEntityData")) { sign.readAdditionalData(selfStack.getData().getCompound("tileEntityData")); @@ -49,6 +52,7 @@ public class ItemSign extends Item { player.displaySignEditorScreen(sign); } } + world.notifyBlockChange(blockPos, blockPlaced); return true; } } diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemSignPainted.java b/game/core/src/main/java/net/minecraft/core/item/ItemSignPainted.java index a431013e7..f73ba4d5a 100644 --- a/game/core/src/main/java/net/minecraft/core/item/ItemSignPainted.java +++ b/game/core/src/main/java/net/minecraft/core/item/ItemSignPainted.java @@ -1,5 +1,6 @@ package net.minecraft.core.item; +import net.minecraft.core.block.Block; import net.minecraft.core.block.Blocks; import net.minecraft.core.block.entity.TileEntitySign; import net.minecraft.core.entity.player.Player; @@ -31,16 +32,18 @@ public class ItemSignPainted extends ItemSign { if (blockPos.y() < 0 || blockPos.y() >= world.getHeightBlocks() || !Blocks.SIGN_POST_PLANKS_OAK_PAINTED.canPlaceAt(world, blockPos)) { return false; } - + + final Block blockPlaced; if (side == Side.TOP) { int direction = MathHelper.floor((double) (((player.yRot + 180F) * 16F) / 360F) + 0.5D) & 0xf; - world.playBlockSoundEffect(player, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, Blocks.SIGN_POST_PLANKS_OAK_PAINTED, EnumBlockSoundEffectType.PLACE); - world.setBlockTypeDataNotify(blockPos, Blocks.SIGN_POST_PLANKS_OAK_PAINTED, Blocks.SIGN_POST_PLANKS_OAK_PAINTED.getLogic().toMetadata(DyeColor.colorFromItemMeta(selfStack.getMetadata())) | direction); + blockPlaced = Blocks.SIGN_POST_PLANKS_OAK_PAINTED; + world.setBlockTypeData(blockPos, blockPlaced, Blocks.SIGN_POST_PLANKS_OAK_PAINTED.getLogic().toMetadata(DyeColor.colorFromItemMeta(selfStack.getMetadata())) | direction); } else { - world.playBlockSoundEffect(player, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, Blocks.SIGN_WALL_PLANKS_OAK_PAINTED, EnumBlockSoundEffectType.PLACE); - world.setBlockTypeDataNotify(blockPos, Blocks.SIGN_WALL_PLANKS_OAK_PAINTED, Blocks.SIGN_POST_PLANKS_OAK_PAINTED.getLogic().toMetadata(DyeColor.colorFromItemMeta(selfStack.getMetadata())) | side.getId()); + blockPlaced = Blocks.SIGN_WALL_PLANKS_OAK_PAINTED; + world.setBlockTypeData(blockPos, blockPlaced, Blocks.SIGN_POST_PLANKS_OAK_PAINTED.getLogic().toMetadata(DyeColor.colorFromItemMeta(selfStack.getMetadata())) | side.getId()); } selfStack.consumeItem(player); + world.playBlockSoundEffect(player, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, blockPlaced, EnumBlockSoundEffectType.PLACE); if (world.getTileEntity(blockPos) instanceof TileEntitySign sign) { if (selfStack.getData().containsKey("tileEntityData")) { sign.readAdditionalData(selfStack.getData().getCompound("tileEntityData")); @@ -49,6 +52,7 @@ public class ItemSignPainted extends ItemSign { player.displaySignEditorScreen(sign); } } + world.notifyBlockChange(blockPos, blockPlaced); return true; } diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemStatue.java b/game/core/src/main/java/net/minecraft/core/item/ItemStatue.java index b60c5d684..59e3381a7 100644 --- a/game/core/src/main/java/net/minecraft/core/item/ItemStatue.java +++ b/game/core/src/main/java/net/minecraft/core/item/ItemStatue.java @@ -36,13 +36,10 @@ public class ItemStatue extends Item { return false; } - world.noNeighborUpdate = true; - world.setBlockTypeDataNotify(blockPos, this.statueBlockBottom, MathHelper.floor((double) (((player.yRot + 180F) * 16F) / 360F) + 0.5D) & 0xf); - world.setBlockTypeDataNotify(blockPos.up(new TilePos()), this.statueBlockTop, MathHelper.floor((double) (((player.yRot + 180F) * 16F) / 360F) + 0.5D) & 0xf); - world.noNeighborUpdate = false; - world.notifyBlocksOfNeighborChange(blockPos, this.statueBlockBottom); - world.notifyBlocksOfNeighborChange(blockPos.up(new TilePos()), this.statueBlockTop); - world.playBlockSoundEffect(player, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, this.statueBlockBottom, EnumBlockSoundEffectType.PLACE); + world.setBlockTypeData(blockPos, this.statueBlockBottom, MathHelper.floor((double) (((player.yRot + 180F) * 16F) / 360F) + 0.5D) & 0xf); + world.setBlockTypeData(blockPos.up(new TilePos()), this.statueBlockTop, MathHelper.floor((double) (((player.yRot + 180F) * 16F) / 360F) + 0.5D) & 0xf); + selfStack.consumeItem(player); + this.statueBlockBottom.onPlacedByMob(world, blockPos, side, player, xHit, yHit); this.statueBlockTop.onPlacedByMob(world, blockPos.up(new TilePos()), side, player, xHit, yHit); @@ -52,8 +49,11 @@ public class ItemStatue extends Item { tileEntity.readAdditionalData(selfStack.getData().getCompound("tileEntityData")); } } + world.notifyBlockChange(blockPos, this.statueBlockBottom); + world.notifyBlockChange(blockPos.up(new TilePos()), this.statueBlockTop); + + world.playBlockSoundEffect(player, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, this.statueBlockBottom, EnumBlockSoundEffectType.PLACE); - selfStack.consumeItem(player); return true; } diff --git a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlock.java b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlock.java index 18351c234..7169216c3 100644 --- a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlock.java +++ b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlock.java @@ -2,6 +2,7 @@ package net.minecraft.core.item.block; import net.minecraft.core.block.Block; import net.minecraft.core.block.BlockLogic; +import net.minecraft.core.block.Blocks; import net.minecraft.core.block.entity.TileEntity; import net.minecraft.core.block.entity.TileEntityActivator; import net.minecraft.core.block.tag.BlockTags; @@ -33,44 +34,58 @@ public class ItemBlock extends Item { } @Override - public boolean onUseOnBlock(@NotNull ItemStack selfStack, @NotNull World world, @Nullable Player player, @NotNull TilePosc blockPos, @NotNull Side side, double xHit, double yHit) { + public boolean onUseOnBlock( + @NotNull ItemStack selfStack, @NotNull World world, @Nullable Player player, + @NotNull TilePosc blockPos, @NotNull Side side, double xHit, double yHit + ) { + final int meta = getPlacedData(selfStack, world, player, blockPos, side, xHit, yHit); + return this.placeWithMeta(selfStack, world, player, blockPos, meta, side, xHit, yHit); + } + + public final boolean placeWithMeta( + @NotNull ItemStack selfStack, @NotNull World world, @Nullable Player player, + @NotNull TilePosc blockPos, int meta, @NotNull Side side, double xHit, double yHit + ) { if (selfStack.stackSize <= 0) { return false; } - if (!world.canPlaceInsideBlock(blockPos)) { - blockPos = blockPos.add(side.getDirection(), new TilePos()); - } - if (blockPos.y() < 0 || blockPos.y() >= world.getHeightBlocks()) { - return false; + final boolean placeNextToExisting = !world.canPlaceInsideBlock(blockPos) || + (this.block.hasTag(BlockTags.PLACE_OVERWRITES) && this.block == world.getBlockType(blockPos)); + + if (placeNextToExisting) blockPos = blockPos.add(side.getDirection(), new TilePos()); + + if (!world.canBlockIdBePlacedAt(this.block.id(), blockPos, false, side)) return false; + + if (!world.setBlockTypeData(blockPos, this.block, meta)) return false; + if (!selfStack.consumeItem(player)) return false; // should always be true + + if (player == null) { + this.block.onPlacedOnSide(world, blockPos, side, xHit, yHit); + } else { + this.block.onPlacedByMob(world, blockPos, side, player, xHit, yHit); } - if (world.canBlockIdBePlacedAt(this.block.id(), blockPos, false, side) && selfStack.consumeItem(player)) { - int meta = getPlacedData(selfStack, world, player, blockPos, side, xHit, yHit); - if (world.setBlockTypeDataNotify(blockPos, this.block, meta)) { - if (player == null) { - this.block.onPlacedOnSide(world, blockPos, side, xHit, yHit); - } else { - this.block.onPlacedByMob(world, blockPos, side, player, xHit, yHit); - } - if (this.block.isEntityTile && selfStack.getData().containsKey("tileEntityData")) { - TileEntity tileEntity = world.getTileEntity(blockPos); - if (tileEntity != null) { - tileEntity.readAdditionalData(selfStack.getData().getCompound("tileEntityData")); - } - } - world.playBlockSoundEffect(player, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, this.block, EnumBlockSoundEffectType.PLACE); - return true; - } else if (player == null || player.getGamemode().hasBlockConsumption()) { - selfStack.stackSize += 1; + + if (this.block.isEntityTile && selfStack.getData().containsKey("tileEntityData")) { + final TileEntity tileEntity = world.getTileEntity(blockPos); + if (tileEntity != null) { + tileEntity.readAdditionalData(selfStack.getData().getCompound("tileEntityData")); } } - return false; + + world.notifyBlockChange(blockPos, this.block); + world.playBlockSoundEffect( + player, + blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, + this.block, EnumBlockSoundEffectType.PLACE + ); + return true; } @Override public void onUseByActivator(@NotNull ItemStack selfStack, @NotNull World world, @NotNull TileEntityActivator activator, @NotNull Random random, @NotNull TilePosc blockPos, @NotNull Direction direction, double offX, double offY, double offZ) { - blockPos = blockPos.add(direction, new TilePos()); - Block b = world.getBlockType(blockPos); - if (b == null || BlockTags.PLACE_OVERWRITES.appliesTo(b)) { + blockPos = new TilePos(blockPos).add(direction); + @NotNull Block b = world.getBlockType(blockPos); + if (b == Blocks.AIR || BlockTags.PLACE_OVERWRITES.appliesTo(b)) { onUseOnBlock(selfStack, world, null, blockPos, direction.getSide(), 0.5, 0.5); } } diff --git a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockAlgae.java b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockAlgae.java index 8694aaf19..829a4db67 100644 --- a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockAlgae.java +++ b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockAlgae.java @@ -2,11 +2,11 @@ package net.minecraft.core.item.block; import net.minecraft.core.block.Block; import net.minecraft.core.block.BlockLogic; +import net.minecraft.core.block.BlockLogicFluid; import net.minecraft.core.block.Blocks; +import net.minecraft.core.block.FluidWater; import net.minecraft.core.block.entity.TileEntityActivator; -import net.minecraft.core.block.tag.BlockTags; import net.minecraft.core.entity.player.Player; -import net.minecraft.core.enums.EnumBlockSoundEffectType; import net.minecraft.core.item.ItemStack; import net.minecraft.core.util.helper.Direction; import net.minecraft.core.util.helper.Side; @@ -34,40 +34,39 @@ public class ItemBlockAlgae extends ItemBlock { @Override public @Nullable ItemStack onUse(@NotNull ItemStack selfStack, @NotNull World world, @NotNull Player player) { - double reachDistance = player.getGamemode().getBlockReachDistance(); - HitResult rayCast = player.rayCast(reachDistance, 1f, true, false, false); - if (rayCast == null) { - return selfStack; - } - if (rayCast instanceof HitResult.Tile hitTile) { - TilePos blockPos = new TilePos(hitTile.tilePos); - if (world.getBlockType(blockPos) == Blocks.FLUID_WATER_STILL) { - blockPos.y++; - } else { - return selfStack; - } + final double reachDistance = player.getGamemode().getBlockReachDistance(); + final HitResult rayCast = player.rayCast(reachDistance, 1f, true, false, false); + if (!(rayCast instanceof HitResult.Tile hitTile)) return selfStack; - if (world.getBlockType(blockPos) != Blocks.AIR) { - return selfStack; - } - if (selfStack.consumeItem(player) && world.setBlockTypeNotify(blockPos, this.block)) { - this.block.onPlacedByMob(world, blockPos, Side.NONE, player, 0.5, 0.5); - world.playBlockSoundEffect(player, blockPos.x + 0.5F, blockPos.y + 0.5F, blockPos.z + 0.5F, this.block, EnumBlockSoundEffectType.PLACE); - player.swingItem(); - } - } + final var pos = new TilePos(hitTile.tilePos); + if (!testPlace(world, pos)) return selfStack; + + super.onUseOnBlock(selfStack, world, player, pos, Side.NONE, 0.5, 0.5); return selfStack; } - + @Override public void onUseByActivator(@NotNull ItemStack selfStack, @NotNull World world, @NotNull TileEntityActivator activator, @NotNull Random random, @NotNull TilePosc blockPos, @NotNull Direction direction, double offX, double offY, double offZ) { - blockPos = blockPos.add(direction, new TilePos()); - TilePos up = blockPos.up(new TilePos()); - Block b = world.getBlockType(blockPos); - Block bAbove = world.getBlockType(up); - if (b == Blocks.FLUID_WATER_STILL && (bAbove == null || bAbove.hasTag(BlockTags.PLACE_OVERWRITES))) { - world.setBlockTypeNotify(up, this.block); - this.block.onPlacedOnSide(world, up, Side.NONE, 0.5, 0.5); - } + + final var pos = new TilePos(blockPos).add(direction); + if (!testPlace(world, pos)) return; + + if (!world.setBlockType(pos, this.block)) return; + selfStack.consumeItem(null); + + this.block.onPlacedOnSide(world, pos, Side.NONE, 0.5, 0.5); + world.notifyBlockChange(pos, this.block); + } + + private static final boolean testPlace(@NotNull World world, @NotNull TilePos toMove) { + final TilePos origin = new TilePos(toMove); + + @NotNull Block up = world.getBlockType(toMove.up()); + if (up != Blocks.AIR) return false; + + if (!(world.getBlockType(origin).getLogic() instanceof BlockLogicFluid fluid)) return false; + if (!(fluid.fluid instanceof FluidWater)) return false; + if (fluid.getDepth(world, origin) != 0) return false; + return true; } } diff --git a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLadder.java b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLadder.java index 99ea24a7b..e7a7a2cca 100644 --- a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLadder.java +++ b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLadder.java @@ -3,7 +3,6 @@ package net.minecraft.core.item.block; import net.minecraft.core.block.Block; import net.minecraft.core.block.BlockLogicLadder; import net.minecraft.core.entity.player.Player; -import net.minecraft.core.enums.EnumBlockSoundEffectType; import net.minecraft.core.item.ItemStack; import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.World; @@ -20,55 +19,23 @@ public class ItemBlockLadder extends ItemBlock { @Override public boolean onUseOnBlock(@NotNull ItemStack selfStack, @NotNull World world, @Nullable Player player, @NotNull TilePosc blockPos, @NotNull Side side, double xHit, double yHit) { - TilePos bp = new TilePos(blockPos); - Block clickedBlock = world.getBlockType(bp); - - BlockLogicLadder ladder = this.block.getLogic(); - - if (clickedBlock == this.block && player != null && !player.isSneaking()) { - Side clickedLadderSide = ladder.getSideFromMeta(world.getBlockData(bp)); - while (world.getBlockType(bp) == this.block && ladder.getSideFromMeta(world.getBlockData(bp)) == clickedLadderSide) - bp.y--; - int meta = ladder.getMetaForSide(clickedLadderSide); - if (ladder.canExistAt(world, new TilePos(bp), meta)) { - return placeBlock(selfStack, world, bp, meta, player, clickedLadderSide, 0.5, 0.5); + final TilePos bp = new TilePos(blockPos); + final @NotNull BlockLogicLadder ladder = this.block.getLogic(); + + final Side pside; + if (player == null || player.isSneaking() || world.getBlockType(bp) != this.block) { + if (!world.canPlaceInsideBlock(bp)) bp.add(side.getDirection()); + pside = ladder.getSideForPlacement(world, bp, side); + } else { + xHit = 0.5; + yHit = 0.5; + pside = ladder.getSideFromMeta(world.getBlockData(bp)); + while (world.getBlockType(bp) == this.block && ladder.getSideFromMeta(world.getBlockData(bp)) == pside) { + bp.down(); } - - return false; - } - - if (!world.canPlaceInsideBlock(bp)) { - bp = bp.add(side.getDirection(), new TilePos()); - } - - Side sideForPlacement = ladder.getSideForPlacement(world, bp, side); - if (sideForPlacement == null) { - return false; - } - - int meta = ladder.getMetaForSide(sideForPlacement); - if (ladder.canExistAt(world, bp, meta)) { - return placeBlock(selfStack, world, bp, meta, player, sideForPlacement, xHit, yHit); } - - return false; - } - - - public boolean placeBlock(@NotNull ItemStack selfStack, @NotNull World world, @NotNull TilePos tilePos, int meta, @Nullable Player player, @NotNull Side side, double xHit, double yHit) { - if (world.canPlaceInsideBlock(tilePos) && world.canBlockIdBePlacedAt(this.block.id(), tilePos, false, side) && selfStack.consumeItem(player)) { - if (world.setBlockTypeDataNotify(tilePos, this.block, meta)) { - if (player == null) { - this.block.onPlacedOnSide(world, tilePos, side, xHit, yHit); - } else { - this.block.onPlacedByMob(world, tilePos, side, player, xHit, yHit); - } - world.playBlockSoundEffect(player, tilePos.x + 0.5f, tilePos.y + 0.5f, tilePos.z + 0.5f, this.block, EnumBlockSoundEffectType.PLACE); - return true; - } - } - return false; + final var meta = ladder.getMetaForSide(pside); + if (!ladder.canExistAt(world, bp, meta)) return false; + return super.placeWithMeta(selfStack, world, player, bp, meta, pside, xHit, yHit); } - - } diff --git a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLayer.java b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLayer.java index b5c06c363..0d4f4bf49 100644 --- a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLayer.java +++ b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLayer.java @@ -2,7 +2,6 @@ package net.minecraft.core.item.block; import net.minecraft.core.block.Block; import net.minecraft.core.block.BlockLogicLayerBase; -import net.minecraft.core.block.tag.BlockTags; import net.minecraft.core.entity.player.Player; import net.minecraft.core.enums.EnumBlockSoundEffectType; import net.minecraft.core.item.ItemStack; @@ -12,8 +11,8 @@ import net.minecraft.core.world.pos.TilePos; import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.joml.Vector3d; import org.joml.primitives.AABBd; -import org.joml.primitives.AABBdc; public class ItemBlockLayer extends ItemBlock { @@ -21,89 +20,51 @@ public class ItemBlockLayer extends ItemBlock super(block); } + // TODO: sideways placement into layer @Override public boolean onUseOnBlock(@NotNull ItemStack selfStack, @NotNull World world, @Nullable Player player, @NotNull TilePosc tilePos, @NotNull Side side, double xHit, double yHit) { - Block targetBlock = world.getBlockType(tilePos); - int meta = world.getBlockData(tilePos); - if (targetBlock != this.block && targetBlock != null && targetBlock.hasTag(BlockTags.PLACE_OVERWRITES)) { - targetBlock = null; - meta = 0; - } - if (selfStack.stackSize <= 0 || tilePos.y() == world.getHeightBlocks() - 1 && this.block.getMaterial().isSolid()) { + if (selfStack.stackSize <= 0) return false; + if (tilePos.y() == world.getHeightBlocks() - 1 && this.block.getMaterial().isSolid()) { return false; } - - // Check if we're placing "inside" a layer - if (targetBlock == this.block && side == Side.TOP) { - final BlockLogicLayerBase blockLayer = this.block.getLogic(); - final int newMeta = meta + 1; - - final AABBdc bbBox = new AABBd(tilePos.x(), tilePos.y(), tilePos.z(), tilePos.x() + 1f, tilePos.y() + (2 * (newMeta + 1)) / 16.0f, tilePos.z() + 1f); - if (!world.checkIfAABBIsClear(bbBox)) { - return false; - } - - if (newMeta < 7) { - world.setBlockTypeDataNotify(tilePos, this.block, newMeta); - } else { - if (blockLayer.fullBlock != null) { - world.setBlockTypeNotify(tilePos, blockLayer.fullBlock); - } else { - world.setBlockTypeNotify(tilePos.up(new TilePos()), this.block); - } - } - world.playBlockSoundEffect(player, tilePos.x() + 0.5F, tilePos.y() + 0.5F, tilePos.z() + 0.5F, this.block, EnumBlockSoundEffectType.PLACE); - selfStack.consumeItem(player); - return true; - + final var targetBlock = world.getBlockType(tilePos); + if (targetBlock != this.block || side != Side.TOP) { + // you can no longer stack layers by placing on + // the top face of a partial block under the layers :3 + return super.placeWithMeta(selfStack, world, player, tilePos, 0, side, xHit, yHit); } - // Offset position - if (targetBlock != null) { - tilePos = tilePos.add(side.getDirection(), new TilePos()); - targetBlock = world.getBlockType(tilePos); - meta = world.getBlockData(tilePos); - } + final @NotNull BlockLogicLayerBase blockLayer = this.block.getLogic(); + final int meta = world.getBlockData(tilePos) + 1; - // Check if the block we're placing into is a layer - if (targetBlock == this.block) { - final BlockLogicLayerBase blockLayer = this.block.getLogic(); - final int newMeta = meta + 1; + final var bbmin = new Vector3d(tilePos.vec()); + final var bbmax = new Vector3d(bbmin).add(1, (meta + 1) / 8.0f, 1); + if (!world.checkIfAABBIsClear(new AABBd(bbmin, bbmax))) return false; - final AABBdc bbBox = new AABBd(tilePos.x(), tilePos.y(), tilePos.z(), tilePos.x() + 1f, tilePos.y() + (2 * (newMeta + 1)) / 16.0f, tilePos.z() + 1f); - if (!world.checkIfAABBIsClear(bbBox)) { - return false; - } + final boolean placed; + final @NotNull Block placedBlock; + final var placedPos = new TilePos(tilePos); - if (newMeta < 7) { - world.setBlockTypeDataNotify(tilePos, this.block, newMeta); - } else { - if (blockLayer.fullBlock != null) { - world.setBlockTypeNotify(tilePos, blockLayer.fullBlock); - } else { - world.setBlockTypeNotify(tilePos.up(new TilePos()), this.block); - } - } - world.playBlockSoundEffect(player, tilePos.x() + 0.5F, tilePos.y() + 0.5F, tilePos.z() + 0.5F, this.block, EnumBlockSoundEffectType.PLACE); - selfStack.consumeItem(player); - return true; + if (meta < 7) { + placedBlock = this.block; + placed = world.setBlockTypeData(placedPos, placedBlock, meta); + } else if (blockLayer.fullBlock != null) { + placedBlock = blockLayer.fullBlock; + placed = world.setBlockType(placedPos, placedBlock); + } else { + placedBlock = this.block; + // TODO this can place inside entities + placed = world.setBlockType(placedPos.up(), placedBlock); } + if (!placed) return false; + selfStack.consumeItem(player); - // Regular placement, as all else fails - if (world.canBlockIdBePlacedAt(this.block.id(), tilePos, false, side)) { - int placeMeta = getPlacedData(selfStack, world, player, tilePos, side, xHit, yHit); - if (world.setBlockTypeDataNotify(tilePos, this.block, placeMeta)) { - if (player == null) { - this.block.onPlacedOnSide(world, tilePos, side, xHit, yHit); - } else { - this.block.onPlacedByMob(world, tilePos, Side.NONE, player, xHit, yHit); - } - world.playBlockSoundEffect(player, tilePos.x() + 0.5F, tilePos.y() + 0.5F, tilePos.z() + 0.5F, this.block, EnumBlockSoundEffectType.PLACE); - selfStack.consumeItem(player); - return true; - } - } - return false; + placedBlock.onPlacedByMob(world, tilePos, side, player, xHit, yHit); + world.notifyBlockChange(placedPos, placedBlock); + world.playBlockSoundEffect(player, + placedPos.x() + 0.5F, placedPos.y() + 0.5F, placedPos.z() + 0.5F, + this.block, EnumBlockSoundEffectType.PLACE); + return true; } } diff --git a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLayerLeaves.java b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLayerLeaves.java index 7761fa869..160c93803 100644 --- a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLayerLeaves.java +++ b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockLayerLeaves.java @@ -3,8 +3,6 @@ package net.minecraft.core.item.block; import net.minecraft.core.block.Block; import net.minecraft.core.block.BlockLogicLayerBase; import net.minecraft.core.block.BlockLogicLayerLeaves; -import net.minecraft.core.block.BlockLogicLeavesBase; -import net.minecraft.core.block.tag.BlockTags; import net.minecraft.core.entity.player.Player; import net.minecraft.core.enums.EnumBlockSoundEffectType; import net.minecraft.core.item.ItemStack; @@ -14,102 +12,60 @@ import net.minecraft.core.world.pos.TilePos; import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.joml.Vector3d; import org.joml.primitives.AABBd; -import org.joml.primitives.AABBdc; public class ItemBlockLayerLeaves extends ItemBlock { public ItemBlockLayerLeaves(@NotNull Block block) { super(block); } + // TODO: refactor to reuse ItemBlockLayer? @Override - public boolean onUseOnBlock(@NotNull ItemStack selfStack, @NotNull World world, @Nullable Player player, @NotNull TilePosc blockPos, @NotNull Side side, double xHit, double yHit) { - Block targetBlock = world.getBlockType(blockPos); - int meta = world.getBlockData(blockPos); - if (targetBlock != this.block && targetBlock != null && targetBlock.hasTag(BlockTags.PLACE_OVERWRITES)) { - targetBlock = null; - meta = 0; - } - if (selfStack.stackSize <= 0 || blockPos.y() == world.getHeightBlocks() - 1 && this.block.getMaterial().isSolid()) { + public boolean onUseOnBlock(@NotNull ItemStack selfStack, @NotNull World world, @Nullable Player player, @NotNull TilePosc tilePos, @NotNull Side side, double xHit, double yHit) { + if (selfStack.stackSize <= 0) return false; + if (tilePos.y() == world.getHeightBlocks() - 1 && this.block.getMaterial().isSolid()) { return false; } - - // Check if we're placing "inside" a layer - if (targetBlock == this.block && side == Side.TOP) { - final BlockLogicLayerBase blockLayer = this.block.getLogic(); - final int newMeta = meta + 1; - - final AABBdc bbBox = new AABBd(blockPos.x(), blockPos.y(), blockPos.z(), blockPos.x() + 1f, blockPos.y() + (2 * (newMeta + 1)) / 16.0f, blockPos.z() + 1f); - if (!world.checkIfAABBIsClear(bbBox)) { - return false; - } - - if ((newMeta & 0b00001111) < 7) { - world.setBlockTypeDataNotify(blockPos, this.block, BlockLogicLayerLeaves.setPermanent(newMeta, true)); - } else { - if (blockLayer.fullBlock != null) { - world.setBlockTypeDataNotify(blockPos, blockLayer.fullBlock, BlockLogicLeavesBase.setPermanent(0, true)); - } else { - world.setBlockTypeDataNotify(blockPos.up(new TilePos()), this.block, BlockLogicLayerLeaves.setPermanent(0, true)); - } - } - world.playBlockSoundEffect(player, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, this.block, EnumBlockSoundEffectType.PLACE); - selfStack.consumeItem(player); - return true; - } - - // Offset position - if (targetBlock != null) { - blockPos = blockPos.add(side.getDirection(), new TilePos()); - targetBlock = world.getBlockType(blockPos); - meta = world.getBlockData(blockPos); + final var targetBlock = world.getBlockType(tilePos); + if (targetBlock != this.block || side != Side.TOP) { + // you can no longer stack layers by placing on + // the top face of a partial block under the layers :3 + return super.placeWithMeta(selfStack, world, player, tilePos, + BlockLogicLayerLeaves.setPermanent(0, true), side, xHit, yHit); } - // Check if the block we're placing into is a layer - if (targetBlock == this.block) { - final BlockLogicLayerBase blockLayer = this.block.getLogic(); - final int newMeta = meta + 1; + final @NotNull BlockLogicLayerBase blockLayer = this.block.getLogic(); + final int meta = world.getBlockData(tilePos) + 1; - final AABBdc bbBox = new AABBd(blockPos.x(), blockPos.y(), blockPos.z(), blockPos.x() + 1f, blockPos.y() + (2 * (newMeta + 1)) / 16.0f, blockPos.z() + 1f); - if (!world.checkIfAABBIsClear(bbBox)) { - return false; - } + final var bbmin = new Vector3d(tilePos.vec()); + final var bbmax = new Vector3d(bbmin).add(1, (meta + 1) / 8.0f, 1); + if (!world.checkIfAABBIsClear(new AABBd(bbmin, bbmax))) return false; - if ((newMeta & 0b00001111) < 7) { - world.setBlockTypeDataNotify(blockPos, this.block, BlockLogicLayerLeaves.setPermanent(newMeta, true)); - } else { - if (blockLayer.fullBlock != null) { - world.setBlockTypeDataNotify(blockPos, blockLayer.fullBlock, BlockLogicLeavesBase.setPermanent(0, true)); - } else { - world.setBlockTypeDataNotify(blockPos.up(new TilePos()), this.block, BlockLogicLayerLeaves.setPermanent(0, true)); - } - } - world.playBlockSoundEffect(player, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, this.block, EnumBlockSoundEffectType.PLACE); - selfStack.consumeItem(player); - return true; - } + final boolean placed; + final @NotNull Block placedBlock; + final var placedPos = new TilePos(tilePos); - // Regular placement, as all else fails - if (world.canBlockIdBePlacedAt(this.block.id(), blockPos, false, side)) { - int placeMeta = getPlacedData(selfStack, world, player, blockPos, side, xHit, yHit); - if (world.setBlockTypeDataNotify(blockPos, this.block, placeMeta)) { - if (player == null) { - this.block.onPlacedOnSide(world, blockPos, side, xHit, yHit); - } else { - this.block.onPlacedByMob(world, blockPos, side, player, xHit, yHit); - } - world.playBlockSoundEffect(player, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, this.block, EnumBlockSoundEffectType.PLACE); - selfStack.consumeItem(player); - return true; - } + if ((meta & 0x0F) < 7) { + placedBlock = this.block; + placed = world.setBlockTypeData(placedPos, placedBlock, BlockLogicLayerLeaves.setPermanent(meta, true)); + } else if (blockLayer.fullBlock != null) { + placedBlock = blockLayer.fullBlock; + placed = world.setBlockTypeData(placedPos, placedBlock, BlockLogicLayerLeaves.setPermanent(0, true)); + } else { + placedBlock = this.block; + // TODO this can place inside entities + placed = world.setBlockTypeData(placedPos.up(), placedBlock, BlockLogicLayerLeaves.setPermanent(0, true)); } - return false; + if (!placed) return false; + selfStack.consumeItem(player); - } + placedBlock.onPlacedByMob(world, tilePos, side, player, xHit, yHit); + world.notifyBlockChange(placedPos, placedBlock); - @Override - public int getPlacedData(@NotNull ItemStack selfStack, @NotNull World world, @Nullable Player player, @NotNull TilePosc blockPos, @NotNull Side side, double xHit, double yHit) { - return BlockLogicLayerLeaves.MASK_PERMANENT; + world.playBlockSoundEffect(player, + placedPos.x() + 0.5F, placedPos.y() + 0.5F, placedPos.z() + 0.5F, + this.block, EnumBlockSoundEffectType.PLACE); + return true; } - } diff --git a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockSlab.java b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockSlab.java index 009657755..7ba51df41 100644 --- a/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockSlab.java +++ b/game/core/src/main/java/net/minecraft/core/item/block/ItemBlockSlab.java @@ -2,7 +2,6 @@ package net.minecraft.core.item.block; import net.minecraft.core.block.Block; import net.minecraft.core.block.BlockLogic; -import net.minecraft.core.block.Blocks; import net.minecraft.core.block.tag.BlockTags; import net.minecraft.core.entity.player.Player; import net.minecraft.core.enums.EnumBlockSoundEffectType; @@ -13,8 +12,8 @@ import net.minecraft.core.world.pos.TilePos; import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.joml.Vector3d; import org.joml.primitives.AABBd; -import org.joml.primitives.AABBdc; public class ItemBlockSlab extends ItemBlock { public ItemBlockSlab(@NotNull Block block) { @@ -23,69 +22,53 @@ public class ItemBlockSlab extends ItemBlock { @Override public boolean onUseOnBlock(@NotNull ItemStack selfStack, @NotNull World world, @Nullable Player player, @NotNull TilePosc blockPos, @NotNull Side side, double xHit, double yHit) { - @NotNull Block block = world.getBlockType(blockPos); - int meta = world.getBlockData(blockPos) & 0b11; - int otherMeta = world.getBlockData(blockPos) & ~0b11; - if (world.getBlockType(blockPos).hasTag(BlockTags.PLACE_OVERWRITES)) { - block = Blocks.AIR; - meta = 0; - } - if (selfStack.stackSize <= 0 || blockPos.y() == world.getHeightBlocks() - 1 && this.block.getMaterial().isSolid()) { + if (selfStack.stackSize <= 0) return false; + if (blockPos.y() == world.getHeightBlocks() - 1 && this.block.getMaterial().isSolid()) { return false; } - // Check if we're placing "inside" a slab - if (block == this.block && otherMeta == selfStack.getMetadata() && (side == Side.TOP || side == Side.BOTTOM)) { - if ((side == Side.TOP && meta == 0) || (side == Side.BOTTOM && meta == 2)) { - AABBdc bbBox = new AABBd(blockPos.x(), blockPos.y(), blockPos.z(), blockPos.x() + 1f, blockPos.y() + 1f, blockPos.z() + 1f); - if (!world.checkIfAABBIsClear(bbBox)) { - return false; - } - - world.setBlockDataNotify(blockPos, 1 | selfStack.getMetadata()); - world.playBlockSoundEffect(player, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, this.block, EnumBlockSoundEffectType.PLACE); - selfStack.consumeItem(player); - return true; - } + var block = world.getBlockType(blockPos); + if (block.hasTag(BlockTags.PLACE_OVERWRITES)) { + return super.onUseOnBlock(selfStack, world, player, blockPos, side, xHit, yHit); } - // Offset position - if (block != Blocks.AIR) { - blockPos = blockPos.add(side.getDirection(), new TilePos()); - block = world.getBlockType(blockPos); - meta = world.getBlockData(blockPos) & 0b11; - otherMeta = world.getBlockData(blockPos) & ~0b11; + final int selfMeta = selfStack.getMetadata(); + final var shiftPos = new TilePos(blockPos); + + int i; + for (i = 0; i < 2; i++) { + block = world.getBlockType(shiftPos); + final var blockMeta = world.getBlockData(shiftPos); + final boolean canPlaceInto = + block == this.block && + (blockMeta & ~0b11) == selfMeta && + switch (blockMeta & 0b11) { + default -> false; + case 0 -> yHit >= 0.5f; + case 2 -> yHit <= 0.5f; + }; + if (canPlaceInto) break; + shiftPos.add(side); + yHit -= side.getOffsetY(); + } if (i == 2) { // for else + return super.onUseOnBlock(selfStack, world, player, blockPos, side, xHit, yHit); } - // Check if the block we're placing into is a slab - if (block == this.block && otherMeta == selfStack.getMetadata()) { - if ((yHit > 0.5f && meta == 0) || (yHit <= 0.5f && meta == 2) || (side == Side.BOTTOM && meta == 0) || (side == Side.TOP && meta == 2)) { - AABBdc bbBox = new AABBd(blockPos.x(), blockPos.y(), blockPos.z(), blockPos.x() + 1f, blockPos.y() + 1f, blockPos.z() + 1f); - if (!world.checkIfAABBIsClear(bbBox)) { - return false; - } + final var bbmin = new Vector3d(shiftPos.vec()); + final var bbmax = new Vector3d(bbmin).add(1,1,1); + if (!world.checkIfAABBIsClear(new AABBd(bbmin, bbmax))) return false; - world.setBlockDataNotify(blockPos, 1 | selfStack.getMetadata()); - world.playBlockSoundEffect(player, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, this.block, EnumBlockSoundEffectType.PLACE); - selfStack.consumeItem(player); - return true; - } - } + if (!world.setBlockData(shiftPos, 1 | selfStack.getMetadata())) return false; + selfStack.consumeItem(player); - // Regular placement, as all else fails - if (world.canBlockIdBePlacedAt(this.block.id(), blockPos, false, side)) { - int placeMeta = getPlacedData(selfStack, world, player, blockPos, side, xHit, yHit); - if (world.setBlockTypeDataNotify(blockPos, this.block, placeMeta)) { - if (player == null) { - this.block.onPlacedOnSide(world, blockPos, side, xHit, yHit); - } else { - this.block.onPlacedByMob(world, blockPos, side, player, xHit, yHit); - } - world.playBlockSoundEffect(player, blockPos.x() + 0.5F, blockPos.y() + 0.5F, blockPos.z() + 0.5F, this.block, EnumBlockSoundEffectType.PLACE); - selfStack.consumeItem(player); - return true; - } - } - return false; + // this invokes modelBlock's on place logic. is this a good idea? + this.block.onPlacedByWorld(world, shiftPos); + + world.notifyBlockChange(shiftPos, block); + world.playBlockSoundEffect(player, + shiftPos.x() + 0.5F, shiftPos.y() + 0.5F, shiftPos.z() + 0.5F, + this.block, EnumBlockSoundEffectType.PLACE); + + return true; } } diff --git a/game/core/src/main/java/net/minecraft/core/util/PackedField.java b/game/core/src/main/java/net/minecraft/core/util/PackedField.java new file mode 100644 index 000000000..9b7791a95 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/util/PackedField.java @@ -0,0 +1,37 @@ +package net.minecraft.core.util; + +public final class PackedField { + final int offset; + public final int mask; + + public PackedField(int offset, int size) { + assert offset >= 0 && size >= 0 && offset + size < 32; + this.offset = offset; + this.mask = ((1 << size) - 1) << offset; + } + + public PackedField(int mask) { + this.offset = 0; + this.mask = mask; + } + + public int get(int src) { + return (src & mask) >> offset; + } + + public int getNoShift(int src) { + return src & mask; + } + + public boolean bool(int src) { + return get(src) != 0; + } + + public int set(int src, int val) { + return (src &~ mask) | ((val << offset) & mask); + } + + public int setNoShift(int src, int val) { + return (src &~ mask) | (val & mask); + } +} diff --git a/game/core/src/main/java/net/minecraft/core/util/helper/NBTFormatHelper.java b/game/core/src/main/java/net/minecraft/core/util/helper/NBTFormatHelper.java new file mode 100644 index 000000000..ba891371a --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/util/helper/NBTFormatHelper.java @@ -0,0 +1,402 @@ +package net.minecraft.core.util.helper; + +import net.minecraft.core.item.ItemStack; +import net.minecraft.core.net.command.TextFormatting; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class NBTFormatHelper { + + //removes version and expanded tags, modifies id, damage, and tile entity data + private static final Pattern VERSION_PATTERN = Pattern.compile("\"?(Version)\"?\\s*:\\s*([^,;{}]+|\"[^\"]*\")\\s*[;,]?\\s*"); + private static final Pattern EXPANDED_PATTERN = Pattern.compile("\"?(Expanded)\"?\\s*:\\s*([^,;{}]+|\"[^\"]*\")\\s*[;,]?\\s*"); + private static final Pattern ID_PATTERN = Pattern.compile("\"?id\"?\\s*:\\s*(-?\\d+)"); + private static final Pattern DAMAGE_PATTERN = Pattern.compile("\"?Damage\"?\\s*:\\s*(-?\\d+)"); + private static final Pattern TILE_ENTITY_DATA_PATTERN = Pattern.compile("\"?tileEntityData\"?\\s*:\\s*(?=\\{)"); + + //key patterns to match/look for + private static final Pattern EMPTY_KEY_PATTERN = Pattern.compile("\"\"\\s*:\\s*"); + private static final Pattern QUOTED_KEY_PATTERN = Pattern.compile("\"([^\"]+)\"\\s*:"); + + //formatNBTTooltip strips out a lot of whitespace, this char is used to replace it if it needs to be preserved + private static final char VISIBLE_SPACE = '\u00A0'; + + public static @NotNull String formatNbtTooltip(String nbtString) { + nbtString = VERSION_PATTERN.matcher(nbtString).replaceAll(""); + nbtString = EXPANDED_PATTERN.matcher(nbtString).replaceAll(""); + nbtString = processTopLevelTileEntityData(nbtString); + nbtString = resolveEmptyKeys(nbtString); + nbtString = QUOTED_KEY_PATTERN.matcher(nbtString).replaceAll("$1:"); + + boolean[] inlineMask = getInlineMask(nbtString); + StringBuilder stringBuilder = new StringBuilder(nbtString.length() * 2); + + int indentLevel = 0; + boolean inQuotes = false; + boolean isKey = true; + boolean colorNeedsUpdate = true; + boolean[] inObjectStack = new boolean[128]; + + TextFormatting syntaxColor = TextFormatting.GRAY; + TextFormatting contentColor = TextFormatting.LIGHT_GRAY; + TextFormatting titleColor = TextFormatting.MAGENTA; + + for (int i = 0; i < nbtString.length(); i++) { + char charAt = nbtString.charAt(i); + boolean inline = inlineMask[i]; + + if (charAt == '"') { + if (!inQuotes) { + stringBuilder.append(contentColor).append(charAt); + inQuotes = true; + } else { + stringBuilder.append(charAt); + inQuotes = false; + colorNeedsUpdate = true; + } + continue; + } + + if (inQuotes) { + stringBuilder.append(charAt); + continue; + } + + if (charAt == ' ' || charAt == '\n' || charAt == '\r' || charAt == '\t') continue; + + if (charAt == '{' || charAt == '[' || charAt == '(') { + indentLevel++; + if (indentLevel >= inObjectStack.length) { + inObjectStack = Arrays.copyOf(inObjectStack, inObjectStack.length * 2); + } + + boolean isObj = (charAt == '{' || charAt == '('); + inObjectStack[indentLevel] = isObj; + isKey = isObj; + + stringBuilder.append(syntaxColor).append(charAt); + colorNeedsUpdate = true; + + char nextChar = nextNonWhitespace(nbtString, i + 1); + if (isMatchingClose(charAt, nextChar)) { + stringBuilder.append(nextChar); + while (i + 1 < nbtString.length() && Character.isWhitespace(nbtString.charAt(i + 1))) i++; + i++; + indentLevel--; + } else { + stringBuilder.append(inline ? " " : "\n" + getIndent(indentLevel)); + } + } else if (charAt == '}' || charAt == ']' || charAt == ')') { + indentLevel = Math.max(0, indentLevel - 1); + stringBuilder.append(inline ? " " : "\n" + getIndent(indentLevel)); + stringBuilder.append(syntaxColor).append(charAt); + colorNeedsUpdate = true; + } else if (charAt == ',' || charAt == ';') { + stringBuilder.append(syntaxColor).append(charAt); + colorNeedsUpdate = true; + isKey = indentLevel > 0 && inObjectStack[indentLevel]; + + char nextChar = nextNonWhitespace(nbtString, i + 1); + if (nextChar != '}' && nextChar != ']' && nextChar != ')') { + if (!inline) { + stringBuilder.append('\n').append(getIndent(indentLevel)); + } else { + stringBuilder.append(' '); + } + } + } else if (charAt == ':') { + stringBuilder.append(syntaxColor).append(": "); + colorNeedsUpdate = true; + isKey = false; + } else { + if (colorNeedsUpdate) { + stringBuilder.append(isKey ? titleColor : contentColor); + colorNeedsUpdate = false; + } + stringBuilder.append(charAt); + } + } + + return stringBuilder.toString(); + } + + private static @NotNull String resolveEmptyKeys(@NotNull String nbt) { + Matcher keyMatcher = EMPTY_KEY_PATTERN.matcher(nbt); + StringBuilder result = new StringBuilder(nbt.length()); + int lastEnd = 0; + + while (keyMatcher.find()) { + int matchStart = keyMatcher.start(); + int matchEnd = keyMatcher.end(); + result.append(nbt, lastEnd, matchStart); + + int openBrace = nbt.indexOf('{', matchEnd); + + if (openBrace != -1 && isOnlyWhitespace(nbt, matchEnd, openBrace)) { + int closeBrace = findMatchingBrace(nbt, openBrace); + if (closeBrace != -1) { + CharSequence block = nbt.subSequence(openBrace, closeBrace + 1); + Matcher idMatcher = ID_PATTERN.matcher(block); + + if (idMatcher.find()) { + try { + int id = Integer.parseInt(idMatcher.group(1)); + int damage = 0; + Matcher dmgMatcher = DAMAGE_PATTERN.matcher(block); + if (dmgMatcher.find()) { + damage = Integer.parseInt(dmgMatcher.group(1)); + } + + String itemKey = "Item" + VISIBLE_SPACE + VISIBLE_SPACE + id; + try { + ItemStack stack = new ItemStack(id, 1, damage); + itemKey = stack.getItemKey(); + } catch (Exception ignored) {} + + result.append(itemKey).append(":"); + lastEnd = matchEnd; + continue; + } catch (NumberFormatException ignored) {} + } + } + } + + result.append("Tag:"); + lastEnd = matchEnd; + } + + result.append(nbt, lastEnd, nbt.length()); + return result.toString(); + } + + private static @NotNull String processTopLevelTileEntityData(@NotNull String nbt) { + Matcher matcher = TILE_ENTITY_DATA_PATTERN.matcher(nbt); + StringBuilder result = new StringBuilder(nbt.length()); + int searchStart = 0; + + while (matcher.find(searchStart)) { + int openBrace = matcher.end(); + int closeBrace = findMatchingBrace(nbt, openBrace); + + if (closeBrace != -1) { + result.append(nbt, searchStart, openBrace + 1); + + String inner = nbt.substring(openBrace + 1, closeBrace); + result.append(collapseAllTileEntityData(inner)); + + searchStart = closeBrace; + } else { + result.append(nbt, searchStart, openBrace); + searchStart = openBrace; + } + } + + result.append(nbt, searchStart, nbt.length()); + return result.toString(); + } + + private static @NotNull String collapseAllTileEntityData(@NotNull String nbt) { + Matcher matcher = TILE_ENTITY_DATA_PATTERN.matcher(nbt); + StringBuilder result = new StringBuilder(nbt.length()); + int searchStart = 0; + + while (matcher.find(searchStart)) { + int openBrace = matcher.end(); + int closeBrace = findMatchingBrace(nbt, openBrace); + + if (closeBrace != -1) { + int tags = countTags(nbt, openBrace, closeBrace); + String tagWord = tags == 1 ? "Tag" : "Tags"; + String replacement = "<" + tags + VISIBLE_SPACE + tagWord + ">"; + + result.append(nbt, searchStart, openBrace); + result.append(replacement); + + searchStart = closeBrace + 1; + } else { + result.append(nbt, searchStart, openBrace); + searchStart = openBrace; + } + } + + result.append(nbt, searchStart, nbt.length()); + return result.toString(); + } + + private static boolean @NotNull [] getInlineMask(@NotNull String nbt) { + boolean[] mask = new boolean[nbt.length()]; + + for (int i = 0; i < nbt.length(); i++) { + char charAt = nbt.charAt(i); + if (charAt == '{' || charAt == '[') { + int closeIndex = findMatchingBrace(nbt, i); + if (closeIndex != -1) { + boolean isFlat = true; + boolean inQuotes = false; + boolean escaped = false; + + for (int j = i + 1; j < closeIndex; j++) { + char inner = nbt.charAt(j); + if (escaped) { + escaped = false; + continue; + } + if (inner == '\\') { + escaped = true; + continue; + } + if (inner == '"') { + inQuotes = !inQuotes; + } else if (!inQuotes) { + if (inner == '{' || inner == '[' || inner == '}' || inner == ']') { + isFlat = false; + break; + } + } + } + + if (isFlat) { + for (int j = i; j <= closeIndex; j++) { + mask[j] = true; + } + } + } + } + } + + String target = VISIBLE_SPACE + "Tag"; + int start = 0; + + while (true) { + int index = nbt.indexOf(target, start); + if (index == -1) break; + + int openBrace = -1; + int depth = 0; + boolean inQuotes = false; + for (int i = index; i >= 0; i--) { + char charAt = nbt.charAt(i); + if (charAt == '"') inQuotes = !inQuotes; + if (!inQuotes) { + if (charAt == '}' || charAt == ']' || charAt == ')') depth++; + else if (charAt == '{' || charAt == '[' || charAt == '(') { + if (depth == 0) { + openBrace = i; + break; + } else { + depth--; + } + } + } + } + + if (openBrace != -1) { + int closeBrace = findMatchingBrace(nbt, openBrace); + if (closeBrace != -1) { + for (int i = openBrace; i <= closeBrace; i++) { + mask[i] = true; + } + } + } + start = index + target.length(); + } + return mask; + } + + private static int findMatchingBrace(@NotNull String str, int startIndex) { + int depth = 0; + boolean inQuotes = false; + boolean escaped = false; + + for (int i = startIndex; i < str.length(); i++) { + char charAt = str.charAt(i); + + if (escaped) { + escaped = false; + continue; + } + if (charAt == '\\') { + escaped = true; + continue; + } + if (charAt == '"') { + inQuotes = !inQuotes; + } else if (!inQuotes) { + if (charAt == '{') depth++; + else if (charAt == '}') { + depth--; + if (depth == 0) return i; + } + } + } + return -1; + } + + private static int countTags(String nbt, int openBrace, int closeBrace) { + int depth = 0; + int tags = 0; + boolean inQuotes = false; + boolean escaped = false; + boolean hasContent = false; + + for (int i = openBrace; i <= closeBrace; i++) { + char charAt = nbt.charAt(i); + + if (escaped) { + escaped = false; + continue; + } + if (charAt == '\\') { + escaped = true; + continue; + } + if (charAt == '"') { + inQuotes = !inQuotes; + } else if (!inQuotes) { + if (charAt == '{' || charAt == '[') depth++; + else if (charAt == '}' || charAt == ']') { + depth--; + if (depth == 0 && charAt == '}') { + if (hasContent) tags++; + break; + } + } else if (charAt == ',' && depth == 1) { + tags++; + hasContent = false; + } else if (!Character.isWhitespace(charAt)) { + hasContent = true; + } + } + } + return tags; + } + + private static boolean isOnlyWhitespace(String str, int start, int end) { + for (int i = start; i < end; i++) { + if (!Character.isWhitespace(str.charAt(i))) return false; + } + return true; + } + + private static char nextNonWhitespace(@NotNull String str, int startIndex) { + for (int i = startIndex; i < str.length(); i++) { + char charAt = str.charAt(i); + if (!Character.isWhitespace(charAt)) return charAt; + } + return '\0'; + } + + private static boolean isMatchingClose(char open, char close) { + return (open == '{' && close == '}') || + (open == '[' && close == ']') || + (open == '(' && close == ')'); + } + + private static @NotNull String getIndent(int level) { + if (level <= 0) return ""; + return " ".repeat(level); + } +} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/world/ICarriable.java b/game/core/src/main/java/net/minecraft/core/world/ICarriable.java index a7aefa966..d2a19fd8d 100644 --- a/game/core/src/main/java/net/minecraft/core/world/ICarriable.java +++ b/game/core/src/main/java/net/minecraft/core/world/ICarriable.java @@ -25,15 +25,9 @@ public interface ICarriable { */ void drop(World world, Entity holder); - /** - * Called before an entity tries to pick up the object - */ - boolean canBeCarried(World world, Entity potentialHolder); - - /** - * Called by an entity when attempting to pick up the object - */ - ICarriable pickup(World world, Entity holder); + // moved to ICarriableSource + // boolean canBeCarried(World world, Entity potentialHolder); + // ICarriable pickup(World world, Entity holder, TilePosc tilePos); void writeToNBT(CompoundTag tag); diff --git a/game/core/src/main/java/net/minecraft/core/world/ICarrySource.java b/game/core/src/main/java/net/minecraft/core/world/ICarrySource.java new file mode 100644 index 000000000..4a12e9ec3 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/world/ICarrySource.java @@ -0,0 +1,25 @@ +package net.minecraft.core.world; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import net.minecraft.core.entity.Entity; +import net.minecraft.core.world.pos.TilePosc; + +public interface ICarrySource { + @NotNull ICarriable pickup(@NotNull World world, @NotNull Entity holder, @NotNull TilePosc tilePos); + + public static @Nullable ICarrySource getFromWorld(@NotNull World world, @NotNull TilePosc tilePos) { + if (world.getTileEntity(tilePos) instanceof ICarrySource carryTE) return carryTE; + if (world.getBlockType(tilePos).getLogic() instanceof ICarrySource carryTile) return carryTile; + return null; + } + + public static @Nullable ICarrySource tryPickUpFromWorld(@NotNull World world, @NotNull Entity holder, @NotNull TilePosc tilePos) { + final @Nullable var carry = getFromWorld(world, tilePos); + if (carry != null) { + holder.setHeldObject(carry.pickup(world, holder, tilePos)); + } + return carry; + } +} diff --git a/game/core/src/main/java/net/minecraft/core/world/pos/TilePosc.java b/game/core/src/main/java/net/minecraft/core/world/pos/TilePosc.java index 8824a90f0..5c72e0ff5 100644 --- a/game/core/src/main/java/net/minecraft/core/world/pos/TilePosc.java +++ b/game/core/src/main/java/net/minecraft/core/world/pos/TilePosc.java @@ -7,9 +7,9 @@ import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.WorldSource; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.joml.Vector3d; import org.joml.Vector3dc; import org.joml.Vector3fc; +import org.joml.Vector3i; import org.joml.Vector3ic; /** @@ -22,6 +22,10 @@ public interface TilePosc { int z(); + default @NotNull Vector3ic vec() { + return new Vector3i(x(), y(), z()); + } + int get(int component); int get(@NotNull Axis axis); diff --git a/game/server/src/main/java/net/minecraft/server/world/ServerPlayerController.java b/game/server/src/main/java/net/minecraft/server/world/ServerPlayerController.java index 896e67870..17046ee13 100644 --- a/game/server/src/main/java/net/minecraft/server/world/ServerPlayerController.java +++ b/game/server/src/main/java/net/minecraft/server/world/ServerPlayerController.java @@ -10,8 +10,10 @@ import net.minecraft.core.item.Item; import net.minecraft.core.item.ItemStack; import net.minecraft.core.net.packet.PacketBlockUpdate; import net.minecraft.core.util.helper.Side; +import net.minecraft.core.world.ICarrySource; import net.minecraft.core.world.LevelListener; import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; import net.minecraft.server.entity.player.PlayerServer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -164,14 +166,11 @@ public class ServerPlayerController public boolean useOrPlaceItemStackOnTile(Player entityplayer, World world, ItemStack itemstack, int blockX, int blockY, int blockZ, Side side, double xPlaced, double yPlaced) { if (!entityplayer.getGamemode().canInteract()) return false; - int blockId = world.getBlockId(blockX, blockY, blockZ); + final var pos = new TilePos(blockX, blockY, blockZ); + int blockId = world.getBlockType(pos).id(); if (player.getHeldObject() == null) { - if (player.isSneaking() && itemstack == null) { // If crouched and hand empty try to pickup block entity - TileEntity tileEntity = world.getTileEntity(blockX, blockY, blockZ); - if (tileEntity != null && tileEntity.canBeCarried(world, player)) { - player.setHeldObject(tileEntity.pickup(world, player)); - return true; - } + if (player.isSneaking() && itemstack == null) { + if (ICarrySource.tryPickUpFromWorld(world, player, pos) != null) return true; } if (!player.isSneaking() || itemstack == null) { // If standing or hand empty perform block right click method if (blockId > 0 && Blocks.blocksList[blockId].onBlockRightClicked(world, blockX, blockY, blockZ, player, side, xPlaced, yPlaced)) { diff --git a/gradle.properties b/gradle.properties index 37ab4b219..7b5e78a90 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,6 +3,6 @@ org.gradle.daemon = true org.gradle.caching = true bta.group = net.minecraft -bta.version = 7.4 +bta.version = 8.0 bta.assetPackFormat = 4 bta.buildChannel = BuildChannel.DEVELOPMENT \ No newline at end of file diff --git a/util/nbt/src/main/java/com/mojang/nbt/tags/ListTag.java b/util/nbt/src/main/java/com/mojang/nbt/tags/ListTag.java index 0b4ffe9f0..e9854d0cf 100644 --- a/util/nbt/src/main/java/com/mojang/nbt/tags/ListTag.java +++ b/util/nbt/src/main/java/com/mojang/nbt/tags/ListTag.java @@ -108,7 +108,7 @@ public class ListTag @Override public String toString() { - if (getValue().size() > 16) + if (getValue().size() > 27) { return "\"" + getTagName() + "\": [ " + getValue().size() + " elements ]"; }