diff --git a/game/client/src/main/java/net/minecraft/client/Minecraft.java b/game/client/src/main/java/net/minecraft/client/Minecraft.java index 943af4200..1cdba1545 100644 --- a/game/client/src/main/java/net/minecraft/client/Minecraft.java +++ b/game/client/src/main/java/net/minecraft/client/Minecraft.java @@ -102,6 +102,7 @@ import net.minecraft.core.data.DataLoader; import net.minecraft.core.data.registry.Registries; import net.minecraft.core.entity.EntityDispatcher; import net.minecraft.core.entity.EntityItem; +import net.minecraft.core.entity.animal.MobPig; import net.minecraft.core.entity.SkinVariantList; import net.minecraft.core.entity.player.Player; import net.minecraft.core.enums.EnumOS; @@ -2057,8 +2058,12 @@ public class Minecraft Dimension lastDim = Dimension.getDimensionList().get(this.thePlayer.dimension); Dimension newDim = Dimension.getDimensionList().get(dim); LOGGER.info("Switching to dimension \"{}\"!!", newDim.getTranslatedName()); + MobPig mount = this.thePlayer.vehicle instanceof MobPig p ? p : null; this.thePlayer.dimension = dim; this.currentWorld.setEntityDead(this.thePlayer); + if (mount != null) { + this.currentWorld.setEntityDead(mount); + } this.thePlayer.removed = false; double x = this.thePlayer.x; double z = this.thePlayer.z; @@ -2095,6 +2100,14 @@ public class Minecraft this.thePlayer.moveTo(x, y, z, this.thePlayer.yRot, this.thePlayer.xRot); this.currentWorld.updateEntityWithOptionalForce(this.thePlayer, false); (new PortalHandler()).teleportEntity(this.currentWorld, this.thePlayer, portalColor, lastDim, newDim); + if (mount != null) { + this.thePlayer.clearPendingVehicleTag(); + mount.removed = false; + mount.world = this.currentWorld; + mount.moveTo(this.thePlayer.x, this.thePlayer.y, this.thePlayer.z, mount.yRot, mount.xRot); + this.currentWorld.entityJoinedWorld(mount); + this.thePlayer.startRiding(mount); + } } } @@ -2369,10 +2382,14 @@ public class Minecraft if (previousPlayer != null) { this.thePlayer.messageHistory = previousPlayer.messageHistory; + this.thePlayer.rotationLock = previousPlayer.rotationLock; + this.thePlayer.rotationLockHorizontal = previousPlayer.rotationLockHorizontal; + this.thePlayer.rotationLockVertical = previousPlayer.rotationLockVertical; if (!this.currentWorld.isClientSide) { this.thePlayer.inventory.transferAllContents(previousPlayer.inventory); } } + this.thePlayer.syncPlacementMode(); if (canRespawnAtBed) { this.thePlayer.setPlayerSpawnPoint(spawnCoordinates); diff --git a/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java b/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java index 46ca4805d..9bad9c1ac 100644 --- a/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java +++ b/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java @@ -144,10 +144,8 @@ public class PlayerLocal extends Player { } this.prevTimeInPortal = this.timeInPortal; - if (this.inPortal && !this.hasNoPhysics()) { - if (!this.world.isClientSide && this.vehicle != null) { - startRiding(null); - } + + if (this.inPortal && !hasNoPhysics()) { if (this.mc.currentScreen instanceof ScreenContainerAbstract) // Close out of containers like the inventory { this.mc.displayScreen(null); @@ -402,12 +400,10 @@ public class PlayerLocal extends Player { } if (i > 0 && stat.isAchievement()) { Achievement achievement = (Achievement) stat; - if (achievement.parent == null || this.mc.statsCounter.isUnlocked(achievement.parent)) { - if (!this.mc.statsCounter.isUnlocked(achievement)) { - this.mc.guiToasts.addToast(new AchievementToast(achievement, false)); - } - this.mc.statsCounter.add(stat, i); + if (!this.mc.statsCounter.isUnlocked(achievement)) { + this.mc.guiToasts.addToast(new AchievementToast(achievement, false)); } + this.mc.statsCounter.add(stat, i); } else { this.mc.statsCounter.add(stat, i); } diff --git a/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocalMultiplayer.java b/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocalMultiplayer.java index 556f24d0d..1d5c84f87 100644 --- a/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocalMultiplayer.java +++ b/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocalMultiplayer.java @@ -7,8 +7,9 @@ import net.minecraft.core.data.registry.Registries; import net.minecraft.core.entity.Entity; import net.minecraft.core.entity.EntityItem; import net.minecraft.core.entity.player.Player; +import net.minecraft.core.entity.animal.MobPig; import net.minecraft.core.entity.vehicle.EntityBoat; -import net.minecraft.core.net.packet.PacketBoatControl; +import net.minecraft.core.net.packet.PacketVehicleControl; import net.minecraft.core.net.packet.PacketMessage; import net.minecraft.core.net.packet.PacketPlayerConfig; import net.minecraft.core.net.packet.PacketUpdatePlayerState; @@ -108,13 +109,7 @@ public class PlayerLocalMultiplayer extends PlayerLocal implements Player.Player boolean hasRotated = yRotDiff != 0.0D || xRotDiff != 0.0D; if(vehicle != null) { - if(hasMoved) - { - sendQueue.addToSendQueue(new PacketMovePlayer.Pos(xd, -999D, zd, onGround)); - } else - { - sendQueue.addToSendQueue(new PacketMovePlayer.PosRot(xd, -999D, zd, yRot, xRot, onGround)); - } + sendQueue.addToSendQueue(new PacketMovePlayer.PosRot(xd, -999D, zd, yRot, xRot, onGround)); hasMoved = false; } else if(hasMoved && hasRotated) { sendQueue.addToSendQueue(new PacketMovePlayer.PosRot(x, bb.minY, z, yRot, xRot, onGround)); @@ -259,7 +254,10 @@ public class PlayerLocalMultiplayer extends PlayerLocal implements Player.Player @Override public void sendSpecialVehiclePacket() { if (vehicle instanceof EntityBoat) { - sendQueue.addToSendQueue(new PacketBoatControl((EntityBoat) vehicle)); + sendQueue.addToSendQueue(new PacketVehicleControl((Entity) vehicle)); + } else if (vehicle instanceof MobPig pig) { + double trueY = pig.bb.minY + (double) pig.heightOffset; + sendQueue.addToSendQueue(new PacketVehicleControl(pig.id, pig.x, trueY, pig.z, pig.yRot, pig.consumePendingFallDistance())); } } diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenConsole.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenConsole.java index dad670792..c6bcae7f4 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/ScreenConsole.java +++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenConsole.java @@ -9,6 +9,8 @@ import net.minecraft.client.gui.text.ITextField; import net.minecraft.client.gui.text.TextFieldEditor; import net.minecraft.client.console.shell.RuntimeExecutor; import net.minecraft.client.option.GameSettings; +import net.minecraft.client.render.font.FontRenderer; +import net.minecraft.client.render.font.FontRendererDefault; import net.minecraft.client.render.font.Fonts; import net.minecraft.client.render.window.CursorShape; import net.minecraft.core.net.command.TextFormatting; @@ -37,7 +39,10 @@ public class ScreenConsole extends Screen { private int width = 0; private int scroll = 0; - public LogRenderer() { + private final FontRenderer font; + + public LogRenderer(FontRenderer font) { + this.font = font; this.preludes.put(LogMessage.Level.ERROR, TextFormatting.RED); this.preludes.put(LogMessage.Level.WARN, TextFormatting.YELLOW); this.preludes.put(LogMessage.Level.INFO, TextFormatting.WHITE); @@ -65,14 +70,13 @@ public class ScreenConsole extends Screen { this.scroll = 0; } - var font = Minecraft.getMinecraft().font; - font.startDrawingDeferred(); + this.font.startDrawingDeferred(); final int lines = Math.min(heightLines, WORKED_LINES.size() - this.scroll); for (int i = lines - 1; i >= 0; i--) { final @NotNull String line = WORKED_LINES.get((WORKED_LINES.size() - 1) - (i + this.scroll)); - font.render(line, x, y + getHeight(numLines) - LINE_HEIGHT - LINE_HEIGHT * i).setFont(Fonts.MONOSPACE).setColor(0xFF_CF_CF_CF).call(); + this.font.render(line, x, y + getHeight(numLines) - LINE_HEIGHT - LINE_HEIGHT * i).setColor(0xFF_CF_CF_CF).call(); } - font.draw(this.zLevel); + this.font.draw(this.zLevel); renderScrollIndicator(x, y, numLines); } @@ -182,9 +186,11 @@ public class ScreenConsole extends Screen { private int historyIndex = 0; private final Highlighter highlighter = new Highlighter<>(new RendererFactory()); + private final FontRenderer font; - public InputRenderer() { + public InputRenderer(FontRenderer font) { this.editor = new TextFieldEditor(this, true); + this.font = font; } public void tick() { @@ -195,31 +201,31 @@ public class ScreenConsole extends Screen { boolean addedStart = false; final @NotNull String @NotNull [] splitHighlighted = this.highlightedText.split("\n", -1); for (int i = 0; i < splitHighlighted.length; i++) { - Minecraft.getMinecraft().font.render((addedStart ? " " : "> ") + splitHighlighted[i].replace("\n", ""), x, y).setFont(Fonts.MONOSPACE).setZ(this.zLevel).setColor(0xFF_E0_E0_E0).call(); + this.font.render((addedStart ? " " : "> ") + splitHighlighted[i].replace("\n", ""), x, y + i * LINE_HEIGHT).setZ(this.zLevel).setColor(0xFF_E0_E0_E0).call(); addedStart = true; } final @NotNull String @NotNull [] split = this.text.split("\n", -1); - final int offsetWidth = MathHelper.ceil(Minecraft.getMinecraft().font.stringWidthDouble(" ")); + final int offsetWidth = MathHelper.ceil(this.font.stringWidthDouble(" ")); final int[] cursorPos = getCursor(); final int cursorX; if (cursorPos[0] == split[cursorPos[1]].length()) { - cursorX = MathHelper.ceil(Minecraft.getMinecraft().font.stringWidthDouble(split[cursorPos[1]])); + cursorX = MathHelper.ceil(this.font.stringWidthDouble(split[cursorPos[1]])); } else { - cursorX = MathHelper.ceil(Minecraft.getMinecraft().font.stringWidthDouble(split[cursorPos[1]].substring(0, cursorPos[0]))); + cursorX = MathHelper.ceil(this.font.stringWidthDouble(split[cursorPos[1]].substring(0, cursorPos[0]))); } if ((this.cursorCounter / 6) % 2 == 0) { - Minecraft.getMinecraft().font.render("█", x + offsetWidth + cursorX, y + cursorPos[1] * LINE_HEIGHT).setFont(Fonts.MONOSPACE).setZ(this.zLevel).setColor(0xFF_FF_FF_FF).call(); + this.font.render("█", x + offsetWidth + cursorX, y + cursorPos[1] * LINE_HEIGHT).setZ(this.zLevel).setColor(0xFF_FF_FF_FF).call(); if (this.editor.getCursor() < this.text.length() && this.text.charAt(this.editor.getCursor()) != '\n') { - Minecraft.getMinecraft().font.render("" + this.text.charAt(this.editor.getCursor()), x + offsetWidth + cursorX, y + cursorPos[1] * LINE_HEIGHT).setFont(Fonts.MONOSPACE).setZ(this.zLevel).setColor(0xFF_00_00_00).call(); + this.font.render("" + this.text.charAt(this.editor.getCursor()), x + offsetWidth + cursorX, y + cursorPos[1] * LINE_HEIGHT).setZ(this.zLevel).setColor(0xFF_00_00_00).call(); } } else { - Minecraft.getMinecraft().font.render("_", x + offsetWidth + cursorX, y + cursorPos[1] * LINE_HEIGHT).setFont(Fonts.MONOSPACE).setZ(this.zLevel).setColor(0xFF_FF_FF_FF).call(); + this.font.render("_", x + offsetWidth + cursorX, y + cursorPos[1] * LINE_HEIGHT).setZ(this.zLevel).setColor(0xFF_FF_FF_FF).call(); } } public void click(final int mx, final int my) { - final int oneChar = MathHelper.ceil(Minecraft.getMinecraft().font.stringWidthDouble(" ")); + final int oneChar = MathHelper.ceil(this.font.stringWidthDouble(" ")); final int cx = (mx - (oneChar * 2)) / oneChar; final int cy = my / LINE_HEIGHT; @@ -382,12 +388,14 @@ public class ScreenConsole extends Screen { private final @NotNull LogRenderer logRenderer; private final @NotNull InputRenderer inputRenderer; + private final FontRenderer monospaceFont; public ScreenConsole(final @Nullable Screen parent) { super(parent); - - this.logRenderer = new LogRenderer(); - this.inputRenderer = new InputRenderer(); + this.monospaceFont = new FontRendererDefault(Fonts.MONOSPACE); + this.monospaceFont.init(); + this.logRenderer = new LogRenderer(this.monospaceFont); + this.inputRenderer = new InputRenderer(this.monospaceFont); } private int getMaxY() { diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenHudEditor.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenHudEditor.java index 4a63e1bb0..eaf8818d5 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/ScreenHudEditor.java +++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenHudEditor.java @@ -183,12 +183,7 @@ public class ScreenHudEditor extends Screen { } if (eventKey == GameSettings.KEY_HUD_EDITOR_RESET.getKeyCode()) { - HudComponents.INSTANCE.fromSettingsString(HudComponents.DEFAULT_LAYOUT); - for (HudComponent component : HudComponents.INSTANCE.getComponents()) { - for (Option option : component.getRawOptions()) { - option.resetValueToDefault(); - } - } + HudComponents.INSTANCE.resetToDefault(); this.mc.sndManager.playSound("random.click", SoundCategory.GUI_SOUNDS, 1.0F, 1.0F); return; } diff --git a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenInventoryCreative.java b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenInventoryCreative.java index 90b1e8cdb..4767708ca 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenInventoryCreative.java +++ b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenInventoryCreative.java @@ -116,7 +116,11 @@ public class ScreenInventoryCreative extends ScreenInventory implements ITextCha GameSettings.LAST_CREATIVE_INVENTORY_PAGE.set(clamped); GameSettings.saveOptions(); } - this.container.setInventoryStatus(clamped, this.container.searchText); + if (clamped == this.container.page) { + this.container.broadcastInventoryStatus(); + } else { + this.container.setInventoryStatus(clamped, this.container.searchText); + } } private void persistCreativeInventoryPage() { diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngame.java b/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngame.java index ef2f5e185..5820f286c 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngame.java +++ b/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngame.java @@ -19,7 +19,9 @@ import net.minecraft.client.render.renderer.Shaders; import net.minecraft.client.render.renderer.State; import net.minecraft.client.render.tessellator.TessellatorShader; import net.minecraft.client.render.tessellator.TessellatorTerrainImpl; +import net.minecraft.core.block.BlockLogicConduit; import net.minecraft.core.block.BlockLogicPortal; +import net.minecraft.core.block.BlockLogicWireRedstone; import net.minecraft.core.enums.HumanArmorShape; import net.minecraft.core.player.gamemode.Gamemodes; import net.minecraft.core.util.helper.Direction; @@ -385,8 +387,14 @@ public class HudIngame extends Gui { drawDebugScreenLineRight(hudTessellater, hudBuilder.append("Light: Sky: ").append(this.mc.currentWorld.getSavedLightValue(LightLayer.Sky, lightX, lightY, lightZ)).append(" Block: ").append(this.mc.currentWorld.getSavedLightValue(LightLayer.Block, lightX, lightY, lightZ))); hudBuilder.setLength(0); } - drawDebugScreenLineRight(hudTessellater, hudBuilder.append("Signal: ").append(this.mc.currentWorld.hasSignal(hitTile.tilePos, hitTile.side))); hudBuilder.setLength(0); - drawDebugScreenLineRight(hudTessellater, hudBuilder.append("Direct signal: ").append(this.mc.currentWorld.hasDirectSignal(hitTile.tilePos, hitTile.side))); hudBuilder.setLength(0); + Side signalSide = hitTile.side.opposite(); + drawDebugScreenLineRight(hudTessellater, hudBuilder.append("Signal: ").append(this.mc.currentWorld.hasSignal(hitTile.tilePos, signalSide))); hudBuilder.setLength(0); + drawDebugScreenLineRight(hudTessellater, hudBuilder.append("Direct signal: ").append(this.mc.currentWorld.hasDirectSignal(hitTile.tilePos, signalSide))); hudBuilder.setLength(0); + + int signalStrength = getSignalStrength(block, meta, hitTile.tilePos); + if (signalStrength >= 0) { + drawDebugScreenLineRight(hudTessellater, hudBuilder.append("Signal strength: ").append(signalStrength)); hudBuilder.setLength(0); + } for (Tag> tag : BlockTags.TAG_LIST) { if (tag.appliesTo(block)) { @@ -734,4 +742,26 @@ public class HudIngame extends Gui { public static Direction getFacingDirection(Player player) { return directions[(MathHelper.floor((double) ((player.yRot * 4F) / 360F) + 0.5D) + 2) & 3]; } + + /** + * Resolves the 0-15 redstone signal strength emitted by a redstone component. + * Returns -1 for blocks that are not redstone components, signalling that no line should be drawn. + */ + private int getSignalStrength(final @NotNull Block block, final int meta, final @NotNull net.minecraft.core.world.pos.TilePosc tilePos) { + if (block == Blocks.WIRE_REDSTONE) { + return meta & BlockLogicWireRedstone.MASK_POWER; + } + if (block == Blocks.CONDUIT) { + return BlockLogicConduit.getPower(this.mc.currentWorld, tilePos); + } + if (block.isSignalSource()) { + for (final Side side : Side.sides) { + if (this.mc.currentWorld.hasSignal(tilePos, side)) { + return BlockLogicWireRedstone.SIGNAL_MAX; + } + } + return BlockLogicWireRedstone.SIGNAL_MIN; + } + return -1; + } } \ No newline at end of file diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponent.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponent.java index 6b089a1da..75025ead8 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponent.java +++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponent.java @@ -86,7 +86,7 @@ public abstract class HudComponent { } public void setScaleOverride(int value) { - this.getGuiScaleOverrideOption().value = Math.max(0, value); + this.getGuiScaleOverrideOption().value = OptionGuiScaleOverride.clampValue(value); } public static int getEffectiveGlobalScale() { diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponents.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponents.java index 6ee04f34d..895b47967 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponents.java +++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponents.java @@ -7,6 +7,7 @@ import net.minecraft.client.gui.options.components.BooleanOptionComponent; import net.minecraft.client.gui.options.components.KeyBindingComponent; import net.minecraft.client.gui.options.components.ToggleableOptionComponent; import net.minecraft.client.option.GameSettings; +import net.minecraft.client.option.Option; import net.minecraft.core.enums.HumanArmorShape; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -148,6 +149,18 @@ public class HudComponents { return this.components; } + public void resetToDefault() { + if (DEFAULT_LAYOUT == null) { + return; + } + fromSettingsString(DEFAULT_LAYOUT); + for (HudComponent component : getComponents()) { + for (Option option : component.getRawOptions()) { + option.resetValueToDefault(); + } + } + } + public @Nullable HudComponent getComponent(String key) { for (HudComponent component : this.components) { if (component.getKey().equals(key)) { diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java b/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java index d2dbd742c..638f06345 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java +++ b/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java @@ -522,6 +522,10 @@ public abstract class OptionsPages { .withComponent(new ShortcutComponent("gui.options.page.debug.button.reload_commands", () ->{ if (Minecraft.getMinecraft().currentWorld != null) Minecraft.getMinecraft().currentWorld.getCommandManager().reload(); })) + .withComponent(new ShortcutComponent("gui.options.page.debug.button.reset_hud_onboarding", () -> { + GameSettings.SEEN_HUD_EDITOR_ONBOARDING.set(false); + GameSettings.saveOptions(); + })) )); } } \ No newline at end of file diff --git a/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java b/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java index 47d2bc3f8..0bd4e7842 100644 --- a/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java +++ b/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java @@ -41,7 +41,6 @@ import net.minecraft.core.entity.Mob; import net.minecraft.core.entity.EntityPainting; import net.minecraft.core.entity.player.Player; import net.minecraft.core.entity.projectile.Projectile; -import net.minecraft.core.entity.vehicle.EntityBoat; import net.minecraft.core.enums.ArtType; import net.minecraft.core.item.ItemMap; import net.minecraft.core.item.ItemStack; @@ -292,14 +291,19 @@ public class PacketHandlerClient extends PacketHandler { @Override public void handleEntityFling(final @NotNull PacketEntityFling packetEntityFling) { final Entity entity = getEntityByID(packetEntityFling.entityId); - if (entity != null) { - entity.pushesThisTick = packetEntityFling.pushesTick; - entity.fallDistance = 0; - entity.xd = packetEntityFling.xd; - entity.yd = packetEntityFling.yd; - entity.zd = packetEntityFling.zd; - entity.pushTime = packetEntityFling.pushTime; + if (entity == null) { + return; + } + if (entity == this.mc.thePlayer.vehicle) { + entity.fling(packetEntityFling.xd, packetEntityFling.yd, packetEntityFling.zd, packetEntityFling.pushTime); + return; } + entity.pushesThisTick = packetEntityFling.pushesTick; + entity.fallDistance = 0; + entity.xd = packetEntityFling.xd; + entity.yd = packetEntityFling.yd; + entity.zd = packetEntityFling.zd; + entity.pushTime = packetEntityFling.pushTime; } @Override @@ -606,10 +610,10 @@ public class PacketHandlerClient extends PacketHandler { } @Override - public void handleBoatControl(@NotNull PacketBoatControl packetBoatControl) { - Entity e = this.worldClientMP.getEntityFromId(packetBoatControl.entityId); - if (e instanceof EntityBoat) { - ((EntityBoat) e).handleControlDirect(packetBoatControl.targetXD, packetBoatControl.targetZD, packetBoatControl.targetYRot); + public void handleVehicleControl(@NotNull PacketVehicleControl packetVehicleControl) { + Entity e = this.worldClientMP.getEntityFromId(packetVehicleControl.entityId); + if (e != null) { + e.handleControlDirect(packetVehicleControl.targetXD, packetVehicleControl.targetYD, packetVehicleControl.targetZD, packetVehicleControl.targetYRot); } } @@ -732,8 +736,12 @@ public class PacketHandlerClient extends PacketHandler { } else { vehicle = getEntityByID(packetSetRiding.vehicleId); } - if (passenger != null && vehicle != null) { - passenger.startRiding(vehicle); + if (passenger != null) { + if (vehicle != null) { + passenger.startRiding(vehicle); + } else if (!packetSetRiding.isTileEntity && packetSetRiding.vehicleId == -1) { + passenger.startRiding(null); + } } } @@ -793,6 +801,7 @@ public class PacketHandlerClient extends PacketHandler { this.worldClientMP.isClientSide = true; this.mc.changeWorld(this.worldClientMP); this.mc.thePlayer.dimension = packetRespawn.respawnDimensionId; + this.mc.thePlayer.vehicle = null; this.mc.displayScreen(new ScreenDownloadTerrain(this)); } this.mc.respawn(true, packetRespawn.respawnDimensionId); @@ -884,42 +893,35 @@ public class PacketHandlerClient extends PacketHandler { public void handleContainerSetSlot(@NotNull PacketContainerSetSlot packetContainerSetSlot) { if (packetContainerSetSlot.windowId == -1) { this.mc.thePlayer.inventory.setHeldItemStack(packetContainerSetSlot.myItemStack); + this.mc.thePlayer.containerMenu.stateId = packetContainerSetSlot.stateId; } else if (packetContainerSetSlot.windowId == 0 && packetContainerSetSlot.itemSlot >= ContainerInventory.MAIN_INVENTORY_SIZE && packetContainerSetSlot.itemSlot < ContainerInventory.MAIN_INVENTORY_SIZE + ContainerInventory.HOTBAR_SIZE) { ItemStack itemstack = this.mc.thePlayer.inventoryMenu.getSlot(packetContainerSetSlot.itemSlot).getItemStack(); if (packetContainerSetSlot.myItemStack != null && (itemstack == null || itemstack.stackSize < packetContainerSetSlot.myItemStack.stackSize)) { packetContainerSetSlot.myItemStack.animationsToGo = 5; } this.mc.thePlayer.inventoryMenu.setItem(packetContainerSetSlot.itemSlot, packetContainerSetSlot.myItemStack); + this.mc.thePlayer.inventoryMenu.stateId = packetContainerSetSlot.stateId; } else if (packetContainerSetSlot.windowId == this.mc.thePlayer.containerMenu.containerId) { this.mc.thePlayer.containerMenu.setItem(packetContainerSetSlot.itemSlot, packetContainerSetSlot.myItemStack); + this.mc.thePlayer.containerMenu.stateId = packetContainerSetSlot.stateId; } } @Override public void handleContainerAck(@NotNull PacketContainerAck packetContainerAck) { - MenuAbstract container = null; - if (packetContainerAck.windowId == 0) { - container = this.mc.thePlayer.inventoryMenu; - } else if (packetContainerAck.windowId == this.mc.thePlayer.containerMenu.containerId) { - container = this.mc.thePlayer.containerMenu; - } - if (container != null) { - if (packetContainerAck.accepted) { - container.deleteBackup(packetContainerAck.shortWindowId); - } else { - container.rollbackToBackup(packetContainerAck.shortWindowId); - addToSendQueue(new PacketContainerAck(packetContainerAck.windowId, packetContainerAck.shortWindowId, true)); - } - } + //reconciliation of state ids and delta corrections render container ack deprecated } @Override public void handleContainerSetContent(@NotNull PacketContainerSetContent packetContainerSetContent) { if (packetContainerSetContent.windowId == 0) { this.mc.thePlayer.inventoryMenu.setAll(packetContainerSetContent.stackList); + this.mc.thePlayer.inventoryMenu.stateId = packetContainerSetContent.stateId; } else if (packetContainerSetContent.windowId == this.mc.thePlayer.containerMenu.containerId) { this.mc.thePlayer.containerMenu.setAll(packetContainerSetContent.stackList); + this.mc.thePlayer.containerMenu.stateId = packetContainerSetContent.stateId; } + this.mc.thePlayer.inventory.setHeldItemStack(packetContainerSetContent.carriedItem); } @Override diff --git a/game/client/src/main/java/net/minecraft/client/option/GameSettings.java b/game/client/src/main/java/net/minecraft/client/option/GameSettings.java index e8445791d..b21898223 100644 --- a/game/client/src/main/java/net/minecraft/client/option/GameSettings.java +++ b/game/client/src/main/java/net/minecraft/client/option/GameSettings.java @@ -9,7 +9,6 @@ import net.minecraft.client.discord.RichPresenceHandlerThread; import net.minecraft.client.enums.MusicFrequency; import net.minecraft.client.enums.SelectedSoundtrack; import net.minecraft.client.gui.TooltipElement; -import net.minecraft.client.gui.hud.component.HudComponent; import net.minecraft.client.gui.hud.component.HudComponents; import net.minecraft.client.gui.options.ScreenOptions; import net.minecraft.client.input.InputDevice; @@ -134,7 +133,7 @@ public final class GameSettings { public static final @NotNull OptionBoolean VIEW_BOBBING = register(new OptionBoolean("bobView", true)); public static final @NotNull OptionBoolean TRANSPARENCY_DEPTH_CHECK = register(new OptionBoolean("transparencyDepthCheck", true)); public static final @NotNull OptionEnum PARTICLES_QUALITY = register(new OptionEnum<>("particleQuality", ParticlesQuality.class, ParticlesQuality.ALL)); - public static final @NotNull OptionRange PARTICLES_CAP = register(new OptionRange("particleCap", 50000, 1000, 100000)); + public static final @NotNull OptionRange PARTICLES_CAP = register(new OptionRange("particleCap", 4000, 500, 15000)); public static final @NotNull OptionRange PARTICLE_RENDER_DISTANCE = register(new OptionRange("particleRenderDistance", 8, 1, 24) .addOnChangeCallback((mc, option) -> { if (mc.currentScreen instanceof ScreenOptions) { @@ -272,11 +271,6 @@ public final class GameSettings { } }) .withDisplayStringProvider((mc, i18n, option) -> { - for (HudComponent component : HudComponents.INSTANCE.getComponents()) { - if (component.getScaleOverride() > 0) { - return i18n.translateKey("options.guiScale.disabled"); - } - } if (option.value == 0) { return i18n.translateKey("options.guiScale.auto"); } else { @@ -695,6 +689,11 @@ public final class GameSettings { HudComponents.DEFAULT_LAYOUT = HudComponents.INSTANCE.toSettingsString(); loadOptions(); + + if (!SEEN_HUD_EDITOR_ONBOARDING.value) { + HudComponents.INSTANCE.resetToDefault(); + } + saveOptions(); } diff --git a/game/client/src/main/java/net/minecraft/client/option/OptionGuiScaleOverride.java b/game/client/src/main/java/net/minecraft/client/option/OptionGuiScaleOverride.java index d75a8cb59..096b93e0a 100644 --- a/game/client/src/main/java/net/minecraft/client/option/OptionGuiScaleOverride.java +++ b/game/client/src/main/java/net/minecraft/client/option/OptionGuiScaleOverride.java @@ -1,24 +1,32 @@ package net.minecraft.client.option; import net.minecraft.client.Minecraft; -import net.minecraft.client.ScaledResolution; import net.minecraft.core.lang.I18n; import org.jetbrains.annotations.NotNull; /** - * Per-instance scale override for HUD components. Behaves much like - * {@link OptionGuiScale}, but with a "Disabled" entry instead of "Auto"; when - * {@code value == 0} the component should fall back to the global GUI scale. + * Per-instance scale override for HUD components. Has a fixed 1x + * to {@value #MAX_SCALE}x range plus a "Disabled" entry; when 0 the + * component should fall back to the global GUI scale. * *

Instances of this class are intentionally NOT registered through * {@link GameSettings#register}: each HUD Component * owns its own instance and serializes it as part of its own settings string. */ public class OptionGuiScaleOverride extends OptionToggleable { + public static final int MAX_SCALE = 12; + public OptionGuiScaleOverride() { super("guiScaleOverride", 0, new Integer[1]); } + public static int clampValue(int value) { + if (value <= 0) { + return 0; + } + return Math.min(value, MAX_SCALE); + } + @Override public void toggle() { toggle(1); @@ -32,28 +40,24 @@ public class OptionGuiScaleOverride extends OptionToggleable { @Override public int getValueIndex() { - int max = size(); - if (this.value <= 0 || this.value >= max) { + if (this.value <= 0 || this.value > MAX_SCALE) { return 0; } - return max - this.value; + return size() - this.value; } @Override public void setValueWithIndex(int i) { - if (i != 0) { - this.value = size() - i; - } else { + if (i <= 0 || i > MAX_SCALE) { this.value = 0; + } else { + this.value = size() - i; } } @Override public int size() { - Minecraft mc = Minecraft.getMinecraft(); - int width = mc.gameWindow.getWidthScreenCoords(); - int height = mc.gameWindow.getHeightScreenCoords(); - return ScaledResolution.getMaxScale(width, height); + return MAX_SCALE + 1; } @Override @@ -64,7 +68,7 @@ public class OptionGuiScaleOverride extends OptionToggleable { @Override public void fromOptionsString(@NotNull String string) { try { - this.value = Integer.parseInt(string); + this.value = clampValue(Integer.parseInt(string)); } catch (NumberFormatException e) { this.value = 0; } diff --git a/game/client/src/main/java/net/minecraft/client/player/controller/PlayerControllerMP.java b/game/client/src/main/java/net/minecraft/client/player/controller/PlayerControllerMP.java index 3947bb6d1..4dc8f5ed9 100644 --- a/game/client/src/main/java/net/minecraft/client/player/controller/PlayerControllerMP.java +++ b/game/client/src/main/java/net/minecraft/client/player/controller/PlayerControllerMP.java @@ -1,5 +1,7 @@ package net.minecraft.client.player.controller; +import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.PlayerLocalMultiplayer; import net.minecraft.client.net.handler.PacketHandlerClient; @@ -9,6 +11,7 @@ import net.minecraft.core.entity.Entity; import net.minecraft.core.entity.player.Player; import net.minecraft.core.enums.ArtType; import net.minecraft.core.item.ItemStack; +import net.minecraft.core.player.inventory.menu.MenuAbstract; import net.minecraft.core.net.packet.*; import net.minecraft.core.util.helper.Direction; import net.minecraft.core.util.helper.Side; @@ -116,9 +119,29 @@ public class PlayerControllerMP @Override public @Nullable ItemStack handleInventoryMouseClick(final int windowId, final @NotNull InventoryAction action, final int @Nullable [] args, final @NotNull Player player) { - final short actionId = player.containerMenu.backup(player.inventory); + final MenuAbstract menu = player.containerMenu; + + final int slotCount = menu.slots.size(); + final ItemStack[] before = new ItemStack[slotCount]; + for (int i = 0; i < slotCount; i++) { + final ItemStack stack = menu.getSlot(i).getItemStack(); + before[i] = stack == null ? null : stack.copy(); + } + + final int stateId = menu.getStateId(); final @Nullable ItemStack itemStack = super.handleInventoryMouseClick(windowId, action, args, player); - this.packetHandler.addToSendQueue(new PacketContainerClick(windowId, action, args, itemStack, actionId)); + + final Int2ObjectMap changedSlots = new Int2ObjectArrayMap<>(); + for (int i = 0; i < slotCount; i++) { + final ItemStack now = menu.getSlot(i).getItemStack(); + if (!ItemStack.areItemStacksEqual(before[i], now)) { + changedSlots.put(i, now == null ? null : now.copy()); + } + } + final ItemStack held = player.inventory.getHeldItemStack(); + final @Nullable ItemStack carriedItem = held == null ? null : held.copy(); + + this.packetHandler.addToSendQueue(new PacketContainerClick(windowId, action, args, stateId, changedSlots, carriedItem)); return itemStack; } diff --git a/game/client/src/main/java/net/minecraft/client/render/OpenGLHelper.java b/game/client/src/main/java/net/minecraft/client/render/OpenGLHelper.java index d27048aa6..a2a33c714 100644 --- a/game/client/src/main/java/net/minecraft/client/render/OpenGLHelper.java +++ b/game/client/src/main/java/net/minecraft/client/render/OpenGLHelper.java @@ -103,23 +103,24 @@ public class OpenGLHelper { } public static void checkError(String info) { - if (Global.DEBUG_MODE) { - int errorCode = GL41.glGetError(); - - if (errorCode != GL41.GL_NO_ERROR) { - if (Global.BUILD_CHANNEL.isUnstableBuild()) { - String error = errorCode + " (" + getErrorDescription(errorCode) + "): " + info; - throw new RuntimeException("OpenGL Error " + error); - } - - if (!errors.contains(info)) { - errors.add(info); - String error = errorCode + " (" + getErrorDescription(errorCode) + "): " + info; - LOGGER.error("########## GL ERROR ##########"); - LOGGER.error("OpenGL Error {}", error); - } - } - } + // This error checking is not very helpful, the newer logger callback work vastly better +// if (Global.DEBUG_MODE) { +// int errorCode = GL41.glGetError(); +// +// if (errorCode != GL41.GL_NO_ERROR) { +// if (Global.BUILD_CHANNEL.isUnstableBuild()) { +// String error = errorCode + " (" + getErrorDescription(errorCode) + "): " + info; +// throw new RuntimeException("OpenGL Error " + error); +// } +// +// if (!errors.contains(info)) { +// errors.add(info); +// String error = errorCode + " (" + getErrorDescription(errorCode) + "): " + info; +// LOGGER.error("########## GL ERROR ##########"); +// LOGGER.error("OpenGL Error {}", error); +// } +// } +// } } public static String getErrorDescription(int error) { diff --git a/game/client/src/main/java/net/minecraft/client/render/ParticleEngine.java b/game/client/src/main/java/net/minecraft/client/render/ParticleEngine.java index 0daeb80e6..28df94f8c 100644 --- a/game/client/src/main/java/net/minecraft/client/render/ParticleEngine.java +++ b/game/client/src/main/java/net/minecraft/client/render/ParticleEngine.java @@ -13,7 +13,6 @@ import net.minecraft.client.render.renderer.CompareFunc; import net.minecraft.client.render.renderer.GLRenderer; import net.minecraft.client.render.renderer.Shaders; import net.minecraft.client.render.renderer.State; -import net.minecraft.client.render.tessellator.TessellatorGeneral; import net.minecraft.client.render.tessellator.TessellatorParticle; import net.minecraft.client.render.tessellator.TessellatorParticleShader; import net.minecraft.client.render.texture.stitcher.TextureRegistry; @@ -22,6 +21,7 @@ import net.minecraft.core.block.Blocks; import net.minecraft.core.block.material.MaterialGas; import net.minecraft.core.block.material.MaterialLiquid; import net.minecraft.core.entity.player.Player; +import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePosc; @@ -30,9 +30,7 @@ import org.joml.primitives.AABBd; import org.joml.primitives.AABBdc; import org.lwjgl.opengl.GL41; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Random; /** @@ -45,15 +43,11 @@ public final class ParticleEngine { private final @NotNull TessellatorParticleShader shaderParticleTessellator = new TessellatorParticleShader(4000 * 40); private World world; - private final List[] particles; + private final @NotNull List<@NotNull Particle> @NotNull [] particles; private final Random rand; - private final Map, ObjectArrayList> particlePools = new HashMap<>(); - private final AABBd cullingAABB = new AABBd(); - private int globalTick = 0; - private double lastCamX, lastCamY, lastCamZ; - public ParticleEngine(World world) { + //noinspection unchecked this.particles = new ObjectArrayList[TEXTURE_COUNT]; this.rand = new Random(); if (world != null) { @@ -72,54 +66,20 @@ public final class ParticleEngine { public void add(@NotNull Particle particle) { int t = particle.getParticleTexture(); - if (this.particles[t].size() >= GameSettings.PARTICLES_CAP.value) { - // Find the furthest particle to delete instead of just the oldest - int indexToRemove = getIndexToRemove(t); - - // Return the furthest particle to the Object Pool - Particle removed = this.particles[t].remove(indexToRemove); - ObjectArrayList pool = this.particlePools.computeIfAbsent(removed.getClass(), k -> new ObjectArrayList<>()); - if (pool.size() < GameSettings.PARTICLES_CAP.value) { - pool.add(removed); - } + var s = this.particles[t].size(); + if (s >= GameSettings.PARTICLES_CAP.value) { + this.particles[t].remove(this.rand.nextInt(s)); } this.particles[t].add(particle); particle.init(); } - private int getIndexToRemove(int t) { - int indexToRemove = 0; - double maxDistSq = -1; - - // Only scan a handful of particles to avoid CPU lag when overflowing - int scanLimit = Math.min(50, this.particles[t].size()); - - for (int i = 0; i < scanLimit; i++) { - Particle check = this.particles[t].get(i); - double distSq = (check.x - lastCamX)*(check.x - lastCamX) + - (check.y - lastCamY)*(check.y - lastCamY) + - (check.z - lastCamZ)*(check.z - lastCamZ); - - if (distSq > maxDistSq) { - maxDistSq = distSq; - indexToRemove = i; - } - } - return indexToRemove; - } /** * Ticks all the particles in the engine. */ public void tick() { - this.globalTick++; - - Player localPlayer = this.world.players.isEmpty() ? null : this.world.players.get(0); - if (localPlayer != null) { - this.world.particleEmitters.tick(this.world, localPlayer, GameSettings.PARTICLE_RENDER_DISTANCE.value); - } - for (int tt = 0; tt < this.particles.length; tt++) { for (int i = 0; i < this.particles[tt].size(); i++) { Particle p = this.particles[tt].get(i); @@ -127,16 +87,6 @@ public final class ParticleEngine { p.tick(); if (p.removed) { this.particles[tt].remove(i--); - - Class c = p.getClass(); - ObjectArrayList pl = this.particlePools.get(c); - if (pl == null) { - pl = new ObjectArrayList<>(); - this.particlePools.put(c, pl); - } - if (pl.size() < GameSettings.PARTICLES_CAP.value) { - pl.add(p); - } } } } @@ -149,6 +99,9 @@ public final class ParticleEngine { * @param partialTick The time since the last tick. */ public void renderParticles(@NotNull ICamera camera, float partialTick) { +// class Cache { +// private static final AABBd cullingAABB = new AABBd(); +// } GLRenderer.pushFrame(); GLRenderer.setColor4f(1f, 1f, 1f, 1f); GLRenderer.setShader(Shaders.PARTICLE); @@ -169,13 +122,9 @@ public final class ParticleEngine { double yOff = camera.getY(partialTick); double zOff = camera.getZ(partialTick); - this.lastCamX = xOff; - this.lastCamY = yOff; - this.lastCamZ = zOff; - double maxDist = GameSettings.PARTICLE_RENDER_DISTANCE.value * 16.0; double maxRenderDistSq = maxDist * maxDist; - boolean frustumCull = GameSettings.FRUSTUM_CULLING.value; +// boolean frustumCull = GameSettings.FRUSTUM_CULLING.value; for (int tt = 0; tt == WORLD_TEXTURE; tt++) { if (this.particles[tt].isEmpty()) continue; @@ -186,22 +135,25 @@ public final class ParticleEngine { for (int i = 0; i < this.particles[tt].size(); i++) { Particle p = this.particles[tt].get(i); - double distSq = (p.x - xOff)*(p.x - xOff) + (p.y - yOff)*(p.y - yOff) + (p.z - zOff)*(p.z - zOff); + double dx = p.x - xOff; + double dy = p.y - yOff; + double dz = p.z - zOff; + double distSq = dx * dx + dy * dy + dz * dz; if (distSq > maxRenderDistSq) continue; - if (frustumCull) { - double lerpX = net.minecraft.core.util.helper.MathHelper.lerp(p.xo, p.x, partialTick); - double lerpY = net.minecraft.core.util.helper.MathHelper.lerp(p.yo, p.y, partialTick); - double lerpZ = net.minecraft.core.util.helper.MathHelper.lerp(p.zo, p.z, partialTick); - double r = p.size * 0.1; - - this.cullingAABB.setMin(lerpX - r, lerpY - r, lerpZ - r); - this.cullingAABB.setMax(lerpX + r, lerpY + r, lerpZ + r); - - if (!camera.getFrustum().isVisible(this.cullingAABB, partialTick)) { - continue; - } - } +// if (frustumCull) { +// double lerpX = MathHelper.lerp(p.xo, p.x, partialTick); +// double lerpY = MathHelper.lerp(p.yo, p.y, partialTick); +// double lerpZ = MathHelper.lerp(p.zo, p.z, partialTick); +// double r = p.size * 0.1; +// +// Cache.cullingAABB.setMin(lerpX - r, lerpY - r, lerpZ - r); +// Cache.cullingAABB.setMax(lerpX + r, lerpY + r, lerpZ + r); +// +// if (!camera.getFrustum().isVisible(Cache.cullingAABB, partialTick)) { +// continue; +// } +// } p.render(tessellator, partialTick); } @@ -211,15 +163,6 @@ public final class ParticleEngine { GLRenderer.popFrame(); } - @SuppressWarnings("unchecked") - private T getPooledParticle(Class type) { - ObjectArrayList pool = this.particlePools.computeIfAbsent(type, k -> new ObjectArrayList<>()); - if (!pool.isEmpty()) { - return (T) pool.remove(pool.size() - 1); - } - return null; - } - /** * Renders all the particles in the engine whose texture type is ENTITY_PARTICLE_TEXTURE. * These particles are drawn using OpenGL normal-based lighting, unlike the other particles, @@ -228,7 +171,7 @@ public final class ParticleEngine { * @param camera The camera relative to whose perspective the particles should be drawn. * @param partialTick The time since the last tick. */ - public void renderLitParticles(ICamera camera, float partialTick) { + public void renderLitParticles(@NotNull ICamera camera, float partialTick) { int tt = ENTITY_PARTICLE_TEXTURE; if (this.particles[tt].isEmpty()) { return; @@ -291,13 +234,7 @@ public final class ParticleEngine { double velY = yp - blockPos.y() - centerY; double velZ = zp - blockPos.z() - centerZ; - ParticleBlockBreaking particle = getPooledParticle(ParticleBlockBreaking.class); - if (particle == null) { - particle = new ParticleBlockBreaking(this.world, xp, yp, zp, velX, velY, velZ, block, side, data); - } else { - particle.reset(this.world, xp, yp, zp, velX, velY, velZ, block, side, data); - } - + ParticleBlockBreaking particle = new ParticleBlockBreaking(this.world, xp, yp, zp, velX, velY, velZ, block, side, data); add(particle.init(blockPos)); } } @@ -337,25 +274,11 @@ public final class ParticleEngine { xp = blockPos.x() + bounds.maxX() + r; } - ParticleBlockBreaking p = getPooledParticle(ParticleBlockBreaking.class); - if (p == null) { - p = new ParticleBlockBreaking(this.world, xp, yp, zp, 0.0D, 0.0D, 0.0D, block, side, this.world.getBlockData(blockPos)); - } else { - p.reset(this.world, xp, yp, zp, 0.0D, 0.0D, 0.0D, block, side, this.world.getBlockData(blockPos)); - } - + ParticleBlockBreaking p = new ParticleBlockBreaking(this.world, xp, yp, zp, 0.0D, 0.0D, 0.0D, block, side, this.world.getBlockData(blockPos)); add(p.init(blockPos).setPower(0.2F).setScale(0.6F)); } public int countParticles() { return this.particles[WORLD_TEXTURE].size() + this.particles[ENTITY_PARTICLE_TEXTURE].size(); } - - public int getGlobalTick() { - return globalTick; - } - - public void setGlobalTick(int globalTick) { - this.globalTick = globalTick; - } } diff --git a/game/client/src/main/java/net/minecraft/client/render/WorldRenderer.java b/game/client/src/main/java/net/minecraft/client/render/WorldRenderer.java index 7d5b8e246..c299780a8 100644 --- a/game/client/src/main/java/net/minecraft/client/render/WorldRenderer.java +++ b/game/client/src/main/java/net/minecraft/client/render/WorldRenderer.java @@ -170,6 +170,10 @@ public class WorldRenderer { for (int i = 0; i < entities.size(); i++) { final Entity entity = entities.get(i); + if (entity == this.mc.thePlayer.vehicle && entity.passesThroughRiderTargeting(playerItem)) { + continue; + } + if (playerItem != null) { if (!playerItem.interactsWithEntity(entity)) continue; } else { diff --git a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorConduit.java b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorConduit.java index c6a3a258f..ab3b8efe0 100644 --- a/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorConduit.java +++ b/game/client/src/main/java/net/minecraft/client/render/block/color/BlockColorConduit.java @@ -43,9 +43,8 @@ public class BlockColorConduit extends BlockColor { } @Override - public int getWorldColor(WorldSource world, @NotNull TilePosc tilePos, int tintIndex) { - int data = world.getBlockData(tilePos); - int strength = data / BlockLogicConduit.STATE_COUNT; + public int getWorldColor(@NotNull WorldSource world, @NotNull TilePosc tilePos, int tintIndex) { + int strength = BlockLogicConduit.getPower(world, tilePos); strength = Math.max(0, Math.min(15, strength)); return powerColors[strength]; } diff --git a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelConduit.java b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelConduit.java index 7c09ff5fc..de26cd26c 100644 --- a/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelConduit.java +++ b/game/client/src/main/java/net/minecraft/client/render/block/model/BlockModelConduit.java @@ -17,6 +17,8 @@ public class BlockModelConduit extends BlockModelGe private final ModelState[] stateMapOn = new ModelState[BlockLogicConduit.STATE_COUNT]; private final ModelState[] stateMapOff = new ModelState[BlockLogicConduit.STATE_COUNT]; + private final ModelState[] capStateMapOn = new ModelState[6]; + private final ModelState[] capStateMapOff = new ModelState[6]; private final ModelState inertState; public BlockModelConduit(Block block) { @@ -25,17 +27,31 @@ public class BlockModelConduit extends BlockModelGe StaticBlockModel onCore = BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/conduit/conduit_core").asModel(); StaticBlockModel onStraight = BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/conduit/conduit_straight").asModel(); StaticBlockModel onCorner = BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/conduit/conduit_corner").asModel(); + StaticBlockModel onCap = BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/conduit/conduit_cap").asModel(); StaticBlockModel offCore = BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/conduit/conduit_core_off").asModel(); StaticBlockModel offStraight = BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/conduit/conduit_straight_off").asModel(); StaticBlockModel offCorner = BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/conduit/conduit_corner_off").asModel(); + StaticBlockModel offCap = BlockModelDispatcher.loadDataModel("minecraft:block/rubyglass/conduit/conduit_cap_off").asModel(); this.inertState = new ModelState(onCore, 0, 0, 0); populateStateMap(stateMapOn, onCore, onStraight, onCorner); populateStateMap(stateMapOff, offCore, offStraight, offCorner); + populateCapStateMap(capStateMapOn, onCap); + populateCapStateMap(capStateMapOff, offCap); } - private void populateStateMap(ModelState[] map, StaticBlockModel core, StaticBlockModel straight, StaticBlockModel corner) { + private void populateCapStateMap(ModelState @NotNull [] map, StaticBlockModel cap) { + //B + map[0] = new ModelState(cap, 0, 0, 0); //DOWN + map[1] = new ModelState(cap, 2, 0, 0); //UP + map[2] = new ModelState(cap, 1, 0, 0); //N + map[3] = new ModelState(cap, 3, 0, 0); //S + map[4] = new ModelState(cap, 0, 0, 3); //W + map[5] = new ModelState(cap, 0, 0, 1); //E + } + + private void populateStateMap(ModelState @NotNull [] map, StaticBlockModel core, StaticBlockModel straight, StaticBlockModel corner) { // Core map[0] = new ModelState(core, 0, 0, 0); //Closed @@ -63,36 +79,35 @@ public class BlockModelConduit extends BlockModelGe map[15] = new ModelState(corner, 0, 2, 1); //SE } - @Override - public @NotNull StaticBlockModel getModelFromData(int data) { + private @NotNull ModelState resolveState(int data) { int state = data & BlockLogicConduit.STATE_MASK; - int strength = (data >> BlockLogicConduit.POWER_SHIFT) & BlockLogicConduit.POWER_MASK; - if (state == 0 && strength == 15) { - return inertState.model; + if (state != 0) { + int strength = (data >> BlockLogicConduit.POWER_SHIFT) & BlockLogicConduit.POWER_MASK; + return strength == 0 ? stateMapOff[state] : stateMapOn[state]; + } + + if (BlockLogicConduit.isCap(data)) { + int sideId = BlockLogicConduit.getCapSide(data).id; + return BlockLogicConduit.isCapPowered(data) ? capStateMapOn[sideId] : capStateMapOff[sideId]; } - if (strength == 0) { - return stateMapOff[state].model; - } else { - return stateMapOn[state].model; + int strength = (data >> BlockLogicConduit.POWER_SHIFT) & BlockLogicConduit.POWER_MASK; + if (strength == BlockLogicConduit.INERT_MARKER) { + return inertState; } + return stateMapOff[0]; + } + + @Override + public @NotNull StaticBlockModel getModelFromData(int data) { + return resolveState(data).model; } @Override public boolean renderAttached(final @NotNull TessellatorGeneral tessellator, @NotNull final WorldSource worldSource, @NotNull TilePosc tilePos, boolean cullFaces, final @Nullable IconCoordinate overrideTexture) { int data = worldSource.getBlockData(tilePos); - int state = data & BlockLogicConduit.STATE_MASK; - int strength = (data >> BlockLogicConduit.POWER_SHIFT) & BlockLogicConduit.POWER_MASK; - - ModelState activeState; - if (state == 0 && strength == 15) { - activeState = inertState; - } else if (strength == 0) { - activeState = stateMapOff[state]; - } else { - activeState = stateMapOn[state]; - } + ModelState activeState = resolveState(data); return activeState.model.renderAttached(this, tessellator, worldSource, tilePos, activeState.rotX, activeState.rotY, activeState.rotZ, 0, 0, 0, false, cullFaces, overrideTexture); } diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererItem.java b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererItem.java index 62cdf9781..19e2afc00 100644 --- a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererItem.java +++ b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererItem.java @@ -1,7 +1,9 @@ package net.minecraft.client.render.entity; import net.minecraft.client.option.GameSettings; +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.EntityItem; import org.jetbrains.annotations.NotNull; import net.minecraft.client.render.item.model.ItemModelDispatcher; @@ -17,19 +19,26 @@ public class EntityRendererItem extends EntityRenderer { this.shadowOpacity = 0.75F; } + static float getDespawnFadeAlpha(final @NotNull EntityItem entity, final float partialTick) { + return EntityItem.getDespawnFadeAlpha(entity.age, entity.lifetime, partialTick); + } + public void render(@NotNull TessellatorGeneral tessellator, final @NotNull EntityItem entity, final double x, final double y, final double z, final float yaw, final float partialTick) { - int prime = ((entity.lifetime * 3)/4); - if (entity.lifetime >= 0 && (entity.age + partialTick) > prime) { - int pastPrime = entity.age - prime; - double toDeath = 1 - ((pastPrime + partialTick) * 4d)/entity.lifetime; // progress of age from 75% of lifetime to 100% - if (Math.cos(((pastPrime + partialTick) * Math.PI)/ (2.5 + 5.5 * toDeath)) > 0) return; - } final ItemStack itemstack = entity.item; if (itemstack == null) { return; } + final float fadeAlpha = getDespawnFadeAlpha(entity, partialTick); + if (entity.age >= entity.lifetime && entity.lifetime >= 0 && fadeAlpha <= EntityItem.DESPAWN_ALPHA_THRESHOLD) { + return; + } Item item = itemstack.getItem(); GLRenderer.pushFrame(); + if (fadeAlpha < 1.0f) { + GLRenderer.enableState(State.BLEND); + GLRenderer.setBlendFunc(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA); + GLRenderer.setColor4f(1.0f, 1.0f, 1.0f, fadeAlpha); + } final float bobbingOffset = MathHelper.sin((entity.age + partialTick) / 10F + entity.bobOffset) * 0.1F + 0.1F; final float yw = (float) Math.toDegrees(((entity.age + partialTick) / 20F + entity.bobOffset)); byte renderCount = 1; @@ -44,6 +53,18 @@ public class EntityRendererItem extends EntityRenderer { } GLRenderer.modelM4f().translate((float) x, (float) (y + bobbingOffset), (float) z); ItemModelDispatcher.getInstance().getDispatch(item).renderItemEntity(tessellator, itemstack, GameSettings.ITEMS_3D.value, renderCount, entity.age, yw, entity.getLightIndex(partialTick), partialTick); + if (fadeAlpha < 1.0f) { + GLRenderer.setColor4f(1.0f, 1.0f, 1.0f, 1.0f); + } GLRenderer.popFrame(); } + + @Override + public void postRender(@NotNull TessellatorGeneral tessellator, @NotNull EntityItem entity, double x, double y, double z, float yaw, float partialTick) { + final float fadeAlpha = getDespawnFadeAlpha(entity, partialTick); + final float savedShadowOpacity = this.shadowOpacity; + this.shadowOpacity *= fadeAlpha; + super.postRender(tessellator, entity, x, y, z, yaw, partialTick); + this.shadowOpacity = savedShadowOpacity; + } } diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRenderer.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRenderer.java index 957ee5aad..3393df3ae 100644 --- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRenderer.java +++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRenderer.java @@ -46,12 +46,21 @@ public abstract class MobRenderer extends EntityRenderer { this.setupModels.clear(); final int maxRenderLayer = maxRenderLayer(entity); + final float renderAlpha = getRenderAlpha(entity, partialTick); + final boolean translucent = renderAlpha < 1.0f; + //should fix water/particles rendering through pigu :3 + if (translucent) { + GLRenderer.setDepthMask(false); + } for (int layer = 0; layer <= maxRenderLayer; layer++) { try { GLRenderer.pushFrame(); final StaticEntityModel model = getAndSetupModelForLayer(entity, 1f, partialTick, layer); this.setupModels.add(model); if (model != null) { + if (translucent) { + GLRenderer.setColor4f(1.0f, 1.0f, 1.0f, renderAlpha); + } model.render(); } GLRenderer.popFrame(); @@ -59,6 +68,10 @@ public abstract class MobRenderer extends EntityRenderer { LOGGER.error("Error setting up model on layer '{}' in renderer '{}'", layer, getClass().getSimpleName(), e); } } + if (translucent) { + GLRenderer.setColor4f(1.0f, 1.0f, 1.0f, 1.0f); + GLRenderer.setDepthMask(true); + } renderAdditional(tessellator, entity, partialTick); final int argb = getOverlayColor(entity, partialTick); @@ -133,6 +146,10 @@ public abstract class MobRenderer extends EntityRenderer { return baseSize; } + protected float getRenderAlpha(final @NotNull T entity, final float partialTick) { + return 1.0f; + } + protected float getLimbSwing(final @NotNull T entity, final float partialTick) { return entity.walkAnimPos - entity.walkAnimSpeed * (1.0F - partialTick); } diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPig.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPig.java index 5c85103b8..512c0b7c6 100644 --- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPig.java +++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPig.java @@ -1,20 +1,102 @@ package net.minecraft.client.render.entity; +import net.minecraft.client.Minecraft; +import net.minecraft.client.option.GameSettings; +import net.minecraft.core.block.Blocks; import net.minecraft.core.entity.animal.MobPig; +import net.minecraft.core.entity.player.Player; +import net.minecraft.core.item.ItemStack; +import net.minecraft.client.render.tessellator.TessellatorGeneral; import net.minecraft.core.util.helper.MathHelper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.joml.Vector3d; +import org.joml.Vector3dc; +import org.joml.primitives.AABBd; import org.useless.dragonfly.models.entity.BoneTransform; import org.useless.dragonfly.models.entity.StaticEntityModel; public class MobRendererPig extends MobRendererQuadruped { + @Override + protected void renderSpecials(@NotNull final TessellatorGeneral tessellator, @NotNull final MobPig entity, final double x, final double y, final double z) { + if (entity.passenger != null) { + return; + } + super.renderSpecials(tessellator, entity, x, y, z); + } + public MobRendererPig(final float shadowSize) { super(shadowSize); } + private static final float LOOK_FADE_TARGET = 0.2f; + private static final float LOOK_FADE_RATE = 16.0f; + + @Override + protected float getRenderAlpha(@NotNull final MobPig entity, final float partialTick) { + final long now = System.nanoTime(); + float dt = entity.lookFadeLastRenderNanos == 0L ? 0f : (now - entity.lookFadeLastRenderNanos) / 1_000_000_000f; + entity.lookFadeLastRenderNanos = now; + dt = MathHelper.clamp(dt, 0f, 0.1f); + + if (!isRiderLookingAtOwnPig(entity, partialTick)) { + entity.lookFadeAlpha = 1.0f; + return 1.0f; + } + + final float t = 1.0f - (float) Math.exp(-LOOK_FADE_RATE * dt); + entity.lookFadeAlpha += (LOOK_FADE_TARGET - entity.lookFadeAlpha) * t; + if (Math.abs(entity.lookFadeAlpha - LOOK_FADE_TARGET) < 0.01f) { + entity.lookFadeAlpha = LOOK_FADE_TARGET; + } + return entity.lookFadeAlpha; + } + + @Override + public float getShadowSize(@NotNull final MobPig entity) { + if (entity.lookFadeAlpha < 0.9f) { + return 0.0f; + } + return super.getShadowSize(entity); + } + + private boolean isRiderLookingAtOwnPig(@NotNull final MobPig entity, final float partialTick) { + if (GameSettings.THIRD_PERSON_VIEW.value != 0) { + return false; + } + + final Minecraft mc = Minecraft.getMinecraft(); + final Player player = mc.thePlayer; + if (player == null || entity != player.vehicle) { + return false; + } + + final ItemStack held = player.inventory.getCurrentItem(); + if (held != null && (held.itemID == Blocks.MUSHROOM_BROWN.id() || held.itemID == Blocks.MUSHROOM_RED.id())) { + return false; + } + + final Vector3dc eye = player.getPosition(partialTick, true); + final Vector3dc look = player.getViewVector(partialTick); + if (look == null) { + return false; + } + + final double reach = player.getGamemode().getEntityReachDistance() + 1.0; + final Vector3d end = new Vector3d(look).mul(reach).add(eye); + + final double offX = (entity.xo - entity.x) * (1.0 - partialTick); + final double offY = (entity.yo - entity.y) * (1.0 - partialTick); + final double offZ = (entity.zo - entity.z) * (1.0 - partialTick); + + final AABBd renderedBox = entity.bb.translate(offX, offY, offZ, new AABBd()); + return MathHelper.aabbClip(renderedBox, eye, end) != null; + } + @Override protected @Nullable StaticEntityModel getAndSetupModelForLayer(@NotNull final MobPig entity, final float brightness, final float partialTick, final int layer) { + final boolean sitting = entity.getSitting(); final StaticEntityModel model; if (layer == 1) { bindTexture("/assets/minecraft/textures/entity/saddle.png"); @@ -25,23 +107,51 @@ public class MobRendererPig extends MobRendererQuadruped { model.resetBones(); final BoneTransform head = model.getTransform("head"); - final BoneTransform leg0 = model.getTransform("leg0"); - final BoneTransform leg1 = model.getTransform("leg1"); - final BoneTransform leg2 = model.getTransform("leg2"); - final BoneTransform leg3 = model.getTransform("leg3"); - final float bodyYaw = getBodyYaw(entity, partialTick); final float headYaw = getHeadYaw(entity, partialTick) - bodyYaw; final float headPitch = getHeadPitch(entity, partialTick); - final float limbSwing = getLimbSwing(entity, partialTick); - final float limbYaw = getLimbYaw(entity, partialTick); - - head.rotX = headPitch; - head.rotY = headYaw; - leg0.rotX = MathHelper.cos(limbSwing * 0.6662F) * 1.4F * limbYaw; - leg1.rotX = MathHelper.cos(limbSwing * 0.6662F + MathHelper.PI) * 1.4F * limbYaw; - leg2.rotX = MathHelper.cos(limbSwing * 0.6662F + MathHelper.PI) * 1.4F * limbYaw; - leg3.rotX = MathHelper.cos(limbSwing * 0.6662F) * 1.4F * limbYaw; + + if (sitting) { + final BoneTransform body = model.getTransform("body"); + final BoneTransform leg0 = model.getTransform("leg0"); + final BoneTransform leg1 = model.getTransform("leg1"); + + body.rotX = -27.5 * MathHelper.DEG_TO_RAD; + body.posY = -4; + body.posZ = 1; + + leg0.rotX = -90 * MathHelper.DEG_TO_RAD; + leg0.rotY = 15 * MathHelper.DEG_TO_RAD; + leg0.posX = -1; + leg0.posY = -4; + + leg1.rotX = -90 * MathHelper.DEG_TO_RAD; + leg1.rotY = -15 * MathHelper.DEG_TO_RAD; + leg1.posX = 1; + leg1.posY = -4; + + head.posZ = 1; + head.rotX += headPitch; + head.rotY += headYaw; + + } else { + + head.rotX = headPitch; + head.rotY = headYaw; + + final BoneTransform leg0 = model.getTransform("leg0"); + final BoneTransform leg1 = model.getTransform("leg1"); + final BoneTransform leg2 = model.getTransform("leg2"); + final BoneTransform leg3 = model.getTransform("leg3"); + final float limbSwing = getLimbSwing(entity, partialTick); + final float limbYaw = getLimbYaw(entity, partialTick); + + leg0.rotX = MathHelper.cos(limbSwing * 0.6662F) * 1.4F * limbYaw; + leg1.rotX = MathHelper.cos(limbSwing * 0.6662F + MathHelper.PI) * 1.4F * limbYaw; + leg2.rotX = MathHelper.cos(limbSwing * 0.6662F + MathHelper.PI) * 1.4F * limbYaw; + leg3.rotX = MathHelper.cos(limbSwing * 0.6662F) * 1.4F * limbYaw; + + } return model; } 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 be6db2908..6ed6552e2 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 @@ -40,6 +40,14 @@ public class MobRendererPlayer extends MobRendererBipedArmored { super(0.5F); } + @Override + public float getShadowSize(final @NotNull Player entity) { + if (entity.vehicle != null) { + return 0.0f; + } + return super.getShadowSize(entity); + } + protected @NotNull StaticEntityModel getActiveModel(final @NotNull Player player, final boolean onlyArms) { var overrideModel = EntityGeometryMojangData.Cache.getPlayerModelOverride(player.uuid, onlyArms ? EntityGeometryMojangData.PlayerModelOverrideComponent.ARMS : EntityGeometryMojangData.PlayerModelOverrideComponent.MAIN); @@ -226,9 +234,20 @@ public class MobRendererPlayer extends MobRendererBipedArmored { GLRenderer.modelM4f().translate(0.0F, 0.0F, 0.125F); final float yawOff = player.yBodyRotO + (player.yBodyRot - player.yBodyRotO) * partialTick; final float bodyAngle = 5; - final double xd = MathHelper.lerp(player.xdO, player.xd, partialTick); - final double yd = Math.min(MathHelper.lerp(player.ydO, player.yd, partialTick), 0); - final double zd = MathHelper.lerp(player.zdO, player.zd, partialTick); + + final double xd; + final double yd; + final double zd; + if (player.vehicle != null) { + xd = player.x - player.xo; + yd = Math.min(player.y - player.yo, 0); + zd = player.z - player.zo; + } else { + xd = MathHelper.lerp(player.xdO, player.xd, partialTick); + yd = Math.min(MathHelper.lerp(player.ydO, player.yd, partialTick), 0); + zd = MathHelper.lerp(player.zdO, player.zd, partialTick); + } + final double vel = -1 / (3 * Math.hypot(xd, zd) + 1) + 1; final double moveAng = Math.atan2(xd, zd); final double yawRad = Math.toRadians(yawOff); diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/Particle.java b/game/client/src/main/java/net/minecraft/client/render/particle/Particle.java index 4410a5f79..870318f16 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/Particle.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/Particle.java @@ -3,6 +3,7 @@ package net.minecraft.client.render.particle; import net.minecraft.client.render.ParticleEngine; import net.minecraft.client.render.tessellator.TessellatorParticle; import net.minecraft.client.render.texture.stitcher.IconCoordinate; +import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.core.Global; import net.minecraft.core.block.Block; import net.minecraft.core.util.helper.LightIndexHelper; @@ -21,7 +22,7 @@ import java.util.concurrent.ThreadLocalRandom; */ public class Particle { protected static final Random random = new Random(); - public IconCoordinate tex; + public @Nullable IconCoordinate tex; protected float uo; protected float vo; protected int age; @@ -51,8 +52,6 @@ public class Particle { public boolean onGround = false; public boolean removed = false; - private final TilePos qPos = new TilePos(); - public @NotNull World world; /** @@ -88,33 +87,6 @@ public class Particle { this.age = 0; } - public Particle resetBase(@NotNull World world, double x, double y, double z, double xa, double ya, double za) { - this.world = world; - this.x = x; - this.y = y; - this.z = z; - this.rCol = this.gCol = this.bCol = 1.0F; - ThreadLocalRandom tlr = ThreadLocalRandom.current(); - this.xd = xa + (float) (tlr.nextDouble() * 2D - 1.0D) * 0.4F; - this.yd = ya + (float) (tlr.nextDouble() * 2D - 1.0D) * 0.4F; - this.zd = za + (float) (tlr.nextDouble() * 2D - 1.0D) * 0.4F; - float speed = (float) (tlr.nextDouble() + tlr.nextDouble() + 1.0D) * 0.15F; - float dd = MathHelper.sqrt(this.xd * this.xd + this.yd * this.yd + this.zd * this.zd); - this.xd = (this.xd / dd) * speed * 0.4D; - this.yd = (this.yd / dd) * speed * 0.4D + 0.1D; - this.zd = (this.zd / dd) * speed * 0.4D; - this.uo = random.nextFloat() * 3F; - this.vo = random.nextFloat() * 3F; - this.size = (random.nextFloat() * 0.5F + 0.5F) * 2.0F; - this.lifetime = (int) (4F / (random.nextFloat() * 0.9F + 0.1F)); - this.age = 0; - - this.removed = false; - this.noPhysics = false; - this.onGround = false; - return this; - } - public void init() { this.xo = this.x; this.yo = this.y; @@ -174,6 +146,7 @@ public class Particle { } public void move(double dx, double dy, double dz) { + class Cache { private static final @NotNull TilePos queryPos = new TilePos(); } if (this.noPhysics) { this.x += dx; this.y += dy; @@ -185,8 +158,8 @@ public class Particle { // Y-Axis if (dy != 0) { - this.qPos.set(MathHelper.floor(this.x), MathHelper.floor(this.y + dy), MathHelper.floor(this.z)); - AABBdc bb = getCollisionBox(this.qPos); + Cache.queryPos.set(MathHelper.floor(this.x), MathHelper.floor(this.y + dy), MathHelper.floor(this.z)); + AABBdc bb = getCollisionBox(Cache.queryPos); boolean collided = false; if (bb != null && this.x >= bb.minX() && this.x <= bb.maxX() && this.z >= bb.minZ() && this.z <= bb.maxZ()) { @@ -213,8 +186,8 @@ public class Particle { // X-Axis if (dx != 0) { - this.qPos.set(MathHelper.floor(this.x + dx), MathHelper.floor(this.y), MathHelper.floor(this.z)); - AABBdc bb = getCollisionBox(this.qPos); + Cache.queryPos.set(MathHelper.floor(this.x + dx), MathHelper.floor(this.y), MathHelper.floor(this.z)); + AABBdc bb = getCollisionBox(Cache.queryPos); boolean collided = false; if (bb != null && this.y >= bb.minY() && this.y <= bb.maxY() && this.z >= bb.minZ() && this.z <= bb.maxZ()) { @@ -236,8 +209,8 @@ public class Particle { // Z-Axis if (dz != 0) { - this.qPos.set(MathHelper.floor(this.x), MathHelper.floor(this.y), MathHelper.floor(this.z + dz)); - AABBdc bb = getCollisionBox(this.qPos); + Cache.queryPos.set(MathHelper.floor(this.x), MathHelper.floor(this.y), MathHelper.floor(this.z + dz)); + AABBdc bb = getCollisionBox(Cache.queryPos); boolean collided = false; if (bb != null && this.x >= bb.minX() && this.x <= bb.maxX() && this.y >= bb.minY() && this.y <= bb.maxY()) { @@ -302,18 +275,19 @@ public class Particle { } public float calcBrightness(float pt) { + class Cache { private static final @NotNull TilePos queryPos = new TilePos(); } if (Global.accessor.isFullbrightEnabled()) { return 1.0f; } - this.qPos.set( + Cache.queryPos.set( MathHelper.floor(MathHelper.lerp(this.xo, this.x, pt)), MathHelper.floor(MathHelper.lerp(this.yo, this.y, pt)), MathHelper.floor(MathHelper.lerp(this.zo, this.z, pt)) ); - if (this.world.areBlocksLoaded(this.qPos, this.qPos)) { - return this.world.getLightBrightness(this.qPos); + if (this.world.areBlocksLoaded(Cache.queryPos, Cache.queryPos)) { + return this.world.getLightBrightness(Cache.queryPos); } return 0; } @@ -323,23 +297,24 @@ public class Particle { } public byte calcLightIndex(float pt) { + class Cache { private static final @NotNull TilePos queryPos = new TilePos(); } if (Global.accessor.isFullbrightEnabled()) return LightIndexHelper.lightIndex2i(15, 15); int bX = MathHelper.floor(MathHelper.lerp(this.xo, this.x, pt)); int bY = MathHelper.floor(MathHelper.lerp(this.yo, this.y, pt)); int bZ = MathHelper.floor(MathHelper.lerp(this.zo, this.z, pt)); - if (this.world.getBlockLitInteriorSurface(this.qPos.set(bX, bY, bZ))) { + if (this.world.getBlockLitInteriorSurface(Cache.queryPos.set(bX, bY, bZ))) { byte lIdx = 0; - lIdx = LightIndexHelper.max(lIdx, this.world.getSavedLightIndex(this.qPos.set(bX, bY + 1, bZ))); - lIdx = LightIndexHelper.max(lIdx, this.world.getSavedLightIndex(this.qPos.set(bX - 1, bY, bZ))); - lIdx = LightIndexHelper.max(lIdx, this.world.getSavedLightIndex(this.qPos.set(bX + 1, bY, bZ))); - lIdx = LightIndexHelper.max(lIdx, this.world.getSavedLightIndex(this.qPos.set(bX, bY, bZ + 1))); - lIdx = LightIndexHelper.max(lIdx, this.world.getSavedLightIndex(this.qPos.set(bX, bY, bZ - 1))); + lIdx = LightIndexHelper.max(lIdx, this.world.getSavedLightIndex(Cache.queryPos.set(bX, bY + 1, bZ))); + lIdx = LightIndexHelper.max(lIdx, this.world.getSavedLightIndex(Cache.queryPos.set(bX - 1, bY, bZ))); + lIdx = LightIndexHelper.max(lIdx, this.world.getSavedLightIndex(Cache.queryPos.set(bX + 1, bY, bZ))); + lIdx = LightIndexHelper.max(lIdx, this.world.getSavedLightIndex(Cache.queryPos.set(bX, bY, bZ + 1))); + lIdx = LightIndexHelper.max(lIdx, this.world.getSavedLightIndex(Cache.queryPos.set(bX, bY, bZ - 1))); return lIdx; } - return this.world.getSavedLightIndex(this.qPos.set(bX, bY, bZ)); + return this.world.getSavedLightIndex(Cache.queryPos.set(bX, bY, bZ)); } public byte getLightIndex(float partialTick) { diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleAcidBoiling.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleAcidBoiling.java index 131c3a8a2..bcce0bc5b 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleAcidBoiling.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleAcidBoiling.java @@ -1,20 +1,14 @@ package net.minecraft.client.render.particle; -import net.minecraft.client.render.texture.stitcher.IconCoordinate; -import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.core.block.material.Materials; import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePos; -import org.jetbrains.annotations.NotNull; public class ParticleAcidBoiling extends Particle { - private float sinTimer = 0.0F; private final boolean isReversed; private final boolean needsWater; - private final TilePos qpos = new TilePos(); - private final @NotNull IconCoordinate popping = TextureRegistry.getTexture("minecraft:particle/acid_boiling_pop"); public ParticleAcidBoiling(World world, double x, double y, double z, double xa, double ya, double za, boolean needsWater) { super(world, x, y, z, xa, ya, za); @@ -22,7 +16,7 @@ public class ParticleAcidBoiling extends Particle { this.rCol = 1.0F; this.gCol = 1.0F; this.bCol = 1.0F; - this.tex = TextureRegistry.getTexture("minecraft:particle/acid_boiling"); + this.tex = ParticleTextureCache.ICON_ACID_BOILING; this.size *= random.nextFloat() * 0.7F + 0.3F; this.xd = xa * 0.2 + (Math.random() * (double) 2.0F - (double) 1.0F) * (double) 0.02F; this.yd = ya * 0.2 + (Math.random() * (double) 2.0F - (double) 1.0F) * (double) 0.02F; @@ -33,6 +27,9 @@ public class ParticleAcidBoiling extends Particle { @Override public void tick() { + class Cache { + private static final TilePos queryPos = new TilePos(); + } ++this.sinTimer; if (this.sinTimer > 100.0F) { this.sinTimer = 0.0F; @@ -43,7 +40,7 @@ public class ParticleAcidBoiling extends Particle { this.yo = this.y; this.zo = this.z; double expand = 0.05; - boolean inWater = this.world.getBlockMaterial(this.qpos.set((int) this.x, (int) this.y, (int) this.z)) == Materials.ACID; + boolean inWater = this.world.getBlockMaterial(Cache.queryPos.set((int) this.x, (int) this.y, (int) this.z)) == Materials.ACID; if (inWater) { this.yd = 0.2; this.xd = MathHelper.sin(this.sinTimer * 0.95F) / 30.0F * (float) (this.isReversed ? -1 : 1); @@ -61,7 +58,7 @@ public class ParticleAcidBoiling extends Particle { } if (this.lifetime == 6) { - this.tex = this.popping; + this.tex = ParticleTextureCache.ICON_ACID_POPPING; this.world.spawnParticle("arrowtrail", this.x, this.y, this.z, 0.0F, 0.0F, 0.0F, 1, false); } else if (this.lifetime <= 0) { this.remove(); diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleArrowGolden.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleArrowGolden.java index dc1c3086e..0896a5451 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleArrowGolden.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleArrowGolden.java @@ -1,7 +1,6 @@ package net.minecraft.client.render.particle; import net.minecraft.client.render.tessellator.TessellatorParticle; -import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.core.world.World; import org.jetbrains.annotations.NotNull; @@ -20,7 +19,7 @@ public class ParticleArrowGolden extends Particle { this.xd += xa; this.yd += ya; this.zd += za; - this.rCol = gCol = 0.8f; + this.rCol = this.gCol = 0.8f; this.bCol = (float) (Math.random() * 0.3D); this.size *= 0.75F; this.size *= scale; @@ -52,12 +51,7 @@ public class ParticleArrowGolden extends Particle { if (this.age++ >= this.lifetime) { this.remove(); } - int val = (7 - ((this.age * 8) / this.lifetime)); - if (val >= 0) { - this.tex = TextureRegistry.getTexture("minecraft:particle/puff_" + val); - } else { - this.tex = null; - } + this.tex = ParticleTextureCache.getPuffStage(this.age, this.lifetime); this.yd += 0.004D; this.move(this.xd, this.yd, this.zd); if (this.y == this.yo) { @@ -72,5 +66,4 @@ public class ParticleArrowGolden extends Particle { this.zd *= 0.7D; } } - } diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleAsh.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleAsh.java index 2ae163ce5..0f080c642 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleAsh.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleAsh.java @@ -1,6 +1,5 @@ package net.minecraft.client.render.particle; -import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.core.world.World; public class ParticleAsh extends Particle { @@ -12,6 +11,7 @@ public class ParticleAsh extends Particle { this.rCol = this.gCol = this.bCol = 0.2F + random.nextFloat() * 0.3F; this.size = random.nextFloat() * random.nextFloat() * 6F + 1.0F; this.lifetime = (int) (64 / (random.nextFloat() * 0.8D + 0.2D)) + 2; + this.tex = ParticleTextureCache.ICON_PUFF_STAGES[0]; } @Override @@ -23,7 +23,6 @@ public class ParticleAsh extends Particle { if (this.age++ >= this.lifetime) { this.remove(); } - this.tex = TextureRegistry.getTexture("minecraft:particle/puff_0"); move(this.xd, this.yd, this.zd); this.xd *= 0.9D; this.zd *= 0.9D; diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBlockBreaking.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBlockBreaking.java index 7c2fc09f4..e17638089 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBlockBreaking.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBlockBreaking.java @@ -15,24 +15,18 @@ import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; public class ParticleBlockBreaking extends Particle { - private Block block; - private Side side; + private final Block block; + private final Side side; private final @NotNull TilePos initPos = new TilePos(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE); public ParticleBlockBreaking(World world, double x, double y, double z, double xa, double ya, double za, Block block, Side side, int meta) { super(world, x, y, z, xa, ya, za); - this.reset(world, x, y, z, xa, ya, za, block, side, meta); - } - - public ParticleBlockBreaking reset(World world, double x, double y, double z, double xa, double ya, double za, Block block, Side side, int meta) { - super.resetBase(world, x, y, z, xa, ya, za); this.side = side; this.block = block; this.tex = BlockModelDispatcher.getInstance().getDispatch(block).getParticleTexture(this.side, meta); this.gravity = block.blockParticleGravity; this.rCol = this.gCol = this.bCol = 0.6F; this.size /= 2.0F; - return this; } public ParticleBlockBreaking init(@NotNull TilePosc tilePos) { @@ -63,23 +57,26 @@ public class ParticleBlockBreaking extends Particle { @Override public byte calcLightIndex(float partialTick) { + class Cache { + private static final @NotNull TilePos queryPos = new TilePos(); + private static final @NotNull TilePos blockPos = new TilePos(); + } + if (Global.accessor.isFullbrightEnabled()) return LightIndexHelper.lightIndex2i(15, 15); - TilePos blockPos = new TilePos( + Cache.blockPos.set( MathHelper.lerp(this.xo, this.x, partialTick), MathHelper.lerp(this.yo, this.y, partialTick), MathHelper.lerp(this.zo, this.z, partialTick)); byte lightIndex = 0; - if (this.world.getBlockLitInteriorSurface(blockPos) || blockPos.equals(initPos)) { - TilePos queryPos = new TilePos(); - - lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.up(queryPos))); - lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.west(queryPos))); - lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.east(queryPos))); - lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.south(queryPos))); - lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.north(queryPos))); + if (this.world.getBlockLitInteriorSurface(Cache.blockPos) || Cache.blockPos.equals(this.initPos)) { + lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(Cache.blockPos.up(Cache.queryPos))); + lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(Cache.blockPos.west(Cache.queryPos))); + lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(Cache.blockPos.east(Cache.queryPos))); + lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(Cache.blockPos.south(Cache.queryPos))); + lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(Cache.blockPos.north(Cache.queryPos))); } else { - lightIndex = this.world.getSavedLightIndex(blockPos); + lightIndex = this.world.getSavedLightIndex(Cache.blockPos); } return lightIndex; diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBubble.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBubble.java index 659823227..68516117b 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBubble.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBubble.java @@ -1,6 +1,5 @@ package net.minecraft.client.render.particle; -import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.core.block.material.Materials; import net.minecraft.core.world.Dimension; import net.minecraft.core.world.World; @@ -8,6 +7,7 @@ import net.minecraft.core.world.pos.TilePos; import org.jetbrains.annotations.NotNull; public class ParticleBubble extends Particle { + private final boolean needsWater; public ParticleBubble(World world, double x, double y, double z, double xa, double ya, double za, @NotNull Dimension dimension, boolean needsWater) { @@ -16,7 +16,7 @@ public class ParticleBubble extends Particle { this.rCol = 1.0F; this.gCol = 1.0F; this.bCol = 1.0F; - this.tex = dimension == Dimension.NETHER ? TextureRegistry.getTexture("minecraft:particle/bubble_boiling") : TextureRegistry.getTexture("minecraft:particle/bubble"); + this.tex = dimension == Dimension.NETHER ? ParticleTextureCache.ICON_BUBBLE_BOILING : ParticleTextureCache.ICON_BUBBLE; this.size = this.size * (random.nextFloat() * 0.6F + 0.2F); this.xd = xa * 0.2D + (Math.random() * 2D - 1.0D) * 0.02F; this.yd = ya * 0.2D + (Math.random() * 2D - 1.0D) * 0.02F; @@ -26,6 +26,7 @@ public class ParticleBubble extends Particle { @Override public void tick() { + class Cache { private static final @NotNull TilePos queryPos = new TilePos(); } this.cachedLightmapCoord = calcLightIndex(1f); this.xo = this.x; this.yo = this.y; @@ -35,10 +36,10 @@ public class ParticleBubble extends Particle { this.xd *= 0.85D; this.yd *= 0.85D; this.zd *= 0.85D; - if (this.needsWater && this.world.getBlockMaterial(new TilePos(this.x, this.y, this.z)) != Materials.WATER) { + if (this.lifetime-- <= 0) { remove(); } - if (this.lifetime-- <= 0) { + if (this.needsWater && this.world.getBlockMaterial(Cache.queryPos.set(this.x, this.y, this.z)) != Materials.WATER) { remove(); } } diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBubbleBoiling.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBubbleBoiling.java index 125f24332..5197e85c3 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBubbleBoiling.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleBubbleBoiling.java @@ -1,20 +1,14 @@ package net.minecraft.client.render.particle; -import net.minecraft.client.render.texture.stitcher.IconCoordinate; -import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.core.block.material.Materials; import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePos; -import org.jetbrains.annotations.NotNull; public class ParticleBubbleBoiling extends Particle { private float sinTimer = 0; - private boolean isReversed = false; + private final boolean isReversed; private final boolean needsWater; -// private final AABBd aabbd = new AABBd(); - private final TilePos qpos = new TilePos(); - private final @NotNull IconCoordinate popping = TextureRegistry.getTexture("minecraft:particle/bubble_boiling_pop"); public ParticleBubbleBoiling(World world, double x, double y, double z, double xa, double ya, double za, boolean needsWater) { super(world, x, y, z, xa, ya, za); @@ -22,7 +16,7 @@ public class ParticleBubbleBoiling extends Particle { this.rCol = 1.0F; this.gCol = 1.0F; this.bCol = 1.0F; - this.tex = TextureRegistry.getTexture("minecraft:particle/bubble_boiling"); + this.tex = ParticleTextureCache.ICON_BUBBLE_BOILING; this.size = this.size * (random.nextFloat() * 0.7F + 0.3F); this.xd = xa * 0.2D + (Math.random() * 2D - 1.0D) * 0.02F; this.yd = ya * 0.2D + (Math.random() * 2D - 1.0D) * 0.02F; @@ -34,6 +28,10 @@ public class ParticleBubbleBoiling extends Particle { @Override public void tick() { + class Cache { + private static final TilePos queryPos = new TilePos(); +// private static final AABBd aabbd = new AABBd(); + } this.sinTimer++; if (this.sinTimer > 100) { this.sinTimer = 0; @@ -43,10 +41,10 @@ public class ParticleBubbleBoiling extends Particle { this.xo = this.x; this.yo = this.y; this.zo = this.z; - final double expand = 0.05; -// this.aabbd.setMin(this.x - expand, this.y - expand, this.z - expand).setMax(this.x + expand, this.y, this.z + expand); -// boolean inWater = this.world.isAABBInMaterial(this.qpos, Materials.WATER); - boolean inWater = this.world.getBlockMaterial(this.qpos.set((int) this.x, (int) (this.y), (int) this.z)) == Materials.WATER; +// final double expand = 0.05; +// Cache.aabbd.setMin(this.x - expand, this.y - expand, this.z - expand).setMax(this.x + expand, this.y, this.z + expand); +// boolean inWater = this.world.isAABBInMaterial(Cache.qpos, Materials.WATER); + boolean inWater = this.world.getBlockMaterial(Cache.queryPos.set(this.x, this.y, this.z)) == Materials.WATER; if (inWater) { this.yd = 0.20D; @@ -63,8 +61,8 @@ public class ParticleBubbleBoiling extends Particle { this.lifetime = MathHelper.clamp(this.lifetime, 0, 8); } if (this.lifetime == 6) { - this.tex = this.popping; - world.spawnParticle("smoke", x, y, z, 0.0D, 0.0D, 0.0D, 1, false); + this.tex = ParticleTextureCache.ICON_BUBBLE_BOILING_POP; + this.world.spawnParticle("smoke", this.x, this.y, this.z, 0.0D, 0.0D, 0.0D, 1, false); } else if (this.lifetime <= 0) { remove(); } diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleExplode.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleExplode.java index e449080c7..f29a4d7d0 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleExplode.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleExplode.java @@ -1,6 +1,5 @@ package net.minecraft.client.render.particle; -import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.core.world.World; public class ParticleExplode extends Particle { @@ -23,12 +22,7 @@ public class ParticleExplode extends Particle { if (this.age++ >= this.lifetime) { this.remove(); } - int val = (7 - ((this.age * 8) / this.lifetime)); - if (val >= 0) { - this.tex = TextureRegistry.getTexture("minecraft:particle/puff_" + val); - } else { - this.tex = null; - } + this.tex = ParticleTextureCache.getPuffStage(this.age, this.lifetime); this.yd += 0.004D; move(this.xd, this.yd, this.zd); this.xd *= 0.9D; diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFirefly.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFirefly.java index 53bcb7bef..ded9c16fa 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFirefly.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFirefly.java @@ -1,8 +1,6 @@ package net.minecraft.client.render.particle; -import net.minecraft.client.render.LightmapHelper; import net.minecraft.client.render.tessellator.TessellatorParticle; -import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.client.render.tessellator.TessellatorGeneral; import net.minecraft.core.entity.animal.MobFireflyCluster; import net.minecraft.core.util.helper.LightIndexHelper; @@ -43,7 +41,7 @@ public class ParticleFirefly extends Particle { this.lifetime = (int) (24D + random.nextInt(6)); this.lifetime *= (int) scale; this.noPhysics = false; - this.tex = TextureRegistry.getTexture("minecraft:particle/firefly"); + this.tex = ParticleTextureCache.ICON_FIREFLY; if (random.nextInt(2) == 0) { this.isReversed = true; } diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFluidDrip.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFluidDrip.java index b5b6b997b..7e96784df 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFluidDrip.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleFluidDrip.java @@ -83,8 +83,9 @@ public class ParticleFluidDrip extends Particle { @Override public byte calcLightIndex(float partialTick) { + class Cache { private static final @NotNull TilePos queryPos = new TilePos(); } if (this.fullBright) { - return LightIndexHelper.lightIndex2i(this.world.getSavedLightValue(LightLayer.Sky, new TilePos(this.x, this.y, this.z)), 15); + return LightIndexHelper.lightIndex2i(this.world.getSavedLightValue(LightLayer.Sky, Cache.queryPos.set(this.x, this.y, this.z)), 15); } return super.calcLightIndex(partialTick); } diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleHeart.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleHeart.java index b7af7e7af..cb953a275 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleHeart.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleHeart.java @@ -1,7 +1,6 @@ package net.minecraft.client.render.particle; import net.minecraft.client.render.tessellator.TessellatorParticle; -import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.core.world.World; import org.jetbrains.annotations.NotNull; @@ -23,7 +22,7 @@ public class ParticleHeart extends Particle { this.oSize = this.size; this.lifetime = 16; this.noPhysics = false; - this.tex = TextureRegistry.getTexture("minecraft:particle/heart"); + this.tex = ParticleTextureCache.ICON_HEART; } @Override diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLava.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLava.java index cda09824a..5431ed214 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLava.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLava.java @@ -1,7 +1,6 @@ package net.minecraft.client.render.particle; import net.minecraft.client.render.tessellator.TessellatorParticle; -import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.core.world.World; import org.jetbrains.annotations.NotNull; @@ -19,7 +18,7 @@ public class ParticleLava extends Particle { this.oSize = this.size; this.lifetime = (int) (16D / (Math.random() * 0.8D + 0.2D)); this.noPhysics = false; - this.tex = TextureRegistry.getTexture("minecraft:particle/bubble_lava"); + this.tex = ParticleTextureCache.ICON_BUBBLE_LAVA; } @Override diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLeaf.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLeaf.java index c06799116..de44ba8fc 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLeaf.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleLeaf.java @@ -2,6 +2,7 @@ package net.minecraft.client.render.particle; import net.minecraft.client.render.block.color.BlockColorDispatcher; import net.minecraft.client.render.tessellator.TessellatorParticle; +import net.minecraft.client.render.texture.stitcher.IconCoordinate; import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.core.block.Block; import net.minecraft.core.block.BlockLogicLeavesBase; @@ -13,9 +14,10 @@ import org.jetbrains.annotations.Nullable; import org.joml.primitives.AABBdc; public class ParticleLeaf extends Particle { + private static final @NotNull IconCoordinate ICON_OAK_LEAVES = TextureRegistry.getTexture("minecraft:block/leaves/oak_fancy"); public ParticleLeaf(World world, double x, double y, double z, double xa, double ya, double za) { super(world, x, y, z, xa, ya, za); - this.tex = TextureRegistry.getTexture("minecraft:block/leaves/oak_fancy"); + this.tex = ICON_OAK_LEAVES; this.gravity = 0.125F; this.size /= 2.0F; this.lifetime *= 16; diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleNote.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleNote.java index 3f44568c7..ee1aa6c51 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleNote.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleNote.java @@ -1,8 +1,6 @@ package net.minecraft.client.render.particle; - import net.minecraft.client.render.tessellator.TessellatorParticle; -import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.world.World; import org.jetbrains.annotations.NotNull; @@ -28,7 +26,7 @@ public class ParticleNote extends Particle { this.oSize = this.size; this.lifetime = 6; this.noPhysics = false; - this.tex = TextureRegistry.getTexture("minecraft:particle/note"); + this.tex = ParticleTextureCache.ICON_NOTE; } @Override diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePickupAnimation.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePickupAnimation.java index c091499d3..51da06bcf 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePickupAnimation.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePickupAnimation.java @@ -6,6 +6,7 @@ import net.minecraft.core.entity.Entity; import net.minecraft.client.render.EntityRendererDispatcher; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePos; +import org.jetbrains.annotations.NotNull; public class ParticlePickupAnimation extends Particle { private final Entity item; @@ -25,6 +26,7 @@ public class ParticlePickupAnimation extends Particle { @Override public void renderLit(float partialTick, double xOff, double yOff, double zOff) { + class Cache { private static final @NotNull TilePos queryPos = new TilePos(); } float time = (this.life + partialTick) / this.lifeTime; time *= time; double xo = this.item.x; @@ -36,11 +38,11 @@ public class ParticlePickupAnimation extends Particle { double xx = xo + (xt - xo) * time; double yy = yo + (yt - yo) * time; double zz = zo + (zt - zo) * time; - TilePos tilePos = new TilePos(xx, yy, zz); + Cache.queryPos.set(xx, yy, zz); xx -= xOff; yy -= yOff; zz -= zOff; - GLRenderer.setLightmapCoord1i(this.item.world.getLightIndex(tilePos, 0)); + GLRenderer.setLightmapCoord1i(this.item.world.getLightIndex(Cache.queryPos, 0)); GLRenderer.setColor4f(1f, 1f, 1f, 1f); EntityRendererDispatcher.instance.renderEntityWithPosYaw(GLRenderer.getTessellator(), this.item, (float) xx, (float) yy, (float) zz, this.item.yRot, partialTick); } diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePortal.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePortal.java index f063bd052..bf7f22437 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePortal.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePortal.java @@ -1,7 +1,6 @@ package net.minecraft.client.render.particle; import net.minecraft.client.render.tessellator.TessellatorParticle; -import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.client.util.helper.Colors; import net.minecraft.core.util.helper.Color; import net.minecraft.core.world.World; @@ -30,7 +29,7 @@ public class ParticlePortal extends Particle { this.bCol *= color.getBlue() / 255f; this.lifetime = (int) (Math.random() * 10D) + 40; this.noPhysics = true; - this.tex = TextureRegistry.getTexture("minecraft:particle/puff_" + (int) (Math.random() * 8D)); + this.tex = ParticleTextureCache.ICON_PUFF_STAGES[(int) (Math.random() * ParticleTextureCache.ICON_PUFF_STAGES.length)]; } @Override diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePuffRGB.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePuffRGB.java index aed803848..da21927f2 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePuffRGB.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticlePuffRGB.java @@ -1,7 +1,6 @@ package net.minecraft.client.render.particle; import net.minecraft.client.render.tessellator.TessellatorParticle; -import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.core.enums.LightLayer; import net.minecraft.core.util.helper.LightIndexHelper; import net.minecraft.core.util.helper.MathHelper; @@ -10,7 +9,7 @@ import org.jetbrains.annotations.NotNull; public class ParticlePuffRGB extends Particle { private final float oSize; - private int brightness; + private final int brightness; public ParticlePuffRGB(World world, double x, double y, double z, float red, float green, float blue, int brightness) { this(world, x, y, z, 1.0F, red, green, blue, brightness); @@ -18,10 +17,7 @@ public class ParticlePuffRGB extends Particle { public ParticlePuffRGB(World world, double x, double y, double z, float scale, float red, float green, float blue, int brightness) { super(world, x, y, z, 0.0D, 0.0D, 0.0D); - this.brightness = -1; - if (brightness >= 0) { - this.brightness = brightness; - } + this.brightness = brightness >= 0 ? brightness : -1; this.xd *= 0.1D; this.yd *= 0.1D; this.zd *= 0.1D; @@ -39,14 +35,8 @@ public class ParticlePuffRGB extends Particle { @Override public void render(@NotNull TessellatorParticle tessellatorParticle, float partialTick) { - float l = ((this.age + partialTick) / this.lifetime) * 32F; - if (l < 0.0F) { - l = 0.0F; - } - if (l > 1.0F) { - l = 1.0F; - } - this.size = this.oSize * l; + float s = MathHelper.clamp(((this.age + partialTick) / this.lifetime) * 32F, 0, 1); + this.size = this.oSize * s; if (this.tex == null) return; int xTile = MathHelper.floor(this.x); int yTile = MathHelper.floor(this.y); @@ -63,7 +53,7 @@ public class ParticlePuffRGB extends Particle { MathHelper.lerp(this.xo, this.x, partialTick), MathHelper.lerp(this.yo, this.y, partialTick), MathHelper.lerp(this.zo, this.z, partialTick), this.size * 0.1f, - this.tex.getIconUMin() + this.tex.getIconUSize(), this.tex.getIconVMin(), this.tex.getIconUSize() , this.tex.getIconVSize()); + this.tex.getIconUMin(), this.tex.getIconVMin(), this.tex.getIconUSize(), this.tex.getIconVSize()); } @Override @@ -75,12 +65,7 @@ public class ParticlePuffRGB extends Particle { if (this.age++ >= this.lifetime) { this.remove(); } - int val = (7 - ((this.age * 8) / this.lifetime)); - if (val >= 0) { - this.tex = TextureRegistry.getTexture("minecraft:particle/puff_" + val); - } else { - this.tex = null; - } + this.tex = ParticleTextureCache.getPuffStage(this.age, this.lifetime); this.move(this.xd, this.yd, this.zd); if (this.y == this.yo) { this.xd *= 1.1D; diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleRedstoneDust.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleRedstoneDust.java index 2ba5837e9..312e74cfa 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleRedstoneDust.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleRedstoneDust.java @@ -1,8 +1,6 @@ package net.minecraft.client.render.particle; -import net.minecraft.client.render.LightmapHelper; import net.minecraft.client.render.tessellator.TessellatorParticle; -import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.client.util.helper.Colors; import net.minecraft.core.enums.LightLayer; import net.minecraft.core.util.helper.Color; @@ -86,12 +84,7 @@ public class ParticleRedstoneDust extends Particle { if (this.age++ >= this.lifetime) { this.remove(); } - int val = (7 - ((this.age * 8) / this.lifetime)); - if (val >= 0) { - this.tex = TextureRegistry.getTexture("minecraft:particle/puff_" + val); - } else { - this.tex = null; - } + this.tex = ParticleTextureCache.getPuffStage(this.age, this.lifetime); this.move(this.xd, this.yd, this.zd); if (this.y == this.yo) { this.xd *= 1.1D; diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleRubyglassLightning.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleRubyglassLightning.java index 24c67e917..d27fe6c9a 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleRubyglassLightning.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleRubyglassLightning.java @@ -9,6 +9,7 @@ import net.minecraft.client.render.renderer.State; import net.minecraft.client.render.tessellator.TessellatorGeneral; import net.minecraft.core.util.helper.LightIndexHelper; import net.minecraft.core.world.World; +import net.minecraft.core.world.pos.TilePos; import org.jetbrains.annotations.NotNull; import java.util.Random; @@ -49,6 +50,10 @@ public class ParticleRubyglassLightning extends Particle{ @Override public void renderLit(float partialTick, double camOffX, double camOffY, double camOffZ) { + class Cache { + private static final double @NotNull [] xOffs = new double[8]; + private static final double @NotNull [] zOffs = new double[8]; + } TessellatorGeneral t = GLRenderer.getTessellator(); GLRenderer.pushFrame(); GLRenderer.setLightmapCoord1i(this.cachedLightmapCoord); @@ -61,15 +66,14 @@ public class ParticleRubyglassLightning extends Particle{ GLRenderer.enableState(State.BLEND); GLRenderer.setBlendFunc(BlendFactor.SRC_ALPHA, BlendFactor.ONE); - final double @NotNull [] xOffs = new double[8]; - final double @NotNull [] zOffs = new double[8]; + double xOff = 0.0D; double zOff = 0.0D; rand.setSeed(this.seed); for (int h = 7; h >= 0; h--) { - xOffs[h] = xOff; - zOffs[h] = zOff; + Cache.xOffs[h] = xOff; + Cache.zOffs[h] = zOff; xOff += rand.nextInt(11) - 5; zOff += rand.nextInt(11) - 5; } @@ -87,8 +91,8 @@ public class ParticleRubyglassLightning extends Particle{ ht = hs - 2; } - double xo0 = xOffs[hs] - xOff; - double zo0 = zOffs[hs] - zOff; + double xo0 = Cache.xOffs[hs] - xOff; + double zo0 = Cache.zOffs[hs] - zOff; // h = segment for (int h = hs; h >= ht; h--) { diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSmoke.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSmoke.java index 0e0ab3ff5..eaea83f52 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSmoke.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSmoke.java @@ -1,7 +1,7 @@ package net.minecraft.client.render.particle; import net.minecraft.client.render.tessellator.TessellatorParticle; -import net.minecraft.client.render.texture.stitcher.TextureRegistry; +import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.world.World; import org.jetbrains.annotations.NotNull; @@ -31,14 +31,8 @@ public class ParticleSmoke extends Particle { @Override public void render(@NotNull TessellatorParticle tessellatorParticle, float partialTick) { - float l = ((this.age + partialTick) / this.lifetime) * 32F; - if (l < 0.0F) { - l = 0.0F; - } - if (l > 1.0F) { - l = 1.0F; - } - this.size = this.oSize * l; + float s = MathHelper.clamp(((this.age + partialTick) / this.lifetime) * 32F, 0, 1); + this.size = this.oSize * s; super.render(tessellatorParticle, partialTick); } @@ -50,12 +44,7 @@ public class ParticleSmoke extends Particle { if (this.age++ >= this.lifetime) { this.remove(); } - int val = (7 - ((this.age * 8) / this.lifetime)); - if (val >= 0) { - this.tex = TextureRegistry.getTexture("minecraft:particle/puff_" + val); - } else { - this.tex = null; - } + this.tex = ParticleTextureCache.getPuffStage(this.age, this.lifetime); this.yd += 0.004D; this.move(this.xd, this.yd, this.zd); if (this.y == this.yo) { diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSnowShovel.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSnowShovel.java index 20a4154d8..5777f456f 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSnowShovel.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleSnowShovel.java @@ -2,7 +2,6 @@ package net.minecraft.client.render.particle; import net.minecraft.client.render.tessellator.TessellatorParticle; -import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.core.world.World; import org.jetbrains.annotations.NotNull; @@ -51,12 +50,7 @@ public class ParticleSnowShovel extends Particle { if (this.age++ >= this.lifetime) { this.remove(); } - int val = (7 - ((this.age * 8) / this.lifetime)); - if (val >= 0) { - this.tex = TextureRegistry.getTexture("minecraft:particle/puff_" + val); - } else { - this.tex = null; - } + this.tex = ParticleTextureCache.getPuffStage(this.age, this.lifetime); this.yd -= 0.03D; this.move(this.xd, this.yd, this.zd); this.xd *= 0.99D; @@ -67,5 +61,4 @@ public class ParticleSnowShovel extends Particle { this.zd *= 0.7D; } } - } diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleTextureCache.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleTextureCache.java new file mode 100644 index 000000000..412ba1073 --- /dev/null +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleTextureCache.java @@ -0,0 +1,52 @@ +package net.minecraft.client.render.particle; + +import net.minecraft.client.render.texture.stitcher.IconCoordinate; +import net.minecraft.client.render.texture.stitcher.TextureRegistry; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class ParticleTextureCache { + // Statically prefetch icons to avoid the cost of dynamically fetching them at runtime + public static final @NotNull IconCoordinate @NotNull [] ICON_PUFF_STAGES = new IconCoordinate[] { + TextureRegistry.getTexture("minecraft:particle/puff_0"), + TextureRegistry.getTexture("minecraft:particle/puff_1"), + TextureRegistry.getTexture("minecraft:particle/puff_2"), + TextureRegistry.getTexture("minecraft:particle/puff_3"), + TextureRegistry.getTexture("minecraft:particle/puff_4"), + TextureRegistry.getTexture("minecraft:particle/puff_5"), + TextureRegistry.getTexture("minecraft:particle/puff_6"), + TextureRegistry.getTexture("minecraft:particle/puff_7"), + }; + + public static @Nullable IconCoordinate getPuffStage(int age, int lifetime) { + if (age < 0) return ICON_PUFF_STAGES[ICON_PUFF_STAGES.length - 1]; + if (age > lifetime) return null; + final int maxIndex = ICON_PUFF_STAGES.length - 1; + int val = (maxIndex - ((age * maxIndex) / lifetime)); + return ICON_PUFF_STAGES[val]; + } + + public static final @NotNull IconCoordinate @NotNull [] ICON_SPLASH_RAIN = new IconCoordinate[] { + TextureRegistry.getTexture("minecraft:particle/splash_rain_0"), + TextureRegistry.getTexture("minecraft:particle/splash_rain_1"), + TextureRegistry.getTexture("minecraft:particle/splash_rain_2"), + TextureRegistry.getTexture("minecraft:particle/splash_rain_3"), + }; + public static final @NotNull IconCoordinate @NotNull [] ICON_SPLASH_RAIN_BLOOD = new IconCoordinate[] { + TextureRegistry.getTexture("minecraft:particle/splash_rain_blood_0"), + TextureRegistry.getTexture("minecraft:particle/splash_rain_blood_1"), + TextureRegistry.getTexture("minecraft:particle/splash_rain_blood_2"), + TextureRegistry.getTexture("minecraft:particle/splash_rain_blood_3"), + }; + + public static final @NotNull IconCoordinate ICON_ACID_POPPING = TextureRegistry.getTexture("minecraft:particle/acid_boiling_pop"); + public static final @NotNull IconCoordinate ICON_ACID_BOILING = TextureRegistry.getTexture("minecraft:particle/acid_boiling"); + public static final @NotNull IconCoordinate ICON_BUBBLE = TextureRegistry.getTexture("minecraft:particle/bubble"); + public static final @NotNull IconCoordinate ICON_BUBBLE_LAVA = TextureRegistry.getTexture("minecraft:particle/bubble_lava"); + public static final @NotNull IconCoordinate ICON_BUBBLE_BOILING = TextureRegistry.getTexture("minecraft:particle/bubble_boiling"); + public static final @NotNull IconCoordinate ICON_BUBBLE_BOILING_POP = TextureRegistry.getTexture("minecraft:particle/bubble_boiling_pop"); + + public static final @NotNull IconCoordinate ICON_FIREFLY = TextureRegistry.getTexture("minecraft:particle/firefly"); + public static final @NotNull IconCoordinate ICON_HEART = TextureRegistry.getTexture("minecraft:particle/heart"); + public static final @NotNull IconCoordinate ICON_NOTE = TextureRegistry.getTexture("minecraft:particle/note"); +} diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleVentSmoke.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleVentSmoke.java index 5d0b75f4d..7f4b9229e 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleVentSmoke.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleVentSmoke.java @@ -1,7 +1,7 @@ package net.minecraft.client.render.particle; import net.minecraft.client.render.tessellator.TessellatorParticle; -import net.minecraft.client.render.texture.stitcher.TextureRegistry; +import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.world.World; import org.jetbrains.annotations.NotNull; @@ -44,20 +44,24 @@ public class ParticleVentSmoke extends Particle { @Override public void tick() { + int cX = MathHelper.floor(this.x); + int cY = MathHelper.floor(this.y); + int cZ = MathHelper.floor(this.z); + + if (cX != this.bX || cY != this.bY || cZ != this.bZ) { + this.bX = cX; + this.bY = cY; + this.bZ = cZ; + this.cachedLightmapCoord = calcLightIndex(1f); + } + this.xo = this.x; this.yo = this.y; this.zo = this.z; if (this.age++ >= this.lifetime) { this.remove(); } - int val = (14 - ((this.age * 14) / this.lifetime)); - if(val > 7) - val = 7; - if (val >= 0) { - this.tex = TextureRegistry.getTexture("minecraft:particle/puff_" + val); - } else { - this.tex = null; - } + this.tex = ParticleTextureCache.getPuffStage(this.age, this.lifetime); this.yd += 0.004D; this.move(this.xd, this.yd, this.zd); if (this.y == this.yo) { diff --git a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleWaterDrop.java b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleWaterDrop.java index 7303d06d1..7120f132e 100644 --- a/game/client/src/main/java/net/minecraft/client/render/particle/ParticleWaterDrop.java +++ b/game/client/src/main/java/net/minecraft/client/render/particle/ParticleWaterDrop.java @@ -1,6 +1,5 @@ package net.minecraft.client.render.particle; -import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.core.block.BlockLogicFluid; import net.minecraft.core.block.material.Material; import net.minecraft.core.util.helper.MathHelper; @@ -18,13 +17,14 @@ public class ParticleWaterDrop extends Particle { this.rCol = 1.0F; this.gCol = 1.0F; this.bCol = 1.0F; - this.tex = TextureRegistry.getTexture((dimension == Dimension.NETHER ? "minecraft:particle/splash_rain_blood_" : "minecraft:particle/splash_rain_") + random.nextInt(4)); + this.tex = (dimension == Dimension.NETHER ? ParticleTextureCache.ICON_SPLASH_RAIN_BLOOD : ParticleTextureCache.ICON_SPLASH_RAIN)[random.nextInt(4)]; this.gravity = 0.06F; this.lifetime = (int) (8D / (Math.random() * 0.8D + 0.2D)); } @Override public void tick() { + class Cache {private static final @NotNull TilePos queryPos = new TilePos(); } this.xo = this.x; this.yo = this.y; this.zo = this.z; @@ -43,10 +43,10 @@ public class ParticleWaterDrop extends Particle { this.xd *= 0.7D; this.zd *= 0.7D; } - TilePos tilePos = new TilePos(this.x, this.y, this.z); - Material m = this.world.getBlockMaterial(tilePos); + Cache.queryPos.set(this.x, this.y, this.z); + Material m = this.world.getBlockMaterial(Cache.queryPos); if (m.isLiquid() || m.isSolid()) { - double y0 = (MathHelper.floor(this.y) + 1) - BlockLogicFluid.getHeight(this.world.getBlockData(tilePos)); + double y0 = (MathHelper.floor(this.y) + 1) - BlockLogicFluid.getHeight(this.world.getBlockData(Cache.queryPos)); if (this.y < y0) { remove(); } diff --git a/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRendererMultiDraw.java b/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRendererMultiDraw.java index b9f29d5ec..c3eb22959 100644 --- a/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRendererMultiDraw.java +++ b/game/client/src/main/java/net/minecraft/client/render/terrain/ChunkRendererMultiDraw.java @@ -16,7 +16,6 @@ import net.minecraft.core.world.World; import net.minecraft.core.world.WorldSource; import net.minecraft.core.world.chunk.Chunk; import net.minecraft.core.world.chunk.ChunkCache; -import net.minecraft.core.world.particle.ParticleEmitterRange; import net.minecraft.core.world.pos.TilePos; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -83,14 +82,6 @@ public class ChunkRendererMultiDraw extends ChunkRenderer { for (pos.x = this.min.x; pos.x < this.max.x; pos.x++) { final @NotNull Block block = chunkCache.getBlockType(pos); - if (renderPass == 0) { - ParticleEmitterRange type = block.getLogic().getParticleEmitterRange(); - - if (type != null) { - this.getWorld().particleEmitters.add(new TilePos(pos), type); - } - } - if (!hasStartedDrawing) { hasStartedDrawing = true; TESSELLATOR.startDrawingQuads(); diff --git a/game/client/src/main/java/net/minecraft/client/util/debug/OpenGLLoggerCallback.java b/game/client/src/main/java/net/minecraft/client/util/debug/OpenGLLoggerCallback.java index 305026db1..dff1ec2ba 100644 --- a/game/client/src/main/java/net/minecraft/client/util/debug/OpenGLLoggerCallback.java +++ b/game/client/src/main/java/net/minecraft/client/util/debug/OpenGLLoggerCallback.java @@ -27,7 +27,7 @@ public class OpenGLLoggerCallback implements GLDebugMessageCallbackI { getSourceName(source), getTypeName(type), getIdName(id), - msg, new RuntimeException() + msg, new RuntimeException("") ); break; } @@ -37,7 +37,7 @@ public class OpenGLLoggerCallback implements GLDebugMessageCallbackI { getSourceName(source), getTypeName(type), getIdName(id), - msg, new RuntimeException() + msg, new RuntimeException("") ); break; } @@ -47,7 +47,7 @@ public class OpenGLLoggerCallback implements GLDebugMessageCallbackI { getSourceName(source), getTypeName(type), getIdName(id), - msg, new RuntimeException() + msg, new RuntimeException("") ); break; } diff --git a/game/client/src/main/java/net/minecraft/client/world/WorldClient.java b/game/client/src/main/java/net/minecraft/client/world/WorldClient.java index 59e45954c..d11407054 100644 --- a/game/client/src/main/java/net/minecraft/client/world/WorldClient.java +++ b/game/client/src/main/java/net/minecraft/client/world/WorldClient.java @@ -8,10 +8,12 @@ import net.minecraft.client.render.worldtype.WorldTypeFXDispatcher; import net.minecraft.client.world.chunk.provider.ChunkProviderDynamic; import net.minecraft.client.world.chunk.provider.ChunkProviderStatic; import net.minecraft.client.world.chunk.provider.ChunkProviderThreadedClient; +import net.minecraft.core.block.entity.TileEntity; import net.minecraft.core.entity.player.Player; import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.world.Dimension; import net.minecraft.core.world.World; +import net.minecraft.core.world.chunk.Chunk; import net.minecraft.core.world.chunk.ChunkLoader; import net.minecraft.core.world.chunk.provider.ChunkProvider; import net.minecraft.core.world.pos.TilePos; @@ -48,6 +50,27 @@ public class WorldClient extends World { this.mc = parent.mc; } + @Override + protected void updateTileEntities() { + final var particleRenderDistance = GameSettings.PARTICLE_RENDER_DISTANCE.value * 16; + for (int i = this.tileEntityList.size() - 1; i >= 0; i--) { + final TileEntity tileEntity = this.tileEntityList.get(i); + if (!tileEntity.isInvalid() && this.isBlockLoaded(tileEntity.tilePos)) { + tileEntity.tick(); + if (tileEntity instanceof TileEntity.AnimationTicking animated) { + final double dx = tileEntity.tilePos.x - this.mc.thePlayer.x; + final double dy = tileEntity.tilePos.y - this.mc.thePlayer.y; + final double dz = tileEntity.tilePos.z - this.mc.thePlayer.z; + animated.animationTick(particleRenderDistance, dx * dx + dy * dy + dz * dz); + } + } + if (tileEntity.isInvalid()) { + this.tileEntityList.remove(i); + this.getChunk(tileEntity.tilePos).removeTileEntity(tileEntity); + } + } + } + @Override public void setLightningFlicker(final int lightningFlicker) { this.lightningFlicker = lightningFlicker; diff --git a/game/client/src/main/java/net/minecraft/client/world/chunk/provider/ChunkProviderClient.java b/game/client/src/main/java/net/minecraft/client/world/chunk/provider/ChunkProviderClient.java index f18cc4cca..d2f6ae367 100644 --- a/game/client/src/main/java/net/minecraft/client/world/chunk/provider/ChunkProviderClient.java +++ b/game/client/src/main/java/net/minecraft/client/world/chunk/provider/ChunkProviderClient.java @@ -14,15 +14,13 @@ import org.jetbrains.annotations.Nullable; import java.util.*; public class ChunkProviderClient implements ChunkProvider { - protected static final @NotNull ChunkPos MIN_POS = new ChunkPos(Integer.MIN_VALUE, Integer.MIN_VALUE); - private final @NotNull Chunk blankChunk; private final @NotNull Map chunkMapping = new Object2ObjectOpenHashMap<>(); private final @NotNull World world; protected @NotNull Chunk lastQueriedChunk; - protected @NotNull ChunkPos lastQueriedChunkPos = MIN_POS; + protected @NotNull ChunkPos lastQueriedChunkPos = new ChunkPos(Integer.MIN_VALUE, Integer.MIN_VALUE); public ChunkProviderClient(@NotNull World world) { this.blankChunk = new EmptyChunk(world, new ChunkPos(0, 0)); @@ -51,6 +49,10 @@ public class ChunkProviderClient implements ChunkProvider { chunk.onUnload(); } this.chunkMapping.remove(chunkPos); + if (chunkPos.equals(this.lastQueriedChunkPos)) { + this.lastQueriedChunkPos.set(Integer.MIN_VALUE, Integer.MIN_VALUE); + this.lastQueriedChunk = this.blankChunk; + } } @Override diff --git a/game/client/src/main/java/org/useless/dragonfly/data/entity/mojang/EntityGeometryMojangData.java b/game/client/src/main/java/org/useless/dragonfly/data/entity/mojang/EntityGeometryMojangData.java index fbb8b25d3..cae9dc94a 100644 --- a/game/client/src/main/java/org/useless/dragonfly/data/entity/mojang/EntityGeometryMojangData.java +++ b/game/client/src/main/java/org/useless/dragonfly/data/entity/mojang/EntityGeometryMojangData.java @@ -410,6 +410,7 @@ public class EntityGeometryMojangData implements EntityModelData { } } } + } } diff --git a/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_cap.json b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_cap.json new file mode 100644 index 000000000..04f04c2a6 --- /dev/null +++ b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_cap.json @@ -0,0 +1,40 @@ +{ + "format_version": "1.21.6", + "credit": "Made with Blockbench", + "textures": { + "closed": "minecraft:block/rubyglass/conduit/closed/closed", + "closed_overlay": "minecraft:block/rubyglass/conduit/closed/closed_overlay", + "open": "minecraft:block/rubyglass/conduit/open/open", + "open_overlay": "minecraft:block/rubyglass/conduit/open/open_overlay", + "plug": "minecraft:block/rubyglass/conduit/plug/plug", + "plug_overlay": "minecraft:block/rubyglass/conduit/plug/plug_overlay", + "particle": "minecraft:block/rubyglass/conduit/closed/closed" + }, + "elements": [ + { + "name": "Conduit Casing", + "from": [0, 0, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug", "cullface": "north"}, + "east": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug", "cullface": "east"}, + "south": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug", "cullface": "south"}, + "west": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug", "cullface": "west"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#closed", "cullface": "up"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#open", "cullface": "down"} + } + }, + { + "name": "Redstone Overlay", + "from": [0, 0, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug_overlay", "cullface": "north", "tintindex": 0, "shade": false}, + "east": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug_overlay", "cullface": "east", "tintindex": 0, "shade": false}, + "south": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug_overlay", "cullface": "south", "tintindex": 0, "shade": false}, + "west": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug_overlay", "cullface": "west", "tintindex": 0, "shade": false}, + "down": {"uv": [0, 0, 16, 16], "texture": "#open_overlay", "cullface": "down", "tintindex": 0, "shade": false} + } + } + ] +} \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_cap_off.json b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_cap_off.json new file mode 100644 index 000000000..c823c86d8 --- /dev/null +++ b/game/client/src/main/resources/assets/minecraft/models/block/rubyglass/conduit/conduit_cap_off.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.21.6", + "credit": "Made with Blockbench", + "textures": { + "closed": "minecraft:block/rubyglass/conduit/closed/closed", + "closed_overlay": "minecraft:block/rubyglass/conduit/closed/closed_overlay", + "open": "minecraft:block/rubyglass/conduit/open/open", + "open_overlay": "minecraft:block/rubyglass/conduit/open/open_overlay", + "plug": "minecraft:block/rubyglass/conduit/plug/plug", + "particle": "minecraft:block/rubyglass/conduit/closed/closed" + }, + "elements": [ + { + "name": "Conduit Casing", + "from": [0, 0, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug", "cullface": "north"}, + "east": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug", "cullface": "east"}, + "south": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug", "cullface": "south"}, + "west": {"uv": [0, 0, 16, 16], "rotation": 270, "texture": "#plug", "cullface": "west"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#closed", "cullface": "up"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#open", "cullface": "down"} + } + } + ] +} \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/block/workbench.json b/game/client/src/main/resources/assets/minecraft/models/block/workbench.json index 4bf928508..8ee85a0af 100644 --- a/game/client/src/main/resources/assets/minecraft/models/block/workbench.json +++ b/game/client/src/main/resources/assets/minecraft/models/block/workbench.json @@ -3,9 +3,9 @@ "textures": { "top": "minecraft:block/workbench/top", "bottom": "minecraft:block/workbench/bottom", - "north": "minecraft:block/workbench/front", - "south": "minecraft:block/workbench/front", - "west": "minecraft:block/workbench/side", - "east": "minecraft:block/workbench/side" + "north": "minecraft:block/workbench/side", + "south": "minecraft:block/workbench/side", + "west": "minecraft:block/workbench/front", + "east": "minecraft:block/workbench/front" } } \ No newline at end of file diff --git a/game/client/src/main/resources/assets/minecraft/models/entity/pig/pig.animation.json b/game/client/src/main/resources/assets/minecraft/models/entity/pig/pig.animation.json new file mode 100644 index 000000000..40f84bd3c --- /dev/null +++ b/game/client/src/main/resources/assets/minecraft/models/entity/pig/pig.animation.json @@ -0,0 +1,25 @@ +{ + "format_version": "1.8.0", + "animations": { + "animation.pigsitting": { + "loop": true, + "bones": { + "body": { + "rotation": [-27.5, 0, 0], + "position": [0, -4, 1] + }, + "head": { + "position": [0, 0, 1] + }, + "leg0": { + "rotation": [-90, 15, 0], + "position": [-1, -4, 0] + }, + "leg1": { + "rotation": [-90, -15, 0], + "position": [1, -4, 0] + } + } + } + } +} diff --git a/game/client/src/main/resources/credits.txt b/game/client/src/main/resources/credits.txt index f8d77498e..78a297d84 100644 --- a/game/client/src/main/resources/credits.txt +++ b/game/client/src/main/resources/credits.txt @@ -8,7 +8,7 @@ Bigjango Flamarine Kirisamé Soup (@kirisoup) Martin (@sunsetsatellite) -MelonMojito (@watermelonmojito) +MelonMojito (@melon_mojito) NebulaBC Useless (@uselessbullets) @@ -72,6 +72,8 @@ LukeisStuff --Retired BTA helper --Textures --Nether update work +Lux64 +--Conduit bit packing ideas mzov4j --Log top texture adjustments --Bone shale texture diff --git a/game/core/src/main/java/net/minecraft/core/achievement/stat/StatsCounter.java b/game/core/src/main/java/net/minecraft/core/achievement/stat/StatsCounter.java index 2f903e673..d7ec1a765 100644 --- a/game/core/src/main/java/net/minecraft/core/achievement/stat/StatsCounter.java +++ b/game/core/src/main/java/net/minecraft/core/achievement/stat/StatsCounter.java @@ -115,7 +115,7 @@ public class StatsCounter { } public boolean canUnlock(Achievement achievement) { - return achievement.parent == null || isUnlocked(achievement.parent); + return achievement.parent == null || isUnlocked(achievement.parent) || isUnlocked(achievement); } public int readStat(@Nullable Stat stat) { diff --git a/game/core/src/main/java/net/minecraft/core/block/Block.java b/game/core/src/main/java/net/minecraft/core/block/Block.java index cd6a1ac78..3880df35b 100644 --- a/game/core/src/main/java/net/minecraft/core/block/Block.java +++ b/game/core/src/main/java/net/minecraft/core/block/Block.java @@ -589,8 +589,8 @@ public final class Block } @Override - public boolean isEquivalent(final @NotNull World world, final @NotNull TilePosc thisPos, final @NotNull TilePosc thatPos) { - return this.logic.isEquivalent(world, thisPos, thatPos); + public boolean isEquivalent(final @NotNull WorldSource world, final @NotNull TilePosc thisPos, final @NotNull TilePosc thatPos, final @NotNull Block thatBlock) { + return this.logic.isEquivalent(world, thisPos, thatPos, thatBlock); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockInterface.java b/game/core/src/main/java/net/minecraft/core/block/BlockInterface.java index 241264472..a259c11c0 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockInterface.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockInterface.java @@ -390,7 +390,11 @@ interface BlockInterface { return this.isClimbable(world, new TilePos(x, y, z)); } - boolean isEquivalent(final @NotNull World world, final @NotNull TilePosc thisPos, final @NotNull TilePosc thatPos); + boolean isEquivalent(final @NotNull WorldSource world, final @NotNull TilePosc thisPos, final @NotNull TilePosc thatPos, final @NotNull Block thatBlock); + + default boolean isEquivalent(final @NotNull WorldSource world, final @NotNull TilePosc thisPos, final @NotNull TilePosc thatPos) { + return this.isEquivalent(world, thisPos, thatPos, world.getBlockType(thatPos)); + } @Deprecated default boolean isEquivalent(final @NotNull World world, final int thisX, final int thisY, final int thisZ, final int thatX, final int thatY, final int thatZ) { diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java index 668fdc792..e46945dd1 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java @@ -28,7 +28,6 @@ import net.minecraft.core.util.phys.BoundingVolume; import net.minecraft.core.util.phys.HitResult; import net.minecraft.core.world.World; import net.minecraft.core.world.WorldSource; -import net.minecraft.core.world.particle.ParticleEmitterRange; import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -211,18 +210,12 @@ public class BlockLogic implements BlockInterface, IItemConvertible { @Override public void onPlacedByWorld(final @NotNull World world, final @NotNull TilePosc tilePos) { - ParticleEmitterRange t = this.getParticleEmitterRange(); - if (t != null) { - world.particleEmitters.add(tilePos, t); - } + } @Override public void onRemoved(final @NotNull World world, final @NotNull TilePosc tilePos, final int data) { - ParticleEmitterRange t = this.getParticleEmitterRange(); - if (t != null) { - world.particleEmitters.remove(tilePos); - } + } @Override @@ -244,11 +237,6 @@ public class BlockLogic implements BlockInterface, IItemConvertible { @Override public void onPlacedByMob(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side, final @NotNull Mob mob, final double xHit, final double yHit) { this.onPlacedOnSide(world, tilePos, side, xHit, yHit); - - ParticleEmitterRange t = this.getParticleEmitterRange(); - if (t != null) { - world.particleEmitters.add(tilePos, t); - } } @Override @@ -514,54 +502,84 @@ public class BlockLogic implements BlockInterface, IItemConvertible { return false; } - /** - * Metadata compared by the matcher. Override to ignore orientation while keeping visual state (e.g. powered). - */ - protected int getMatcherEquivalenceData(final int data) { - return data; + @Override + public boolean isEquivalent(final @NotNull WorldSource world, final @NotNull TilePosc thisPos, final @NotNull TilePosc thatPos, final @NotNull Block thatBlock) { + return + this.isEquivalentBlockForMatcher(thatBlock) && + this.isEquivalentDataForMatcher(world, thisPos, thatPos) && + this.isEquivalentEntityForMatcher(world, thisPos, thatPos); } - /** - * Whether another block counts as the same type for matcher comparison (e.g. on/off variants). - */ - protected boolean isSameBlockForMatcher(final @NotNull Block other) { - return this.block == other; + // prevents accidental mis-impl + @Override + public final boolean isEquivalent(final @NotNull WorldSource world, final @NotNull TilePosc thisPos, final @NotNull TilePosc thatPos) { + return BlockInterface.super.isEquivalent(world, thisPos, thatPos); } - public record MatcherSnapshot(@NotNull Block block, int meta, @NotNull BlockLogic logic) {} - - /** - * Resolves the block/meta/logic at this position for matcher comparison. - *

- * The default implementation returns the block actually stored in the world. Blocks - * that visually stand in for another block (e.g. the moving piston, which carries - * its real contents in the tile entity) should override this to delegate to that block. - */ - public @NotNull MatcherSnapshot resolveForMatcher(final @NotNull World world, final @NotNull TilePosc tilePos) { - final @NotNull Block block = world.getBlockType(tilePos); - return new MatcherSnapshot(block, world.getBlockData(tilePos), block.getLogic()); + protected boolean isEquivalentBlockForMatcher(final @NotNull Block other) { + return this.block == other; } - public static @NotNull MatcherSnapshot resolveMatcherBlock(final @NotNull World world, final @NotNull TilePosc tilePos) { - return world.getBlockType(tilePos).getLogic().resolveForMatcher(world, tilePos); + protected final boolean isEquivalentDataForMatcher( + @NotNull WorldSource world, @NotNull TilePosc thisPos, @NotNull TilePosc thatPos + ) { + return this.matcherDataEquivImpl == null || this.matcherDataEquivImpl.isEquivalentDataForMatcherImpl( + world.getBlockData(thisPos), + world.getBlockData(thatPos) + ); } - public static boolean areBlocksEquivalentForMatcher( - final @NotNull World world, - final @NotNull TilePosc posA, - final @NotNull TilePosc posB + protected final boolean isEquivalentEntityForMatcher( + @NotNull WorldSource world, @NotNull TilePosc thisPos, @NotNull TilePosc thatPos ) { - final @NotNull MatcherSnapshot a = resolveMatcherBlock(world, posA); - final @NotNull MatcherSnapshot b = resolveMatcherBlock(world, posB); - if (!a.logic().isSameBlockForMatcher(b.block()) || !b.logic().isSameBlockForMatcher(a.block())) { - return false; + if (this.matcherEntityEquivImpl == null) return true; + + final TileEntity a, b; + if (this.matcherEntityEquivImpl.isEntityRequiredForMatching()) { + a = world.getTileEntity(thisPos); + if (a == null) return false; + + final Class entityClass = this.matcherEntityEquivImpl.getEntityEquivalencyClass(); + if (!entityClass.isInstance(a)) return false; + + b = world.getTileEntity(thatPos); + if (b == null || !entityClass.isInstance(b)) return false; + } + else { + a = world.getTileEntity(thisPos); + b = world.getTileEntity(thatPos); } - return a.logic().getMatcherEquivalenceData(a.meta()) == b.logic().getMatcherEquivalenceData(b.meta()); + return this.matcherEntityEquivImpl.isEquivalentEntityForMatcherImpl(a, b); } - @Override - public boolean isEquivalent(final @NotNull World world, final @NotNull TilePosc thisPos, final @NotNull TilePosc thatPos) { - return areBlocksEquivalentForMatcher(world, thisPos, thatPos); + private final @Nullable MatcherDataEquivalency matcherDataEquivImpl = + (this instanceof MatcherDataEquivalency impl) ? impl : null; + + public interface MatcherDataEquivalency { + default boolean isEquivalentDataForMatcherImpl(final int thisData, final int thatData) { + return thisData == thatData; + } + + public interface Masked extends MatcherDataEquivalency { + int getMatcherDataEquivalencyMask(); + + @Override + default boolean isEquivalentDataForMatcherImpl(int thisData, int thatData) { + final int mask = getMatcherDataEquivalencyMask(); + return (thisData & mask) == (thatData & mask); + } + } + } + + @SuppressWarnings("unchecked") + private final @Nullable MatcherEntityEquivalency matcherEntityEquivImpl = + (this instanceof MatcherEntityEquivalency impl) ? (MatcherEntityEquivalency)impl : null; + + public interface MatcherEntityEquivalency { + default boolean isEntityRequiredForMatching() { return true; } + @NotNull Class getEntityEquivalencyClass(); + + boolean isEquivalentEntityForMatcherImpl(final TE thisEntity, final TE thatEntity); } @Override @@ -578,8 +596,4 @@ public class BlockLogic implements BlockInterface, IItemConvertible { public @NotNull ItemStack getDefaultStack() { return this.block.getDefaultStack(); } - - public @Nullable ParticleEmitterRange getParticleEmitterRange() { - return null; // null by default, 16 block radius - } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicActivator.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicActivator.java index c82bba4ed..9779a578f 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicActivator.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicActivator.java @@ -24,12 +24,14 @@ import java.util.Random; import static net.minecraft.core.block.BlockLogicConduit.packEventConduitData; public class BlockLogicActivator - extends BlockLogicVeryRotatable { + extends BlockLogicVeryRotatable + implements BlockLogic.MatcherDataEquivalency.Masked +{ public static final int MASK_POWERED = 0b0000_1000; @Override - protected int getMatcherEquivalenceData(final int data) { - return data & MASK_POWERED; + public int getMatcherDataEquivalencyMask() { + return MASK_POWERED; } public BlockLogicActivator(final @NotNull Block block) { diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicAir.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicAir.java index f381b4741..f8fe18d53 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicAir.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicAir.java @@ -121,9 +121,4 @@ public class BlockLogicAir public int getPistonPushReaction(@NotNull World world, @NotNull TilePosc tilePos) { return Material.PISTON_DESTROY_ON_PUSH; } - - @Override - public boolean isEquivalent(@NotNull World world, @NotNull TilePosc thisPos, @NotNull TilePosc thatPos) { - return false; - } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicAxisAligned.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicAxisAligned.java index 6c4214482..ec2265d18 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicAxisAligned.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicAxisAligned.java @@ -17,11 +17,6 @@ public class BlockLogicAxisAligned super(block, material); } - @Override - protected int getMatcherEquivalenceData(final int data) { - return data & ~MASK_DIRECTION; - } - @Override public void onPlacedByMob(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side, final @NotNull Mob mob, final double xHit, final double yHit) { final @NotNull Axis axis = mob.getPlacementDirection(side, PlacementMode.SIDE).axis(); @@ -47,5 +42,4 @@ public class BlockLogicAxisAligned if (meta == 1) return Axis.Z; return Axis.Y; } - } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBasket.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBasket.java index 980dada5f..121397c0a 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBasket.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBasket.java @@ -26,7 +26,10 @@ import org.jetbrains.annotations.Nullable; import java.util.Objects; -public class BlockLogicBasket extends BlockLogic { +public class BlockLogicBasket +extends BlockLogic +implements BlockLogic.MatcherEntityEquivalency +{ protected BlockLogicBasket(final @NotNull Block block, final @NotNull Material material) { super(block, material); block.withEntity(TileEntityBasket::new); @@ -86,12 +89,14 @@ public class BlockLogicBasket extends BlockLogic { } @Override - public boolean isEquivalent(@NotNull World world, @NotNull TilePosc thisPos, @NotNull TilePosc thatPos) { - assert world.getBlockType(thisPos) == this.block; - if (world.getBlockType(thatPos) != this.block) return false; - if (!(world.getTileEntity(thisPos) instanceof TileEntityBasket thisBasket) || - !(world.getTileEntity(thatPos) instanceof TileEntityBasket thatBasket)) - return false; + public @NotNull Class getEntityEquivalencyClass() { + return TileEntityBasket.class; + } + + @Override + public boolean isEquivalentEntityForMatcherImpl( + @NotNull TileEntityBasket thisBasket, @NotNull TileEntityBasket thatBasket + ) { return getFillLevel(thisBasket) == getFillLevel(thatBasket); } 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 4289fa091..45c1bdaea 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 @@ -25,7 +25,8 @@ import java.util.Objects; public class BlockLogicBed extends BlockLogic - implements ISupportable { + implements ISupportable, BlockLogic.MatcherDataEquivalency.Masked +{ public BlockLogicBed(final @NotNull Block block) { super(block, Materials.WOOD); @@ -33,8 +34,8 @@ public class BlockLogicBed } @Override - protected int getMatcherEquivalenceData(final int data) { - return data & ~(DIRECTION.mask | IS_OCCUPIED.mask); + public int getMatcherDataEquivalencyMask() { + return ~(DIRECTION.mask | IS_OCCUPIED.mask); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicButton.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicButton.java index 63d149c3f..ae0603624 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicButton.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicButton.java @@ -26,7 +26,7 @@ import java.util.Random; public class BlockLogicButton extends BlockLogic - implements IPaintable, ISupportable { + implements IPaintable, ISupportable, BlockLogic.MatcherDataEquivalency.Masked { public static final int MASK_POWERED = 0b0000_1000; public static final int MASK_DIRECTION = 0b0000_0111; public static final int SIDE_WEST = 1; @@ -42,8 +42,8 @@ public class BlockLogicButton } @Override - protected int getMatcherEquivalenceData(final int data) { - return data & MASK_POWERED; + public int getMatcherDataEquivalencyMask() { + return ~MASK_DIRECTION; } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCactus.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCactus.java index 0c8daee2f..cbd627b8b 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCactus.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCactus.java @@ -144,9 +144,4 @@ public class BlockLogicCactus } return true; } - - @Override - protected int getMatcherEquivalenceData(int data) { - return 0; - } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicChest.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicChest.java index 8c9255995..a2205ce9b 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicChest.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicChest.java @@ -19,18 +19,20 @@ import java.util.Objects; public class BlockLogicChest extends BlockLogic - implements IPaintable { + implements IPaintable, BlockLogic.MatcherDataEquivalency { public BlockLogicChest(final @NotNull Block block, final @NotNull Material material) { super(block, material); block.withEntity(TileEntityChest::new); } @Override - protected int getMatcherEquivalenceData(int data) { - data &= ~directionBits; + public boolean isEquivalentDataForMatcherImpl(int thisData, int thatData) { + final int mask1 = ~(directionBits | typeBits); + if ((thisData & mask1) != (thatData & mask1)) return false; + assert Type.SINGLE.ordinal() == 0; - if ((data & typeBits) != 0) data |= typeBits; - return data; + // would be easier if we use 0b01 and 0b11 instead of 0b01 and 0b10 + return ((thisData & typeBits) == 0) == ((thatData & typeBits) == 0); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicConduit.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicConduit.java index cb86b616d..ba134cfca 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicConduit.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicConduit.java @@ -1,11 +1,13 @@ package net.minecraft.core.block; import net.minecraft.core.block.material.Material; +import net.minecraft.core.current.util.BlockState; +import net.minecraft.core.block.piston.BlockLogicPistonBase; +import net.minecraft.core.block.piston.BlockLogicPistonHead; +import net.minecraft.core.block.piston.PistonCommon; import net.minecraft.core.entity.Entity; import net.minecraft.core.entity.Mob; import net.minecraft.core.entity.player.Player; -import net.minecraft.core.item.ItemStack; -import net.minecraft.core.item.Items; import net.minecraft.core.sound.SoundCategory; import net.minecraft.core.util.helper.Direction; import net.minecraft.core.util.helper.Side; @@ -17,12 +19,13 @@ import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.lang.reflect.Array; import java.util.ArrayList; import java.util.List; import java.util.Random; -public class BlockLogicConduit extends BlockLogic { +public class BlockLogicConduit extends BlockLogic + implements BlockLogic.MatcherDataEquivalency +{ public static final Side[][] STATE_TABLE = { {}, // 0 @@ -37,14 +40,51 @@ public class BlockLogicConduit extends BlockLogic { {Side.NORTH, Side.WEST}, {Side.NORTH, Side.EAST}, // 12-13 {Side.SOUTH, Side.WEST}, {Side.SOUTH, Side.EAST} // 14-15 }; - private static final int PROPAGATION_LENGTH = 15; public static final int STATE_COUNT = 16; - public static final int STATE_MASK = 0b1111; public static final int POWER_MASK = 0b1111; public static final int POWER_SHIFT = 4; + private static final Side[][] CAP_SIDES = { + {Side.BOTTOM}, // 0 + {Side.TOP}, // 1 + {Side.NORTH}, // 2 + {Side.SOUTH}, // 3 + {Side.WEST}, // 4 + {Side.EAST} // 5 + }; + public static final int CAP_POWERED = 0b1000; + public static final int CAP_SIDE_MASK = 0b0111; + public static final int INERT_MARKER = 0b1111; + + // Connection priorities (higher takes priority). + private static int pc = -1; + private static final int CONNECT_NONE = pc++; + private static final int CONNECT_RAIL_POWERED = pc++; + private static final int CONNECT_NOTEBLOCK = pc++; + private static final int CONNECT_SPIKES = pc++; + private static final int CONNECT_DISPENSER = pc++; + private static final int CONNECT_PISTON = pc++; + private static final int CONNECT_ACTIVATOR = pc++; + private static final int CONNECT_BUTTON = pc++; + private static final int CONNECT_LEVER = pc++; + private static final int CONNECT_TORCH = pc++; + private static final int CONNECT_REDSTONE_LANTERN = pc++; + private static final int CONNECT_REDSTONE_BLOCK = pc++; + private static final int CONNECT_MOTION_SENSOR = pc++; + private static final int CONNECT_MATCHER = pc++; + private static final int CONNECT_TIMER = pc++; + private static final int CONNECT_REPEATER = pc++; + private static final int CONNECT_REDSTONE_DUST = pc++; + private static final int CONNECT_CONDUIT = pc++; + + // Shape categories for matcher equivalence + private static final int SHAPE_CLOSED = 0; + private static final int SHAPE_CAPPED = 1; + private static final int SHAPE_STRAIGHT = 2; + private static final int SHAPE_CORNER = 3; + public BlockLogicConduit(@NotNull Block block, @NotNull Material material) { super(block, material); } @@ -62,16 +102,10 @@ public class BlockLogicConduit extends BlockLogic { @Override public void animationTick(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Random rand) { - int data = world.getBlockData(tilePos); + int power = getPower(world, tilePos); - if (data == 15 << POWER_SHIFT) { - return; - } - - int strength = (data >> POWER_SHIFT) & POWER_MASK; - - if (strength > 0) { - world.playBlockEvent(tilePos, LevelListener.EVENT_CONDUIT_SURFACE_PARTICLES, packEventConduitData(Side.NONE, strength)); + if (power > 0) { + world.playBlockEvent(tilePos, LevelListener.EVENT_CONDUIT_SURFACE_PARTICLES, packEventConduitData(null, power)); } } @@ -87,7 +121,7 @@ public class BlockLogicConduit extends BlockLogic { @Override public boolean suffocatesEntities(@NotNull WorldSource source, @NotNull TilePosc tilePos, @NotNull Class entityClass) { - return true; + return true; } @Override @@ -96,14 +130,14 @@ public class BlockLogicConduit extends BlockLogic { @Override public void onNeighborChanged(final @NotNull World world, final @NotNull TilePosc cTilePos, final @NotNull Block block) { if (world.isClientSide) return; - world.getConduitHandler().onConduitUpdated(cTilePos); + world.getWireHandler().onWireUpdated(cTilePos); } @Override public void onPlacedByWorld(@NotNull World world, @NotNull TilePosc tilePos) { super.onPlacedByWorld(world, tilePos); if (!world.isClientSide) { - world.getConduitHandler().onConduitAdded(tilePos); + world.getWireHandler().onWireAdded(tilePos); } } @@ -111,37 +145,13 @@ public class BlockLogicConduit extends BlockLogic { public void onRemoved(@NotNull World world, @NotNull TilePosc tilePos, int data) { super.onRemoved(world, tilePos, data); if (!world.isClientSide) { - world.getConduitHandler().onConduitRemoved(tilePos, data); + world.getWireHandler().onWireRemoved(tilePos, new BlockState(this.block, data)); } } // TODO: onMoved and onFlung - /** - * Defines the placement and routing behavior of the conduit when placed into the world by an entity. - *

- * This method handles three distinct placement modes: - *

    - *
  • Rotation Lock: Absolute override. Forces the conduit to place as a straight pipe aligned - * with the player's active rotation lock direction.
  • - *
  • Sneaking (Manual Placement): Bypasses auto-connection. If placed against a closed conduit port, - * it will force that port open and connect to it. Otherwise, defaults to routing a connection from the - * clicked block face toward the placing entity.
  • - *
  • Standard (Auto-connection): Scans adjacent blocks for valid, open conduit ports to link up with.
  • - *
- *
  • 1 Valid Neighbor: Routes from the neighbor toward the entity.
  • - *
  • 2 Valid Neighbors: Creates a straight or corner connection linking both neighbors.
  • - *
  • 3+ Valid Neighbors: Defaults to routing from the block placed against toward the entity.
  • - * - * - * - * @param world World the block is being placed in. - * @param cTilePos The position where this new conduit is being placed. - * @param sidePlacedOnto The face of the existing block that the entity clicked against to place this block. - * @param mob The mob placing the block. - * @param xHit The X coordinate of the cursor hit on the block face. - * @param yHit The Y coordinate of the cursor hit on the block face. - */ + // Javadocs were out of date for placement and interaction and I can't be bothered to rewrite them @Override public void onPlacedByMob(final @NotNull World world, final @NotNull TilePosc cTilePos, final @NotNull Side sidePlacedOnto, final @NotNull Mob mob, final double xHit, final double yHit) { Side sideFacingPlayer = Direction.getLockable(mob).opposite().side(); @@ -149,84 +159,50 @@ public class BlockLogicConduit extends BlockLogic { int stateToPlaceAs = 0; - if (mob instanceof Player player) { - if (player.rotationLock != null) { - Side lockSide = player.rotationLock.side(); - stateToPlaceAs = getStateFromTwoSides(lockSide, lockSide.opposite()); - } - } - - if (stateToPlaceAs == 0 && mob.isSneaking()) { - boolean openedClosedFace = false; + if (mob.isSneaking()) { TilePos clickedPos = new TilePos(cTilePos.x() + sideClickedAgainst.offsetX(), cTilePos.y() + sideClickedAgainst.offsetY(), cTilePos.z() + sideClickedAgainst.offsetZ()); if (world.getBlockType(clickedPos) == this.block) { int clickedData = world.getBlockData(clickedPos); - if (!isSideOpen(clickedData, sidePlacedOnto)) { - int clickedState = clickedData & STATE_MASK; - int clickedStrength = (clickedData >> POWER_SHIFT) & POWER_MASK; - int newClickedState = getNextState(clickedState, sidePlacedOnto); + if (!isInert(clickedData) && !isSideOpen(clickedData, sidePlacedOnto)) { + int newClickedData = getNextDataForFace(world, clickedPos, clickedData, sidePlacedOnto); - if (newClickedState != clickedState) { - world.setBlockDataNotify(clickedPos, (clickedStrength << POWER_SHIFT) | newClickedState); + if (newClickedData != clickedData) { + world.setBlockDataNotify(clickedPos, newClickedData); this.onNeighborChanged(world, clickedPos, this.block); - openedClosedFace = true; } } } - if (openedClosedFace) { - stateToPlaceAs = getStateFromTwoSides(sideClickedAgainst, sideClickedAgainst.opposite()); - } else { - if (sideClickedAgainst != sideFacingPlayer && sideFacingPlayer != Side.NONE) { - stateToPlaceAs = getStateFromTwoSides(sideClickedAgainst, sideFacingPlayer); - } else { - stateToPlaceAs = getStateFromTwoSides(sideClickedAgainst, sideClickedAgainst.opposite()); - } - } + stateToPlaceAs = connectTowardPlayer(sideClickedAgainst, sideFacingPlayer); } - else if (stateToPlaceAs == 0) { - List validSides = new ArrayList<>(); - - for (Side side : Side.values()) { - TilePos nTilePos = new TilePos(cTilePos.x() + side.offsetX(), cTilePos.y() + side.offsetY(), cTilePos.z() + side.offsetZ()); - - if (world.getBlockType(nTilePos) == this.block) { - int nData = world.getBlockData(nTilePos); - - if (isSideOpen(nData, side.opposite())) { - validSides.add(side); - } + else { + final int[] priorities = new int[Side.sides.length]; + List validNeighbors = new ArrayList<>(); + + for (Side side : Side.sides) { + int priority = connectionPriority(world, cTilePos, side); + priorities[side.id] = priority; + if (priority > CONNECT_NONE) { + validNeighbors.add(side); } } - int numOfValidSides = validSides.size(); - - if (numOfValidSides == 1) { - Side autoConnectedSide = validSides.get(0); - - if (sideFacingPlayer != autoConnectedSide && sideFacingPlayer != Side.NONE) { - stateToPlaceAs = getStateFromTwoSides(autoConnectedSide, sideFacingPlayer); - } else { - stateToPlaceAs = getStateFromTwoSides(autoConnectedSide, autoConnectedSide.opposite()); - } - } else if (numOfValidSides == 2) { - stateToPlaceAs = getStateFromTwoSides(validSides.get(0), validSides.get(1)); - } else if (numOfValidSides > 2) { - TilePos nTilePos = new TilePos(cTilePos).add(sideClickedAgainst); - - boolean isMatchingNeighbor = world.getBlockType(nTilePos) == this.block; - boolean isNeighborSideOpen = isSideOpen(world.getBlockData(nTilePos), sidePlacedOnto); - - if (isMatchingNeighbor && isNeighborSideOpen) { - if (sideFacingPlayer != sideClickedAgainst && sideFacingPlayer != Side.NONE) { - stateToPlaceAs = getStateFromTwoSides(sideClickedAgainst, sideFacingPlayer); - } else { - stateToPlaceAs = getStateFromTwoSides(sideClickedAgainst, sideClickedAgainst.opposite()); + if (validNeighbors.size() == 1) { + stateToPlaceAs = connectTowardPlayer(validNeighbors.get(0), sideFacingPlayer); + } else if (validNeighbors.size() >= 2) { + validNeighbors.sort((side1, side2) -> { + if (priorities[side1.id] != priorities[side2.id]) { + return Integer.compare(priorities[side2.id], priorities[side1.id]); } - } + int rank1 = tiebreakRank(side1, sideClickedAgainst, sideFacingPlayer); + int rank2 = tiebreakRank(side2, sideClickedAgainst, sideFacingPlayer); + if (rank1 != rank2) return Integer.compare(rank1, rank2); + return Integer.compare(side1.id, side2.id); + }); + stateToPlaceAs = getStateFromTwoSides(validNeighbors.get(0), validNeighbors.get(1)); } } @@ -237,30 +213,6 @@ public class BlockLogicConduit extends BlockLogic { } - /** - * Handles right-click interactions with an existing conduit in the world. - *

    - * This method controls the manual toggling of conduit connection ports. The interaction succeeds - * and toggles the port state under the following conditions: - *

      - *
    • The player is holding nothing (empty hand).
    • - *
    • The player is holding another conduit, but clicks on a closed port.
    • - *
    - *

    - * If the player is holding a different block/item, or holding a conduit and clicks an open port, - * this method yields the interaction to allow standard block placement or item usage. - *

    - * Successful interactions will update the block state, trigger neighbor updates, play activation - * sound effects, and spawn visual port particles. - * @param world The world containing the block. - * @param cTilePos The position of the conduit being interacted with. - * @param player The player interacting with the block. - * @param side The specific face of the conduit that was clicked (can be null if interacted via indirect means). - * @param xHit The precise X coordinate of the cursor hit on the block face. - * @param yHit The precise Y coordinate of the cursor hit on the block face. - * @return {@code true} if the interaction was consumed (port toggled); {@code false} if the interaction - * should pass through to default item/block placement logic. - */ @Override public boolean onInteracted(final @NotNull World world, final @NotNull TilePosc cTilePos, final @NotNull Player player, final @Nullable Side side, final double xHit, final double yHit) { if(side == null) return false; @@ -274,52 +226,63 @@ public class BlockLogicConduit extends BlockLogic { int cData = world.getBlockData(cTilePos); int cState = cData & STATE_MASK; - int cStrength = (cData >> POWER_SHIFT) & POWER_MASK; - if (holdingNothing && player.isSneaking() && cState == 0) { - if (cStrength == 0) { - world.setBlockDataNotify(cTilePos, (15 << POWER_SHIFT)); + if (holdingNothing && player.isSneaking() && cState == 0 && !isCap(cData)) { + int inertValue = getUpperNibble(cData); + if (inertValue == 0) { + world.setBlockDataNotify(cTilePos, (INERT_MARKER << POWER_SHIFT)); world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, cTilePos.x(), cTilePos.y(), cTilePos.z(), "random.fizz", 0.5f, 2.6f + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.8f); world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, cTilePos.x(), cTilePos.y(), cTilePos.z(), "tile.activator.use", 1, 1.2f); world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, cTilePos.x(), cTilePos.y(), cTilePos.z(), "note.hat", 0.7f, 0.4f); - } else if (cStrength == 15) { + return true; + } else if (inertValue == INERT_MARKER) { world.setBlockDataNotify(cTilePos, 0); world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, cTilePos.x(), cTilePos.y(), cTilePos.z(), "tile.activator.use", 1, 1.2f); world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, cTilePos.x(), cTilePos.y(), cTilePos.z(), "note.hat", 0.7f, 0.4f); + return true; } - return true; } - if (holdingConduit && isSideOpen(cData, side)) { + if (isInert(cData)) { return false; } - int nextState = getNextState(cState, side); + Side[] openSides = getOpenSides(cData); + boolean clickedSideOpen = isSideOpen(cData, side); - if (nextState != cState) { - int newStrength = cStrength; + if (holdingConduit && clickedSideOpen && world.isAirBlock(new TilePos(cTilePos).add(side))) { + return false; + } - if (nextState == 0 || (cState == 0 && cStrength == 15)) { - newStrength = 0; + int nextData; + if (clickedSideOpen) { + if (openSides.length <= 1) { + nextData = 0; + } else { + Side newSide = (openSides[0] == side) ? openSides[1] : openSides[0]; + nextData = makeCap(newSide, false); } + } else { + nextData = getNextDataForFace(world, cTilePos, cData, side); + } - world.setBlockDataNotify(cTilePos, (newStrength << POWER_SHIFT) | nextState); - onNeighborChanged(world, cTilePos, this.block); + if (nextData == cData) { + return false; + } - world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, cTilePos.x(), cTilePos.y(), cTilePos.z(), "tile.activator.use", 1, 1.2f); - world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, cTilePos.x(), cTilePos.y(), cTilePos.z(), "note.hat", 0.7f, 0.4f); - world.playBlockEvent(cTilePos, LevelListener.EVENT_CONDUIT_PORT_PARTICLES, packEventConduitData(side, newStrength)); + world.setBlockDataNotify(cTilePos, nextData); + onNeighborChanged(world, cTilePos, this.block); - return true; - } + world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, cTilePos.x(), cTilePos.y(), cTilePos.z(), "tile.activator.use", 1, 1.2f); + world.playSoundEffect(player, SoundCategory.WORLD_SOUNDS, cTilePos.x(), cTilePos.y(), cTilePos.z(), "note.hat", 0.7f, 0.4f); + world.playBlockEvent(cTilePos, LevelListener.EVENT_CONDUIT_PORT_PARTICLES, packEventConduitData(side, getPower(nextData))); - return false; + return true; } - public static byte packEventConduitData(Side side, int strength) { - if (side == null) side = Side.NONE; + public static byte packEventConduitData(@Nullable Side side, int strength) { int s = Math.max(0, Math.min(PROPAGATION_LENGTH, strength)); - int sideId = side.id & 0x07; + int sideId = (side == null) ? 0 : (side.id & 0x07); return (byte) ((sideId << POWER_SHIFT) | (s & POWER_MASK)); } @@ -335,9 +298,9 @@ public class BlockLogicConduit extends BlockLogic { private static boolean isEmitting(@NotNull WorldSource world, @NotNull TilePosc tilePos, @NotNull Side side) { final int data = world.getBlockData(tilePos); - if ((data & STATE_MASK) == 0) return false; + if (getOpenSides(data).length == 0) return false; - final int currentPower = (data >>> POWER_SHIFT) & POWER_MASK; + final int currentPower = getPower(data); if (currentPower == 0) return false; final Side sideAgainst = side.opposite(); @@ -349,22 +312,45 @@ public class BlockLogicConduit extends BlockLogic { return isSideOpen(data, sideAgainst); } - private int getNextState(int currentState, @NotNull Side sideQueried) { - if (currentState == 0) { - return getStateFromTwoSides(sideQueried, sideQueried.opposite()); - } - Side[] currentSides = STATE_TABLE[currentState]; - for (Side side : currentSides) { - if (side == sideQueried) { - return 0; + public static int getNextDataForFace(@NotNull World world, @NotNull TilePosc cTilePos, int cData, @NotNull Side side) { + int nextData = getNextData(cData, side); + + Side[] openSides = getOpenSides(cData); + if (nextData == cData && (cData & STATE_MASK) != 0 && openSides.length == 2) { + int priority1 = connectionPriority(world, cTilePos, openSides[0]); + int priority2 = connectionPriority(world, cTilePos, openSides[1]); + + if (priority1 != priority2) { + Side keptSide = (priority2 > priority1) ? openSides[1] : openSides[0]; + nextData = getStateFromTwoSides(keptSide, side); + } else { + boolean air1 = world.isAirBlock(new TilePos(cTilePos).add(openSides[0])); + boolean air2 = world.isAirBlock(new TilePos(cTilePos).add(openSides[1])); + if (air1 != air2) { + Side keptSide = air1 ? openSides[1] : openSides[0]; + nextData = getStateFromTwoSides(keptSide, side); + } } } + return nextData; + } - return currentState; + public static int getNextData(int data, @NotNull Side side) { + Side[] openSides = getOpenSides(data); + for (Side s : openSides) { + if (s == side) return data; + } + if (openSides.length == 0) { + return makeCap(side, false); + } + if (openSides.length == 1) { + return getStateFromTwoSides(openSides[0], side); + } + return data; } - private int getStateFromTwoSides(@NotNull Side s1, @NotNull Side s2) { + private static int getStateFromTwoSides(@NotNull Side s1, @NotNull Side s2) { if (s1 == s2) return 0; for (int i = 1; i < STATE_TABLE.length; i++) { @@ -380,8 +366,6 @@ public class BlockLogicConduit extends BlockLogic { return 0; } - - /** * Determines the incoming signal strength from a neighboring block on any given side of the conduit and converts it.

    * n = neighbor (ex. nTilePos = neighboring blocks TilePos)
    @@ -396,18 +380,18 @@ public class BlockLogicConduit extends BlockLogic { TilePos nTilePos = new TilePos(cTilePos.x() + side.offsetX(), cTilePos.y() + side.offsetY(), cTilePos.z() + side.offsetZ()); Block nBlockType = world.getBlockType(nTilePos); - int cStrength = (world.getBlockData(cTilePos) >> POWER_SHIFT) & POWER_MASK; + int cStrength = getPower(world.getBlockData(cTilePos)); if(nBlockType == Blocks.WIRE_REDSTONE) { int nData = world.getBlockData(nTilePos); int nStrength = nData & BlockLogicWireRedstone.MASK_POWER; - return Math.max(0, signalConverter(nStrength, false) - 1); + return Math.max(0, signalConverter(nStrength) - 1); } if (nBlockType == Blocks.CONDUIT) { int nData = world.getBlockData(nTilePos); if (isSideOpen(nData, side.opposite())) { - int nStrength = (nData >> POWER_SHIFT) & POWER_MASK; + int nStrength = getPower(nData); if (nStrength <= cStrength) return 0; @@ -431,6 +415,18 @@ public class BlockLogicConduit extends BlockLogic { } } } else { + if (nBlockType == Blocks.PUMPKIN_REDSTONE) { + Side pumpkinFace = Side.fromId(world1.getBlockData(nTilePos)); + for (Side s : Side.sides) { + if (s == pumpkinFace) continue; + TilePos queryPos = new TilePos(nTilePos.x() + s.offsetX(), nTilePos.y() + s.offsetY(), nTilePos.z() + s.offsetZ()); + Block queryBlock = world1.getBlockType(queryPos); + if (queryBlock != Blocks.WIRE_REDSTONE && queryBlock != Blocks.CONDUIT + && queryBlock.isEmittingDirectSignal(world1, queryPos, s)) { + return PROPAGATION_LENGTH; + } + } + } if (nBlockType.isEmittingSignal(world1, nTilePos, side)) { return PROPAGATION_LENGTH; } @@ -443,17 +439,6 @@ public class BlockLogicConduit extends BlockLogic { return 0; } - /** - * Determines a conduit power level output toward a given side, or 0 if that side is closed.
    - * c = conduit (ex. cStrength = this conduit Signal Strength)
    - * @param cData The metadata of the conduit. - * @param sideTowardReceiver The side of the conduit facing the block asking for power. - * @return Conduit power (0-{@link #PROPAGATION_LENGTH}) - */ - public static int getOutputPower(int cData, @NotNull Side sideTowardReceiver) { - return isSideOpen(cData, sideTowardReceiver) ? (cData >> POWER_SHIFT) & POWER_MASK : 0; - } - /** * Determines if a specific side on a conduit is open.
    * c = conduit (ex. cStrength = this conduit Signal Strength)
    @@ -462,15 +447,7 @@ public class BlockLogicConduit extends BlockLogic { * @return true if the side is open, false otherwise. */ public static boolean isSideOpen(int cData, @NotNull Side side) { - int cState = cData & STATE_MASK; - - if (cState == 0) { - return false; - } - - Side[] openSides = STATE_TABLE[cState]; - - for (Side s : openSides) { + for (Side s : getOpenSides(cData)) { if (s == side) { return true; } @@ -479,30 +456,207 @@ public class BlockLogicConduit extends BlockLogic { return false; } + private static int getUpperNibble(int data) { + return (data >> POWER_SHIFT) & POWER_MASK; + } + + private static int capSideIndex(int data) { + if ((data & STATE_MASK) != 0) return -1; + int sideBits = getUpperNibble(data) & CAP_SIDE_MASK; + return (sideBits >= 1 && sideBits <= 6) ? sideBits - 1 : -1; + } + + /** + * Raw stored power for the given data, without resolving caps or inert markers. + */ + public static int getPower(int data) { + if ((data & STATE_MASK) != 0) return getUpperNibble(data); + if (isCap(data)) return isCapPowered(data) ? 1 : 0; + return 0; + } + + /** + * Power for the conduit at the given position. + */ + public static int getPower(@NotNull WorldSource world, @NotNull TilePosc tilePos) { + int data = world.getBlockData(tilePos); + if (isCap(data)) { + if (!isCapPowered(data)) return 0; + int signal = getAndConvertNeighborSignal(world, tilePos, getCapSide(data)); + return signal > 0 ? signal : PROPAGATION_LENGTH; + } + if (isInert(data)) return PROPAGATION_LENGTH; + return getPower(data); + } + + public static boolean isInert(int data) { + return (data & STATE_MASK) == 0 && getUpperNibble(data) == INERT_MARKER; + } + + public static int makeCap(@NotNull Side side, boolean powered) { + int nibble = (powered ? CAP_POWERED : 0) | (side.id + 1); + return (nibble << POWER_SHIFT); + } + + public static @NotNull Side getCapSide(int data) { + return Side.fromId(capSideIndex(data)); + } + + public static boolean isCapPowered(int data) { + return (getUpperNibble(data) & CAP_POWERED) != 0; + } + + public static boolean isCap(int data) { + return capSideIndex(data) >= 0; + } + + public static int withPower(int data, int newPower) { + int state = data & STATE_MASK; + if (state != 0) { + int p = Math.max(0, Math.min(POWER_MASK, newPower)); + return (p << POWER_SHIFT) | state; + } + if (isCap(data)) { + return makeCap(getCapSide(data), newPower > 0); + } + return data; + } + + private static int connectTowardPlayer(@NotNull Side anchor, @NotNull Side sideFacingPlayer) { + if (anchor == sideFacingPlayer) { + return makeCap(anchor, false); + } + return getStateFromTwoSides(anchor, sideFacingPlayer); + } + + private static int connectionPriority(@NotNull World world, @NotNull TilePosc cTilePos, @NotNull Side side) { + TilePos nTilePos = new TilePos(cTilePos.x() + side.offsetX(), cTilePos.y() + side.offsetY(), cTilePos.z() + side.offsetZ()); + Block nBlock = world.getBlockType(nTilePos); + int nData = world.getBlockData(nTilePos); + var logic = nBlock.getLogic(); + Side against = side.opposite(); + + // TODO should probably make connections handled per block rather then by the conduit itself. + // Held off for now as the exact same issue occurs in redstone dust, and should be handled together. + + if (nBlock == Blocks.CONDUIT) { + if (isInert(nData)) return CONNECT_NONE; + return isSideOpen(nData, against) ? CONNECT_CONDUIT : CONNECT_NONE; + } + if (logic instanceof BlockLogicPistonHead) { + return CONNECT_NONE; + } + if (logic instanceof BlockLogicPistonBase) { + Side head = Direction.fromId(PistonCommon.DIRECTION.get(nData)).side(); + return head == against ? CONNECT_NONE : CONNECT_PISTON; + } + if (logic instanceof BlockLogicActivator) { + Side face = BlockLogicVeryRotatable.metaToDirection(nData).side(); + return face == against ? CONNECT_NONE : CONNECT_ACTIVATOR; + } + if (logic instanceof BlockLogicDispenser) { + Side face = BlockLogicVeryRotatable.metaToDirection(nData).side(); + return face == against ? CONNECT_NONE : CONNECT_DISPENSER; + } + if (logic instanceof BlockLogicMotionSensor) { + Side face = BlockLogicVeryRotatable.metaToDirection(nData).side(); + return face == against ? CONNECT_NONE : CONNECT_MOTION_SENSOR; + } + if (nBlock == Blocks.WIRE_REDSTONE) { + return CONNECT_REDSTONE_DUST; + } + if (logic instanceof BlockLogicPumpkinRedstone) { + Side face = BlockLogicVeryRotatable.metaToDirection(nData).side(); + return face == against ? CONNECT_REDSTONE_LANTERN : CONNECT_NONE; + } + if (nBlock == Blocks.BLOCK_REDSTONE) { + return CONNECT_REDSTONE_BLOCK; + } + if (logic instanceof BlockLogicRepeater) { + Side axis = BlockLogicRepeater.getSideFromMeta(nData); + return (side == axis || side == axis.opposite()) ? CONNECT_REPEATER : CONNECT_NONE; + } + if (logic instanceof BlockLogicTimer) { + Side axis = BlockLogicTimer.getSideFromMeta(nData); + return (side == axis || side == axis.opposite()) ? CONNECT_TIMER : CONNECT_NONE; + } + if (nBlock == Blocks.MATCHER || nBlock == Blocks.MATCHER_ACTIVE) { + return (side.axis() != BlockLogicAxisAligned.metaToAxis(nData)) ? CONNECT_MATCHER : CONNECT_NONE; + } + if (logic instanceof BlockLogicTorchRedstone) { + return CONNECT_TORCH; + } + if (logic instanceof BlockLogicLever) { + return CONNECT_LEVER; + } + if (logic instanceof BlockLogicButton) { + return CONNECT_BUTTON; + } + if (nBlock == Blocks.SPIKES) { + return CONNECT_SPIKES; + } + if (nBlock == Blocks.NOTEBLOCK) { + return CONNECT_NOTEBLOCK; + } + if (nBlock == Blocks.RAIL_POWERED) { + return CONNECT_RAIL_POWERED; + } + return CONNECT_NONE; + } + + private static int tiebreakRank(@NotNull Side side, @NotNull Side sideClickedAgainst, @NotNull Side sideFacingPlayer) { + if (side == sideClickedAgainst) return 0; + if (side == sideFacingPlayer) return 1; + return 2; + } + /** * Determines which sides on a given conduit are open.
    * c = conduit (ex. cStrength = this conduit Signal Strength)
    * @param cData The metadata of the conduit to check. - * @return a {@link Side} {@link Array} of sides that are open. + * @return a {@link Side} array of the sides that are open. */ public static Side[] getOpenSides(int cData){ - return STATE_TABLE[cData & STATE_MASK]; + int state = cData & STATE_MASK; + if (state != 0) return STATE_TABLE[state]; + + int capSide = capSideIndex(cData); + return capSide >= 0 ? CAP_SIDES[capSide] : STATE_TABLE[0]; } /** * Converts signal strengths between redstone and conduit. * @param strength The signal strength to convert - * @param conduitToRedstone Whether to convert conduit -> redstone or vice versa * @return The converted signal strength */ - public static int signalConverter(int strength, boolean conduitToRedstone) { + public static int signalConverter(int strength) { return Math.max(0, Math.min(PROPAGATION_LENGTH, strength)); } @Override - protected int getMatcherEquivalenceData(int data) { - if ((data & STATE_MASK) == 0) assert getOpenSides(data).length == 0; - else data |= STATE_MASK; - return data; + public boolean isEquivalent(@NotNull WorldSource world, @NotNull TilePosc thisPos, @NotNull TilePosc thatPos, @NotNull Block thatBlock) { + if (!super.isEquivalent(world, thisPos, thatPos, thatBlock)) return false; + if (isCap(world.getBlockData(thisPos))) { + return getPower(world, thisPos) == getPower(world, thatPos); + } + return true; + } + + @Override + public boolean isEquivalentDataForMatcherImpl(int thisData, int thatData) { + return getMatcherShape(thisData) == getMatcherShape(thatData) + && getMatcherPower(thisData) == getMatcherPower(thatData); + } + private static int getMatcherShape(int data) { + int state = data & STATE_MASK; + if (state != 0) { + return (state <= 3) ? SHAPE_STRAIGHT : SHAPE_CORNER; + } + return isCap(data) ? SHAPE_CAPPED : SHAPE_CLOSED; + } + + private static int getMatcherPower(int data) { + if (isInert(data)) return PROPAGATION_LENGTH; + return getPower(data); } } \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCropsPumpkin.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCropsPumpkin.java index e042cb912..df84bf46c 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCropsPumpkin.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCropsPumpkin.java @@ -3,7 +3,7 @@ package net.minecraft.core.block; import net.minecraft.core.block.entity.TileEntity; import net.minecraft.core.entity.player.Player; import net.minecraft.core.enums.EnumDropCause; -import net.minecraft.core.item.IBonemealable; +// import net.minecraft.core.item.IBonemealable; import net.minecraft.core.item.ItemStack; import net.minecraft.core.item.Items; import net.minecraft.core.util.helper.Side; @@ -20,7 +20,7 @@ import java.util.Random; public class BlockLogicCropsPumpkin extends BlockLogicFlower - implements IBonemealable { + /*implements IBonemealable*/ { public BlockLogicCropsPumpkin(final @NotNull Block block) { super(block); } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCropsWheat.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCropsWheat.java index 9b2fdfbd6..1b6e4ac01 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCropsWheat.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCropsWheat.java @@ -5,7 +5,7 @@ import java.util.Random; import net.minecraft.core.block.entity.TileEntity; import net.minecraft.core.entity.player.Player; import net.minecraft.core.enums.EnumDropCause; -import net.minecraft.core.item.IBonemealable; +// import net.minecraft.core.item.IBonemealable; import net.minecraft.core.item.Item; import net.minecraft.core.item.Items; import net.minecraft.core.item.ItemStack; @@ -16,7 +16,7 @@ import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class BlockLogicCropsWheat extends BlockLogicFlower implements IBonemealable { +public class BlockLogicCropsWheat extends BlockLogicFlower /*implements IBonemealable*/ { public static final int MASK_GROWTH = 0b0000_0111; public static final int MAX_GROWTH_STATE = 7; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java index 55e368fea..faacd85aa 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java @@ -27,11 +27,6 @@ import org.joml.Vector3dc; public class BlockLogicDispenser extends BlockLogicVeryRotatable { public static final int MASK_POWERED = 0b0000_1000; - @Override - protected int getMatcherEquivalenceData(final int data) { - return data & MASK_POWERED; - } - public BlockLogicDispenser(final @NotNull Block block) { super(block, Materials.STONE); block.withEntity(TileEntityDispenser::new); 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 b9a16b98a..46dd64bbc 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 @@ -30,7 +30,7 @@ import java.util.function.Supplier; // TODO this needs massive refactor public class BlockLogicDoor extends BlockLogic - implements IPaintable { + implements IPaintable/*, BlockLogic.MatcherDataEquivalency*/ { public static final int MASK_ROTATION = 0b0000_0011; public static final int MASK_OPENED = 0b0000_0100; public static final int MASK_HINGE = 0b0000_1000; // 0 == left hinge; 1 == right hinge @@ -52,24 +52,16 @@ public class BlockLogicDoor } } - @Override - protected boolean isSameBlockForMatcher(final @NotNull Block other) { - if (!(other.getLogic() instanceof BlockLogicDoor otherDoor)) { - return false; - } - return otherDoor.isTop == this.isTop; - } - - @Override - protected int getMatcherEquivalenceData(int data) { - final int MASK_NON_COLOR = MASK_OPENED | MASK_HINGE | MASK_ROTATION; - assert (MASK_HINGE >>> 1) == MASK_OPENED; - int data2 = data | ((data & MASK_HINGE) >>> 1); // flips the opened bit if hinge bit is set - data &= ~MASK_NON_COLOR; - data2 &= MASK_NON_COLOR; - data |= data2; - return data; - } + // this doesn't actually work that well + // @Override + // public boolean isEquivalentDataForMatcherImpl(int thisData, int thatData) { + // // assert (MASK_HINGE >>> 1) == MASK_OPENED; + // thisData &= MASK_OPENED | MASK_HINGE; + // thatData &= MASK_OPENED | MASK_HINGE; + // thisData ^= thisData >>> 1; + // thatData ^= thatData >>> 1; + // return (thisData & MASK_OPENED) == (thatData & MASK_OPENED); + // } @Override public void onPlacedOnSide(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side, final double xHit, final double yHit) { 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 7e8b34df3..930c49f81 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 @@ -19,6 +19,15 @@ public class BlockLogicDoorPainted super(block, material, isTop, false, null); } + public static final int MASK_COLOR = 0xF0; + + // @Override + // public boolean isEquivalentDataForMatcherImpl(int thisData, int thatData) { + // return + // (thisData & MASK_COLOR) == (thatData & MASK_COLOR) && + // super.isEquivalentDataForMatcherImpl(thisData, thatData); + // } + @Override public @NotNull ItemStack @Nullable [] getBreakResult(final @NotNull World world, final @NotNull EnumDropCause dropCause, final int data, final @Nullable TileEntity tileEntity) { return new ItemStack[]{new ItemStack(Items.DOOR_OAK_PAINTED, 1, 15 - (data >> 4 & 0xF))}; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicEdible.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicEdible.java index 3da2eec24..76a72897d 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicEdible.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicEdible.java @@ -19,7 +19,8 @@ import org.jetbrains.annotations.Nullable; import java.util.function.Supplier; public abstract class BlockLogicEdible - extends BlockLogic { + extends BlockLogic + implements BlockLogic.MatcherDataEquivalency { private final @NotNull Supplier<@NotNull Item> itemSupplier; public int maxBites; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFarmland.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFarmland.java index 237696e82..2d3f67923 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFarmland.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFarmland.java @@ -28,7 +28,7 @@ import java.util.Random; public class BlockLogicFarmland extends BlockLogic - implements IBonemealable { + implements IBonemealable, BlockLogic.MatcherDataEquivalency { public static final int MASK_FERTILIZED = 0b0001_0000; public static final int MASK_WET = 0b0000_1111; @@ -246,8 +246,8 @@ public class BlockLogicFarmland } @Override - protected int getMatcherEquivalenceData(int data) { - if ((data & MASK_WET) != 0) data |= MASK_WET; - return data; + public boolean isEquivalentDataForMatcherImpl(int thisData, int thatData) { + if ((thisData & ~MASK_WET) != (thatData & ~MASK_WET)) return false; + return ((thisData & MASK_WET) == 0) == ((thatData & MASK_WET) == 0); } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceGate.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceGate.java index 11dad2ba7..d25f78220 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceGate.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceGate.java @@ -23,7 +23,7 @@ import org.joml.primitives.AABBdc; public class BlockLogicFenceGate extends BlockLogic - implements IPaintable { + implements IPaintable, BlockLogic.MatcherDataEquivalency.Masked { public static final int MASK_DIRECTION = 0b0000_0011; public static final int MASK_OPEN = 0b0000_0100; public static final int MASK_POWERED = 0b0000_1000; @@ -33,9 +33,15 @@ public class BlockLogicFenceGate } @Override - protected int getMatcherEquivalenceData(final int data) { - assert (data & (MASK_POWERED | MASK_OPEN)) != MASK_POWERED : "fence gate should be opened when powered"; - return data & ~(MASK_DIRECTION | MASK_POWERED); + public int getMatcherDataEquivalencyMask() { + return ~(MASK_DIRECTION | MASK_POWERED); + } + + @Override + public boolean isEquivalentDataForMatcherImpl(int thisData, int thatData) { + assert (thisData & (MASK_POWERED | MASK_OPEN)) != MASK_POWERED : "fence gate should be opened when powered"; + assert (thatData & (MASK_POWERED | MASK_OPEN)) != MASK_POWERED : "fence gate should be opened when powered"; + return BlockLogic.MatcherDataEquivalency.Masked.super.isEquivalentDataForMatcherImpl(thisData, thatData); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFire.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFire.java index 790404ddc..53b5267a0 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFire.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFire.java @@ -397,9 +397,4 @@ public class BlockLogicFire public void onEntityCollision(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Entity entity) { entity.activeFireBlock = this.block; } - - @Override - protected int getMatcherEquivalenceData(int data) { - return 0; - } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlag.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlag.java index a6f8badc5..67cd126d4 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlag.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlag.java @@ -22,7 +22,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.primitives.AABBdc; -public class BlockLogicFlag extends BlockLogic { +public class BlockLogicFlag extends BlockLogic + implements BlockLogic.MatcherEntityEquivalency +{ public BlockLogicFlag(@NotNull Block block, @NotNull Material material) { super(block, material); @@ -88,14 +90,14 @@ public class BlockLogicFlag extends BlockLogic { return Material.PISTON_DESTROY_ON_PUSH; } + @Override + public @NotNull Class getEntityEquivalencyClass() { + return TileEntityFlag.class; + } + // TODO: pure color comparison instead of dye index comparison @Override - public boolean isEquivalent(@NotNull World world, @NotNull TilePosc thisPos, @NotNull TilePosc thatPos) { - assert world.getBlockType(thisPos) == this.block; - if (world.getBlockType(thatPos) != this.block) return false; - if (!(world.getTileEntity(thisPos) instanceof TileEntityFlag thisFlag) || - !(world.getTileEntity(thatPos) instanceof TileEntityFlag thatFlag)) - return false; + public boolean isEquivalentEntityForMatcherImpl(@NotNull TileEntityFlag thisFlag, @NotNull TileEntityFlag thatFlag) { if (thisFlag.colorHash != thatFlag.colorHash) return false; if (thisFlag.colorHash != ~0) { if (thisFlag.flipped != thatFlag.flipped) return false; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlower.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlower.java index 0faccf85a..f3ab0af12 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlower.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlower.java @@ -22,7 +22,7 @@ import java.util.Random; public class BlockLogicFlower extends BlockLogic - implements IBonemealable { + implements IBonemealable, BlockLogic.MatcherDataEquivalency.Masked { public static final int MASK_PERMANENT = 0b1000_0000; public boolean killedByWeather = false; @@ -161,7 +161,7 @@ public class BlockLogicFlower } @Override - protected int getMatcherEquivalenceData(int data) { - return data & ~ MASK_PERMANENT; + public int getMatcherDataEquivalencyMask() { + return ~MASK_PERMANENT; } } 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 e7428b752..5ffc6f297 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 @@ -238,10 +238,12 @@ public abstract class BlockLogicFluid extends BlockLogic { } @Override - protected boolean isSameBlockForMatcher(@NotNull Block other) { + protected boolean isEquivalentBlockForMatcher(@NotNull Block other) { + if (other == this.block) return true; return other.getLogic() instanceof BlockLogicFluid fluid && fluid.material == this.material; } + public static boolean isStillEquivalentToFlowing(Block block1, Block block2) { if (block1 == null || block2 == null) return false; if (block1 == block2) return true; 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 29190bc4f..49e10c5e3 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 @@ -14,7 +14,7 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; import java.util.Arrays; import java.util.Random; -public class BlockLogicFluidFlowing extends BlockLogicFluid { +public class BlockLogicFluidFlowing extends BlockLogicFluid implements BlockLogic.MatcherDataEquivalency { int maxCount; public final @NotNull Block blockStill; @@ -83,11 +83,12 @@ public class BlockLogicFluidFlowing extends BlockLogicFluid { if (b != null) { b.dropWithCause(world, EnumDropCause.WORLD, spreadPos, world.getBlockData(spreadPos), null, null); } - if (localFlowDecay >= 8) { - world.setBlockTypeDataNotify(spreadPos, this.block, localFlowDecay); - } else { - world.setBlockTypeDataNotify(spreadPos, this.block, localFlowDecay + 8); - } + world.setBlockTypeDataNotify(spreadPos, this.block, 8); + // if (localFlowDecay >= 8) { + // world.setBlockTypeDataNotify(spreadPos, this.block, localFlowDecay); + // } else { + // world.setBlockTypeDataNotify(spreadPos, this.block, localFlowDecay + 8); + // } } else if (localFlowDecay >= 0 && (localFlowDecay == 0 || isFluidBlocking(world, tilePos.down(queryPos)))) { final int meta = (localFlowDecay < MAX_SPREAD) ? localFlowDecay + flowDecayMod diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluidStill.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluidStill.java index e4ebf706e..896b7daa7 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluidStill.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluidStill.java @@ -3,7 +3,6 @@ package net.minecraft.core.block; import java.util.Random; import net.minecraft.core.block.material.Material; -import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFullyRotatable.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFullyRotatable.java index b80fefd85..2313016d4 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFullyRotatable.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFullyRotatable.java @@ -14,11 +14,6 @@ public class BlockLogicFullyRotatable extends BlockLogic { super(block, material); } - @Override - protected int getMatcherEquivalenceData(final int data) { - return data & ~MASK_DIRECTION; - } - @Override public void onPlacedByMob(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Side side, @NotNull Mob mob, double xHit, double yHit) { final Direction direction = mob.getPlacementDirection(side).opposite(); diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicGrowthRubyglass.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicGrowthRubyglass.java index 4e6b54adb..ea739bee2 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicGrowthRubyglass.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicGrowthRubyglass.java @@ -16,7 +16,7 @@ import org.jetbrains.annotations.Nullable; import org.joml.primitives.AABBd; import org.joml.primitives.AABBdc; -public class BlockLogicGrowthRubyglass extends BlockLogic { +public class BlockLogicGrowthRubyglass extends BlockLogic implements BlockLogic.MatcherDataEquivalency.Masked { public static final int DIRECTION_MASK = 0b0000_0111; public static final int SHAPE_MASK = 0b0001_1000; @@ -226,7 +226,7 @@ public class BlockLogicGrowthRubyglass extends BlockLogic { } @Override - protected int getMatcherEquivalenceData(int data) { - return data & ~DIRECTION_MASK; + public int getMatcherDataEquivalencyMask() { + return ~DIRECTION_MASK; } } \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicJar.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicJar.java index ae7d3de80..d59f551d5 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicJar.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicJar.java @@ -18,7 +18,6 @@ import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.World; import net.minecraft.core.world.WorldSource; import net.minecraft.core.world.pos.TilePosc; -import net.minecraft.core.world.wind.WindProvider; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,7 +26,12 @@ import org.joml.primitives.AABBdc; import java.util.function.Supplier; -public class BlockLogicJar extends BlockLogic implements ISupportable { +public class BlockLogicJar extends BlockLogic +implements + ISupportable, + BlockLogic.MatcherDataEquivalency, + BlockLogic.MatcherEntityEquivalency +{ private final @NotNull Supplier<@NotNull Item> itemSupplier; @@ -137,19 +141,22 @@ public class BlockLogicJar extends BlockLogic implements ISupportable { } @Override - public boolean isEquivalent(@NotNull World world, @NotNull TilePosc thisPos, @NotNull TilePosc thatPos) { - assert world.getBlockType(thisPos) == this.block; - if (world.getBlockType(thatPos) != this.block) return false; - final int thisData, thatData; { - thisData = world.getBlockData(thisPos); - thatData = world.getBlockData(thatPos); - } - if ((thisData | thatData) == 0) return true; - if (!(world.getTileEntity(thisPos) instanceof TileEntityFlowerJar thisFlowerJar) || - !(world.getTileEntity(thatPos) instanceof TileEntityFlowerJar thatFlowerJar)) - return false; - if (thisFlowerJar.flowerInPot != thatFlowerJar.flowerInPot) return false; - if (thisFlowerJar.flowerData != thatFlowerJar.flowerData) return false; - return true; + public boolean isEntityRequiredForMatching() { + return false; + } + + @Override + public @NotNull Class getEntityEquivalencyClass() { + return TileEntityFlowerJar.class; + } + + @Override + public boolean isEquivalentEntityForMatcherImpl( + @Nullable TileEntityFlowerJar thisJar, @Nullable TileEntityFlowerJar thatJar + ) { + if (thisJar == null || thatJar == null) return thisJar == null && thatJar == null; + return + thisJar.flowerInPot == thatJar.flowerInPot && + thisJar.flowerData == thatJar.flowerData; } } \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicJarButterfly.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicJarButterfly.java index 5cba540b4..a6924d945 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicJarButterfly.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicJarButterfly.java @@ -25,7 +25,7 @@ import org.joml.primitives.AABBdc; import java.util.function.Supplier; -public class BlockLogicJarButterfly extends BlockLogic implements ISupportable { +public class BlockLogicJarButterfly extends BlockLogic implements ISupportable, BlockLogic.MatcherEntityEquivalency { public static final int MASK_HANGING = 0b0000_0001; public static final int MASK_ANGLED = 0b0000_0010; private final @NotNull Supplier<@NotNull Item> itemSupplier; @@ -152,12 +152,14 @@ public class BlockLogicJarButterfly extends BlockLogic implements ISupportable { } @Override - public boolean isEquivalent(@NotNull World world, @NotNull TilePosc thisPos, @NotNull TilePosc thatPos) { - assert world.getBlockType(thisPos) == this.block; - if (world.getBlockType(thatPos) != this.block) return false; - if (!(world.getTileEntity(thisPos) instanceof TileEntityJarButterfly thisJar) || - !(world.getTileEntity(thatPos) instanceof TileEntityJarButterfly thatJar)) - return false; - return thisJar.color.id() == thatJar.color.id(); + public @NotNull Class getEntityEquivalencyClass() { + return TileEntityJarButterfly.class; + } + + @Override + public boolean isEquivalentEntityForMatcherImpl( + @NotNull TileEntityJarButterfly thisButterfly, @NotNull TileEntityJarButterfly thatButterfly + ) { + return thisButterfly.color.id() == thatButterfly.color.id(); } } 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 b33ba3f0a..0f49116de 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 @@ -7,12 +7,17 @@ import net.minecraft.core.entity.player.Player; import net.minecraft.core.util.helper.Direction; import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.World; +import net.minecraft.core.world.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; -public class BlockLogicJukebox extends BlockLogic { +public class BlockLogicJukebox extends BlockLogic +implements + BlockLogic.MatcherDataEquivalency, + BlockLogic.MatcherEntityEquivalency +{ public BlockLogicJukebox(@NotNull Block block) { super(block, Materials.WOOD); block.withEntity(TileEntityJukebox::new); @@ -51,19 +56,36 @@ public class BlockLogicJukebox extends BlockLogic { } @Override - public boolean isEquivalent(@NotNull World world, @NotNull TilePosc thisPos, @NotNull TilePosc thatPos) { - assert world.getBlockType(thisPos) == this.block; - if (world.getBlockType(thatPos) != this.block) return false; + public boolean isEquivalent( + @NotNull WorldSource world, + @NotNull TilePosc thisPos, @NotNull TilePosc thatPos, + @NotNull Block thatBlock + ) { + if (!this.isEquivalentBlockForMatcher(thatBlock)) return false; final int thisData, thatData; { thisData = world.getBlockData(thisPos); thatData = world.getBlockData(thatPos); } if (thisData != thatData) return false; - if ((thisData | thatData) == 0) return true; + if (thatData == 0 /*&& thatData == 0*/) return true; + return this.isEquivalentEntityForMatcher(world, thisPos, thatPos); + } - if (!(world.getTileEntity(thisPos) instanceof TileEntityJukebox thisJukebox) || - !(world.getTileEntity(thatPos) instanceof TileEntityJukebox thatJukebox)) - return false; + @Override + public boolean isEntityRequiredForMatching() { + return false; + } + + @Override + public @NotNull Class getEntityEquivalencyClass() { + return TileEntityJukebox.class; + } + + @Override + public boolean isEquivalentEntityForMatcherImpl( + @Nullable TileEntityJukebox thisJukebox, @Nullable TileEntityJukebox thatJukebox + ) { + if (thisJukebox == null || thatJukebox == null) return thisJukebox == null && thatJukebox == null; return thisJukebox.record == thatJukebox.record; } } 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 1c6969c32..2f8cbeef1 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 @@ -22,11 +22,6 @@ public class BlockLogicLadder extends BlockLogic implements ISupportable { super(block, Materials.WOOD); } - @Override - protected int getMatcherEquivalenceData(final int data) { - return 0; - } - @Override public boolean isSolidRender() { return false; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLamp.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLamp.java index 2fec961c1..1d17e7402 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLamp.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLamp.java @@ -173,7 +173,7 @@ public class BlockLogicLamp extends BlockLogic implements IPainted { } @Override - protected boolean isSameBlockForMatcher(final @NotNull Block other) { + protected boolean isEquivalentBlockForMatcher(@NotNull Block other) { return other.getLogic() instanceof BlockLogicLamp lamp && this.isActive == lamp.isActive; } } \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerBase.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerBase.java index 30776c77a..f2d134527 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerBase.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerBase.java @@ -14,7 +14,7 @@ import org.jetbrains.annotations.Nullable; import org.joml.primitives.AABBd; import org.joml.primitives.AABBdc; -public abstract class BlockLogicLayerBase extends BlockLogic +public abstract class BlockLogicLayerBase extends BlockLogic implements BlockLogic.MatcherDataEquivalency { public final @Nullable Block fullBlock; public static final int MASK_HEIGHT = 0b111; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerLeaves.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerLeaves.java index 13b1d03e7..4c083affd 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerLeaves.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerLeaves.java @@ -18,7 +18,7 @@ import org.joml.primitives.AABBdc; import java.util.Random; -public class BlockLogicLayerLeaves extends BlockLogicLayerSupportable { +public class BlockLogicLayerLeaves extends BlockLogicLayerSupportable implements BlockLogic.MatcherDataEquivalency.Masked { public static final int MASK_PERMANENT = 0b1000_0000; public BlockLogicLayerLeaves(@NotNull Block block, @NotNull Block fullBlock, @NotNull Material material) { @@ -93,7 +93,7 @@ public class BlockLogicLayerLeaves extends BlockLogicLayerSupportable { } @Override - protected int getMatcherEquivalenceData(int data) { - return super.getMatcherEquivalenceData(data) & ~MASK_PERMANENT; + public int getMatcherDataEquivalencyMask() { + return ~MASK_PERMANENT; } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesBase.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesBase.java index df0b4cd1a..fea1184e5 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesBase.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesBase.java @@ -201,9 +201,4 @@ public class BlockLogicLeavesBase extends BlockLogic { public float getAmbientOcclusionStrength(@NotNull WorldSource source, @NotNull TilePosc tilePos) { return enableTreeShadowing ? 0.8f : 0.0f; } - - @Override - protected int getMatcherEquivalenceData(int data) { - return data & ~MASK_DECAY_DATA; - } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesCacao.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesCacao.java index 39f7684d8..e672a9731 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesCacao.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesCacao.java @@ -21,7 +21,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Random; -public class BlockLogicLeavesCacao extends BlockLogicLeavesBase implements IBonemealable { +public class BlockLogicLeavesCacao extends BlockLogicLeavesBase implements IBonemealable, BlockLogic.MatcherDataEquivalency.Masked { public static final int MASK_GROWTH_DATA = 0b1111_0000; public static final int MAX_GROWTH_STATE = 4; @@ -133,4 +133,9 @@ public class BlockLogicLeavesCacao extends BlockLogicLeavesBase implements IBone public static int setGrowthRate(int meta, int growthRate) { return (meta & ~MASK_GROWTH_DATA) | (growthRate << 4) & MASK_GROWTH_DATA; } + + @Override + public int getMatcherDataEquivalencyMask() { + return ~MASK_DECAY_DATA; + } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesCherryFlowering.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesCherryFlowering.java index fcd2d4395..430595cbf 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesCherryFlowering.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesCherryFlowering.java @@ -17,7 +17,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Random; -public class BlockLogicLeavesCherryFlowering extends BlockLogicLeavesCherry implements IBonemealable +public class BlockLogicLeavesCherryFlowering extends BlockLogicLeavesCherry implements IBonemealable, BlockLogic.MatcherDataEquivalency.Masked { public static final int MASK_GROWTH_DATA = 0b1111_0000; public static final int MAX_GROWTH_STATE = 1; @@ -112,4 +112,9 @@ public class BlockLogicLeavesCherryFlowering extends BlockLogicLeavesCherry impl public static int setGrowthRate(int meta, int growthRate) { return (meta & ~MASK_GROWTH_DATA) | (growthRate << 4) & MASK_GROWTH_DATA; } + + @Override + public int getMatcherDataEquivalencyMask() { + return ~MASK_DECAY_DATA; + } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLever.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLever.java index e029e54be..a1c166143 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLever.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLever.java @@ -16,14 +16,13 @@ import net.minecraft.core.util.helper.Direction; import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.World; import net.minecraft.core.world.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; -public class BlockLogicLever extends BlockLogic implements ISupportable { +public class BlockLogicLever extends BlockLogic implements ISupportable, BlockLogic.MatcherDataEquivalency.Masked { public static final int MASK_POWERED = 0b0001_0000; public static final int MASK_ROTATION = 0b0000_1111; public static final int ROTATION_EAST = 1; @@ -40,8 +39,8 @@ public class BlockLogicLever extends BlockLogic implements ISupportable { } @Override - protected int getMatcherEquivalenceData(final int data) { - return data & MASK_POWERED; + public int getMatcherDataEquivalencyMask() { + return MASK_POWERED; } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMatcher.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMatcher.java index e1066c02f..13508dc26 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMatcher.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMatcher.java @@ -11,6 +11,7 @@ import net.minecraft.core.enums.EnumDropCause; import net.minecraft.core.enums.PlacementMode; import net.minecraft.core.item.ItemStack; import net.minecraft.core.util.helper.Axis; +import net.minecraft.core.util.helper.Direction; import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.LevelListener; import net.minecraft.core.world.World; @@ -32,11 +33,6 @@ public class BlockLogicMatcher extends BlockLogicAxisAligned { this.isActive = isActive; } - @Override - protected boolean isSameBlockForMatcher(final @NotNull Block other) { - return other.getLogic() instanceof BlockLogicMatcher matcher && (this.isActive == matcher.isActive); - } - @Override public int tickDelay() { return 4; @@ -113,40 +109,45 @@ public class BlockLogicMatcher extends BlockLogicAxisAligned { } public void updateState(@NotNull World world, @NotNull TilePosc tilePos) { - Axis a = BlockLogicAxisAligned.metaToAxis(world.getBlockData(tilePos) & BlockLogicAxisAligned.MASK_DIRECTION); + final int meta = world.getBlockData(tilePos); + final Axis axis = BlockLogicAxisAligned.metaToAxis(meta & BlockLogicAxisAligned.MASK_DIRECTION); - TilePos front = new TilePos(tilePos); - TilePos back = new TilePos(tilePos); - switch (a) { - case X: - front.x += 1; - back.x -= 1; - break; - case Y: - front.y += 1; - back.y -= 1; - break; - case Z: - default: - front.z += 1; - back.z -= 1; - break; + final TilePos frontPos = new TilePos(tilePos); + final TilePos backPos = new TilePos(tilePos); + switch (axis) { + default -> { return; } + case X -> { + frontPos.x += 1; + backPos.x -= 1; + } + case Y -> { + frontPos.y += 1; + backPos.y -= 1; + } + case Z -> { + frontPos.z += 1; + backPos.z -= 1; + } } + final Block front = world.getBlockType(frontPos); + final Block back = world.getBlockType(backPos); - final @Nullable Block frontBlock = world.getBlockType(front); - final boolean backMatchesFront = frontBlock.isEquivalent(world, front, back); + final boolean isUnionImpl = + (front == back) || + front.getLogic().getClass() == back.getLogic().getClass(); + + final boolean matches = (isUnionImpl) + ? front.isEquivalent(world, frontPos, backPos, back) + : front.isEquivalent(world, frontPos, backPos, back) && back.isEquivalent(world, backPos, frontPos, front); - if (!this.isActive && backMatchesFront) { - world.setBlockTypeDataNotify(tilePos, Blocks.MATCHER_ACTIVE, world.getBlockData(tilePos)); - } else if (this.isActive && !backMatchesFront) { - world.setBlockTypeDataNotify(tilePos, Blocks.MATCHER, world.getBlockData(tilePos)); - } + if (this.isActive == matches) return; + world.setBlockTypeDataNotify(tilePos, (matches) ? Blocks.MATCHER_ACTIVE : Blocks.MATCHER, meta); } @Override public void animationTick(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Random rand) { - if (!this.isActive) {return;} + if (!this.isActive) return; world.playBlockEvent(tilePos, LevelListener.EVENT_CONDUIT_SURFACE_PARTICLES, packEventConduitData(null, 10)); } @@ -168,4 +169,14 @@ public class BlockLogicMatcher extends BlockLogicAxisAligned { return new ItemStack[]{new ItemStack(Blocks.MATCHER)}; } + public static void updateNeighboringMatchers( + final @NotNull World world, + final @NotNull TilePosc origin + ) { + final var query = new TilePos(); + for (final var dir : Direction.all) { + final var b = world.getBlockType(origin.add(dir, query)); + if (b.getLogic() instanceof BlockLogicMatcher matcher) matcher.scheduleUpdate(world, query); + } + } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMeshGold.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMeshGold.java index db9199595..9cbe60533 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMeshGold.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMeshGold.java @@ -1,6 +1,5 @@ package net.minecraft.core.block; -import net.minecraft.core.block.entity.TileEntity; import net.minecraft.core.block.entity.TileEntityMeshGold; import net.minecraft.core.entity.Entity; import net.minecraft.core.entity.EntityItem; @@ -12,7 +11,7 @@ import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class BlockLogicMeshGold extends BlockLogicMesh { +public class BlockLogicMeshGold extends BlockLogicMesh implements BlockLogic.MatcherEntityEquivalency { public BlockLogicMeshGold(@NotNull Block block) { super(block); block.withEntity(TileEntityMeshGold::new); @@ -44,15 +43,13 @@ public class BlockLogicMeshGold extends BlockLogicMesh { } @Override - public boolean isEquivalent(@NotNull World world, @NotNull TilePosc thisPos, @NotNull TilePosc thatPos) { - if (super.isEquivalent(world, thisPos, thatPos)) { - TileEntity thisEntity = world.getTileEntity(thisPos); - TileEntity otherEntity = world.getTileEntity(thatPos); - if (thisEntity instanceof TileEntityMeshGold thisMesh && otherEntity instanceof TileEntityMeshGold otherMesh) { - return stacksAreSame(thisMesh.filterItem, otherMesh.filterItem); - } - } - return false; + public @NotNull Class getEntityEquivalencyClass() { + return TileEntityMeshGold.class; + } + + @Override + public boolean isEquivalentEntityForMatcherImpl(@NotNull TileEntityMeshGold thisMesh, @NotNull TileEntityMeshGold thatMesh) { + return stacksAreSame(thisMesh.filterItem, thatMesh.filterItem); } public boolean stacksAreSame(@Nullable ItemStack a, @Nullable ItemStack b) { diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMobSpawner.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMobSpawner.java index 6f1777a07..464e5c4e3 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMobSpawner.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMobSpawner.java @@ -15,7 +15,7 @@ import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class BlockLogicMobSpawner extends BlockLogicMobSpawnerDeactivated { +public class BlockLogicMobSpawner extends BlockLogicMobSpawnerDeactivated implements BlockLogic.MatcherEntityEquivalency { public BlockLogicMobSpawner(@NotNull Block block) { super(block); @@ -102,12 +102,14 @@ public class BlockLogicMobSpawner extends BlockLogicMobSpawnerDeactivated { } @Override - public boolean isEquivalent(@NotNull World world, @NotNull TilePosc thisPos, @NotNull TilePosc thatPos) { - assert world.getBlockType(thisPos) == this.block; - if (world.getBlockType(thatPos) != this.block) return false; - if (!(world.getTileEntity(thisPos) instanceof TileEntityMobSpawner thisSpawner) || - !(world.getTileEntity(thatPos) instanceof TileEntityMobSpawner thatSpawner)) - return false; + public @NotNull Class getEntityEquivalencyClass() { + return TileEntityMobSpawner.class; + } + + @Override + public boolean isEquivalentEntityForMatcherImpl( + @NotNull TileEntityMobSpawner thisSpawner, @NotNull TileEntityMobSpawner thatSpawner + ) { final @Nullable String thisId, thatId; { thisId = thisSpawner.getMobId(); thatId = thatSpawner.getMobId(); @@ -115,5 +117,5 @@ public class BlockLogicMobSpawner extends BlockLogicMobSpawnerDeactivated { if (thisId == thatId) return true; if (thisId == null || thatId == null) return false; return thisId.equals(thatId); - } + } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicNote.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicNote.java index 83a4f2f06..b9e7533fa 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicNote.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicNote.java @@ -13,6 +13,7 @@ import net.minecraft.core.sound.SoundCategory; import net.minecraft.core.util.helper.Direction; import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.World; +import net.minecraft.core.world.WorldSource; import net.minecraft.core.block.material.Material; import net.minecraft.core.world.pos.TilePos; import net.minecraft.core.world.pos.TilePosc; @@ -20,27 +21,25 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; -public class BlockLogicNote extends BlockLogic { +public class BlockLogicNote extends BlockLogic implements BlockLogic.MatcherDataEquivalency { private static final Logger LOGGER = LogUtils.getLogger(); public static final int MASK_NOTE = 0b0011_1111; public static final int MASK_POWERED = 0b1000_0000; @Override - public boolean isEquivalent(@NotNull World world, @NotNull TilePosc thisPos, @NotNull TilePosc thatPos) { - assert world.getBlockType(thisPos) == this.block; - if (world.getBlockType(thatPos) != this.block) return false; - final int thisData, thatData; { - thisData = world.getBlockData(thisPos); - thatData = world.getBlockData(thatPos); + public boolean isEquivalent( + @NotNull WorldSource world, + @NotNull TilePosc thisPos, @NotNull TilePosc thatPos, + @NotNull Block thatBlock + ) { + if (!this.isEquivalentBlockForMatcher(thatBlock)) return false; + if (!this.isEquivalentDataForMatcher(world, thisPos, thatPos)) return false; + final @NotNull Instrument thisInstrument, thatInstrument; { + final var query = new TilePos(); + thisInstrument = Instrument.getInstrumentFromBlock(world.getBlockType(thisPos.down(query))); + thatInstrument = Instrument.getInstrumentFromBlock(world.getBlockType(thatPos.down(query))); } - if (thisData != thatData) return false; // We check note as well because it sucks otherwise - // // TODO instrument update - // final @NotNull Instrument thisInstru, thatInstru; { - // final var query = new TilePos(); - // thisInstru = Instrument.getInstrumentFromBlock(world.getBlockType(thisPos.down(query))); - // thatInstru = Instrument.getInstrumentFromBlock(world.getBlockType(thatPos.down(query))); - // } - // if (thisInstru != thatInstru) return false; // reference eq + if (thisInstrument != thatInstrument) return false; // reference eq return true; } @@ -56,10 +55,12 @@ public class BlockLogicNote extends BlockLogic { final int data = world.getBlockData(tilePos); final boolean hasSignal = world.hasNeighborSignal(tilePos); final boolean isPowered = isPowered(data); - if (isPowered == hasSignal) return; - world.setBlockData(tilePos, data ^ MASK_POWERED); - if (hasSignal) triggerNote(world, tilePos); - world.notifyBlocksOfNeighborChange(tilePos, this.block); + if (isPowered != hasSignal) { + world.setBlockData(tilePos, data ^ MASK_POWERED); + if (hasSignal) triggerNote(world, tilePos); + // world.notifyBlocksOfNeighborChange(tilePos, this.block); + } + BlockLogicMatcher.updateNeighboringMatchers(world, tilePos); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicOverlayPebbles.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicOverlayPebbles.java index abacf19c0..8380cd13d 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicOverlayPebbles.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicOverlayPebbles.java @@ -12,14 +12,13 @@ import net.minecraft.core.item.ItemStack; import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.World; 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.AABBdc; public class BlockLogicOverlayPebbles extends BlockLogic - implements ISupportable + implements ISupportable, BlockLogic.MatcherDataEquivalency { public static final int MAX_PEBBLES = 3; public static final int MASK_PEBBLE_AMOUNT = 0b0000_0011; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPlanksPainted.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPlanksPainted.java index 60d30cd09..5df791596 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPlanksPainted.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPlanksPainted.java @@ -12,7 +12,7 @@ import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class BlockLogicPlanksPainted extends BlockLogic implements IPainted +public class BlockLogicPlanksPainted extends BlockLogic implements IPainted, BlockLogic.MatcherDataEquivalency { public BlockLogicPlanksPainted(@NotNull Block block) { diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPortal.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPortal.java index f2af23610..6c3a6c0b6 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPortal.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPortal.java @@ -7,6 +7,8 @@ import net.minecraft.core.block.support.ISupport; import net.minecraft.core.block.support.PartialSupport; import net.minecraft.core.entity.Entity; import net.minecraft.core.entity.EntityItem; +import net.minecraft.core.entity.animal.MobPig; +import net.minecraft.core.entity.player.Player; import net.minecraft.core.enums.EnumDropCause; import net.minecraft.core.item.ItemStack; import net.minecraft.core.item.Items; @@ -26,7 +28,7 @@ import org.joml.primitives.AABBdc; import java.util.Random; -public class BlockLogicPortal extends BlockLogicTransparent implements IPainted { +public class BlockLogicPortal extends BlockLogicTransparent implements IPainted, BlockLogic.MatcherDataEquivalency.Masked { public static final int MAX_PORTAL_SIZE = 32; public static final int MASK_COLOR = 0b1111_0000; public static final int MASK_ROTATION = 0b0000_0001; @@ -41,8 +43,8 @@ public class BlockLogicPortal extends BlockLogicTransparent implements IPainted public final @NotNull Block portalTrigger; @Override - protected int getMatcherEquivalenceData(final int data) { - return data & ~MASK_ROTATION; + public int getMatcherDataEquivalencyMask() { + return ~(MASK_ROTATION | MASK_SOURCE); } public BlockLogicPortal(@NotNull Block block, @NotNull Dimension targetDimension, @NotNull Block portalMaterial, @NotNull Block portalTrigger) { @@ -319,7 +321,11 @@ public class BlockLogicPortal extends BlockLogicTransparent implements IPainted } } } - if (entity.vehicle == null && entity.passenger == null) { + if (entity instanceof Player ridingPlayer && ridingPlayer.vehicle instanceof MobPig) { + ridingPlayer.handlePortal(this.block.id(), getColor(world, tilePos)); + } else if (entity instanceof MobPig && entity.passenger instanceof Player riderPlayer) { + riderPlayer.handlePortal(this.block.id(), getColor(world, tilePos)); + } else if (entity.vehicle == null && entity.passenger == null) { entity.handlePortal(this.block.id(), getColor(world, tilePos)); } } 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 ddf3577e6..c90f2b9ba 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 @@ -12,7 +12,6 @@ import net.minecraft.core.util.helper.Side; import net.minecraft.core.sound.SoundCategory; import net.minecraft.core.world.World; 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; @@ -22,13 +21,19 @@ import org.joml.primitives.AABBdc; import java.util.List; import java.util.Random; -public class BlockLogicPressurePlate extends BlockLogic implements IPaintable, ISupportable { +public class BlockLogicPressurePlate extends BlockLogic +implements + IPaintable, + ISupportable, + BlockLogic.MatcherDataEquivalency.Masked +{ public static final int MASK_POWERED = 0b0000_0001; @Override - protected int getMatcherEquivalenceData(final int data) { - return data & MASK_POWERED; + public int getMatcherDataEquivalencyMask() { + return MASK_POWERED; } + public static final int MASK_SIDE = 0b0000_1110; private final @NotNull Class triggerMobClass; @@ -117,27 +122,39 @@ public class BlockLogicPressurePlate extends BlockLogic implem Direction dir = sideFromMeta(meta).direction(); boolean isSteppedOn = false; float pixel = 0.125F; - List list = switch (sideFromMeta(meta)) { + AABBdc box = switch (sideFromMeta(meta)) { case BOTTOM -> - world.getEntitiesWithinAABB(this.triggerMobClass, new AABBd(pixel, 0.0F, pixel, 1.0F - pixel, (isPressed ? pixel / 2f : pixel), 1.0F - pixel).translate(tilePos.x(), tilePos.y(), tilePos.z())); + new AABBd(pixel, 0.0F, pixel, 1.0F - pixel, (isPressed ? pixel / 2f : pixel), 1.0F - pixel).translate(tilePos.x(), tilePos.y(), tilePos.z()); case TOP -> - world.getEntitiesWithinAABB(this.triggerMobClass, new AABBd(pixel, 1f - (isPressed ? pixel / 2f : pixel), pixel, 1.0F - pixel, 1f, 1.0F - pixel).translate(tilePos.x(), tilePos.y(), tilePos.z())); + new AABBd(pixel, 1f - (isPressed ? pixel / 2f : pixel), pixel, 1.0F - pixel, 1f, 1.0F - pixel).translate(tilePos.x(), tilePos.y(), tilePos.z()); case NORTH -> - world.getEntitiesWithinAABB(this.triggerMobClass, new AABBd(pixel, pixel, 0, 1 - pixel, 1 - pixel, (isPressed ? pixel / 2f : pixel)).translate(tilePos.x(), tilePos.y(), tilePos.z())); + new AABBd(pixel, pixel, 0, 1 - pixel, 1 - pixel, (isPressed ? pixel / 2f : pixel)).translate(tilePos.x(), tilePos.y(), tilePos.z()); case SOUTH -> - world.getEntitiesWithinAABB(this.triggerMobClass, new AABBd(pixel, pixel, 1f - (isPressed ? pixel / 2f : pixel), 1 - pixel, 1 - pixel, 1).translate(tilePos.x(), tilePos.y(), tilePos.z())); + new AABBd(pixel, pixel, 1f - (isPressed ? pixel / 2f : pixel), 1 - pixel, 1 - pixel, 1).translate(tilePos.x(), tilePos.y(), tilePos.z()); case WEST -> - world.getEntitiesWithinAABB(this.triggerMobClass, new AABBd(0, pixel, pixel, (isPressed ? pixel / 2f : pixel), 1 - pixel, 1 - pixel).translate(tilePos.x(), tilePos.y(), tilePos.z())); + new AABBd(0, pixel, pixel, (isPressed ? pixel / 2f : pixel), 1 - pixel, 1 - pixel).translate(tilePos.x(), tilePos.y(), tilePos.z()); default -> - world.getEntitiesWithinAABB(this.triggerMobClass, new AABBd(1 - (isPressed ? pixel / 2f : pixel), pixel, pixel, 1, 1 - pixel, 1 - pixel).translate(tilePos.x(), tilePos.y(), tilePos.z())); + new AABBd(1 - (isPressed ? pixel / 2f : pixel), pixel, pixel, 1, 1 - pixel, 1 - pixel).translate(tilePos.x(), tilePos.y(), tilePos.z()); }; + List list = world.getEntitiesWithinAABB(this.triggerMobClass, box); for (T t : list) { if (t.canInteract()) { isSteppedOn = true; break; } } + + if (!isSteppedOn) { + List vehicles = world.getEntitiesWithinAABB(Entity.class, box); + for (Entity vehicle : vehicles) { + Entity rider = vehicle.getPassenger(); + if (this.triggerMobClass.isInstance(rider) && rider.canInteract()) { + isSteppedOn = true; + break; + } + } + } if (isSteppedOn && !isPressed) { world.setBlockData(tilePos, meta | MASK_POWERED); world.markBlockNeedsUpdate(tilePos); diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRail.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRail.java index cb789a486..94561ecb9 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRail.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRail.java @@ -23,7 +23,7 @@ import org.joml.primitives.AABBdc; import java.util.ArrayList; import java.util.List; -public class BlockLogicRail extends BlockLogic implements ISupportable { +public class BlockLogicRail extends BlockLogic implements ISupportable, BlockLogic.MatcherDataEquivalency { public static final int MASK_DIRECTION = 0b0000_0111; public static final int MASK_POWERED = 0b0000_1000; public final boolean isPowered; @@ -39,20 +39,17 @@ public class BlockLogicRail extends BlockLogic implements ISupportable { } @Override - protected int getMatcherEquivalenceData(int data) { + public boolean isEquivalentDataForMatcherImpl(int thisData, int thatData) { final int dirMask = (this.isPowered) ? MASK_DIRECTION : MASK_DIRECTION | MASK_POWERED; - var railDir = RailDirection.getFromMeta(data & dirMask); - if (railDir.isStraight()) { - railDir = RailDirection.STRAIGHT_NS; - } else if (railDir.isSloped()) { - railDir = RailDirection.SLOPE_E; - } else if (railDir.isCurved()) { - assert !this.isPowered; - railDir = RailDirection.TURN_ES; - } - data &= ~MASK_DIRECTION; - data |= railDir.meta & dirMask; - return data; + if (this.isPowered && (thisData & MASK_POWERED) != (thatData & MASK_POWERED)) return false; + + final var thisDir = RailDirection.getFromMeta(thisData & dirMask);; + final var thatDir = RailDirection.getFromMeta(thatData & dirMask);; + + if (thisDir.isStraight()) return thatDir.isStraight(); + if (thisDir.isCurved()) return thatDir.isCurved(); + if (thisDir.isSloped()) return thatDir.isSloped(); + return false; } public @NotNull RailDirection getRailDirection(@NotNull WorldSource world, @NotNull TilePosc tilePos) { diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRepeater.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRepeater.java index 3accdf548..49d86f1cc 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRepeater.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRepeater.java @@ -23,7 +23,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Random; -public class BlockLogicRepeater extends BlockLogic implements ISupportable { +public class BlockLogicRepeater extends BlockLogic implements ISupportable, BlockLogic.MatcherDataEquivalency.Masked { public static final double[] torchPosOffset = { -0.0625D, 0.0625D, 0.1875D, 0.3125D }; @@ -46,13 +46,8 @@ public class BlockLogicRepeater extends BlockLogic implements ISupportable { } @Override - protected boolean isSameBlockForMatcher(final @NotNull Block other) { - return other.getLogic() instanceof BlockLogicRepeater repeater && (this.isRepeaterPowered == repeater.isRepeaterPowered); - } - - @Override - protected int getMatcherEquivalenceData(final int data) { - return data & MASK_TICK_DELAY; + public int getMatcherDataEquivalencyMask() { + return MASK_TICK_DELAY; } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRope.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRope.java index ffd78e7c0..6e1a1bca6 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRope.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRope.java @@ -161,10 +161,4 @@ public class BlockLogicRope public ItemStack[] getBreakResult(@NotNull World world, @NotNull EnumDropCause dropCause, int data, @Nullable TileEntity tileEntity) { return new ItemStack[]{new ItemStack(Items.ROPE)}; } - - @Override - protected int getMatcherEquivalenceData(int data) { - // return data & ~MASK_ROPE_CONNECT; - return 0; - } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRotatable.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRotatable.java index f8ce3cecf..772126c65 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRotatable.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRotatable.java @@ -16,11 +16,6 @@ public class BlockLogicRotatable extends BlockLogic { super(block, material); } - @Override - protected int getMatcherEquivalenceData(final int data) { - return data & ~MASK_DIRECTION; - } - public static @NotNull Direction getDirectionFromMeta(int meta) { return Direction.fromId(meta & MASK_DIRECTION); } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassCrystal.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassCrystal.java index 41ff6a93b..c3cd42236 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassCrystal.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRubyglassCrystal.java @@ -20,7 +20,7 @@ import org.joml.primitives.AABBdc; import java.util.Random; -public class BlockLogicRubyglassCrystal extends BlockLogicTransparent { +public class BlockLogicRubyglassCrystal extends BlockLogicTransparent implements BlockLogic.MatcherDataEquivalency { public static final int BREAK_STAGES = 3; private final @NotNull AABBd checkAABB = new AABBd(); public BlockLogicRubyglassCrystal(@NotNull Block block) { diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSaplingBase.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSaplingBase.java index 204c5b483..8ec08268a 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSaplingBase.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSaplingBase.java @@ -3,7 +3,7 @@ package net.minecraft.core.block; import java.util.Random; import net.minecraft.core.entity.player.Player; -import net.minecraft.core.item.IBonemealable; +// import net.minecraft.core.item.IBonemealable; import net.minecraft.core.item.ItemStack; import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.util.helper.Side; @@ -13,7 +13,7 @@ import net.minecraft.core.world.pos.TilePosc; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public abstract class BlockLogicSaplingBase extends BlockLogicFlower implements IBonemealable { +public abstract class BlockLogicSaplingBase extends BlockLogicFlower /*implements IBonemealable*/ { public boolean canGrowOnSand = false; public BlockLogicSaplingBase(@NotNull Block block) { @@ -68,9 +68,4 @@ public abstract class BlockLogicSaplingBase extends BlockLogicFlower implements } public abstract void growTree(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Random random); - - @Override - protected int getMatcherEquivalenceData(int data) { - return 0; - } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSign.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSign.java index 55b145a16..8bcc92e0d 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSign.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSign.java @@ -23,7 +23,12 @@ import org.jetbrains.annotations.Nullable; import org.joml.primitives.AABBd; import org.joml.primitives.AABBdc; -public class BlockLogicSign extends BlockLogic implements IPaintable { +public class BlockLogicSign extends BlockLogic +implements + IPaintable, + BlockLogic.MatcherDataEquivalency.Masked, + BlockLogic.MatcherEntityEquivalency +{ public static final int MASK_SIDE = 0b0000_1111; public static final int SIDE_NORTH = 2; public static final int SIDE_SOUTH = 3; @@ -41,18 +46,24 @@ public class BlockLogicSign extends BlockLogic implements IPaintable { } @Override - public boolean isEquivalent(@NotNull World world, @NotNull TilePosc thisPos, @NotNull TilePosc thatPos) { - assert world.getBlockType(thisPos) == this.block; - if (world.getBlockType(thatPos) != this.block) return false; - if (((world.getBlockData(thisPos) ^ world.getBlockData(thatPos)) & ~MASK_SIDE) != 0) return false; - if (!(world.getTileEntity(thisPos) instanceof TileEntitySign thisSign) || - !(world.getTileEntity(thatPos) instanceof TileEntitySign thatSign)) - return false; + public int getMatcherDataEquivalencyMask() { + return ~MASK_SIDE; + } + + @Override + public @NotNull Class getEntityEquivalencyClass() { + return TileEntitySign.class; + } + + @Override + public boolean isEquivalentEntityForMatcherImpl( + @NotNull TileEntitySign thisSign, @NotNull TileEntitySign thatSign + ) { if (thisSign.getPicture() != thatSign.getPicture()) return false; boolean isAllBlank = true; - assert thisSign.signText.length == 4 && thatSign.signText.length == 4; - for (int i = 0; i < 4; i++) { + assert thisSign.signText.length == thatSign.signText.length; + for (int i = 0; i < thisSign.signText.length; i++) { final boolean thisIsBlank, thatIsBlank; { thisIsBlank = thisSign.signText[i].isEmpty() || thisSign.signText[i].isBlank(); thatIsBlank = thatSign.signText[i].isEmpty() || thatSign.signText[i].isBlank(); @@ -64,7 +75,7 @@ public class BlockLogicSign extends BlockLogic implements IPaintable { if (thisSign.getColor() != thatSign.getColor()) return false; if (thisSign.isGlowing() != thatSign.isGlowing()) return false; - for (int i = 0; i < 4; i++) { + for (int i = 0; i < thisSign.signText.length; i++) { if (!thisSign.signText[i].equals(thatSign.signText[i])) return false; } return true; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSlab.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSlab.java index cd85f0a6f..7d9e75bef 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSlab.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSlab.java @@ -27,7 +27,7 @@ import org.joml.primitives.AABBdc; import java.util.Random; -public class BlockLogicSlab extends BlockLogic +public class BlockLogicSlab extends BlockLogic implements BlockLogic.MatcherDataEquivalency { public @NotNull Block modelBlock; public int modelBlockMetadata; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSpikes.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSpikes.java index f9b83120b..9c4df7e19 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSpikes.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSpikes.java @@ -26,7 +26,7 @@ import org.jetbrains.annotations.Nullable; import org.joml.primitives.AABBd; import org.joml.primitives.AABBdc; -public class BlockLogicSpikes extends BlockLogic +public class BlockLogicSpikes extends BlockLogic implements BlockLogic.MatcherDataEquivalency.Masked { public static final int MASK_POWERED = 0b0000_0001; public static final int MASK_DIRECTION = 0b0000_1110; @@ -39,8 +39,8 @@ public class BlockLogicSpikes extends BlockLogic } @Override - protected int getMatcherEquivalenceData(final int data) { - return data & MASK_POWERED; + public int getMatcherDataEquivalencyMask() { + return MASK_POWERED; } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStairs.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStairs.java index 9d86f24b0..599e968d3 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStairs.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStairs.java @@ -1,5 +1,6 @@ package net.minecraft.core.block; +import java.util.ArrayList; import java.util.List; import java.util.Random; @@ -16,82 +17,21 @@ import net.minecraft.core.entity.Entity; import net.minecraft.core.enums.EnumDropCause; import net.minecraft.core.item.ItemStack; import net.minecraft.core.util.helper.Direction; +import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.util.helper.Side; +import net.minecraft.core.util.phys.BoundingVolume; +import net.minecraft.core.util.phys.HitResult; import net.minecraft.core.world.WorldSource; 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.joml.Vector3d; +import org.joml.Vector3dc; import org.joml.primitives.AABBd; import org.joml.primitives.AABBdc; -public class BlockLogicStairs extends BlockLogic { - @Override - protected int getMatcherEquivalenceData(final int data) { - return data & ~MASK_ROTATION_HORIZONTAL; - } - - // private static final Map selectionVolumes = new HashMap<>(); -// -// static -// { -// // EAST UP -// System.out.println("EAST UP"); -// BoundingVolume vol = BoundingVolume.newFilledVolume(); -// vol.carveVolume(0, 8, 0, 7, 15, 15); -// vol.bake(); -// selectionVolumes.put(0b0000, vol); -// -// // WEST UP -// System.out.println("WEST UP"); -// vol = BoundingVolume.newFilledVolume(); -// vol.carveVolume(8, 8, 0, 15, 15, 15); -// vol.bake(); -// selectionVolumes.put(0b0001, vol); -// -// // SOUTH UP -// System.out.println("SOUTH UP"); -// vol = BoundingVolume.newFilledVolume(); -// vol.carveVolume(0, 8, 0, 15, 15, 7); -// vol.bake(); -// selectionVolumes.put(0b0010, vol); -// -// // NORTH UP -// System.out.println("NORTH UP"); -// vol = BoundingVolume.newFilledVolume(); -// vol.carveVolume(0, 8, 8, 15, 15, 15); -// vol.bake(); -// selectionVolumes.put(0b0011, vol); -// -// // EAST DOWN -// System.out.println("EAST DOWN"); -// vol = BoundingVolume.newFilledVolume(); -// vol.carveVolume(0, 0, 0, 7, 7, 15); -// vol.bake(); -// selectionVolumes.put(0b1000, vol); -// -// // WEST DOWN -// System.out.println("WEST DOWN"); -// vol = BoundingVolume.newFilledVolume(); -// vol.carveVolume(8, 0, 0, 15, 7, 15); -// vol.bake(); -// selectionVolumes.put(0b1001, vol); -// -// // SOUTH DOWN -// System.out.println("SOUTH DOWN"); -// vol = BoundingVolume.newFilledVolume(); -// vol.carveVolume(0, 0, 0, 15, 7, 7); -// vol.bake(); -// selectionVolumes.put(0b1010, vol); -// -// // NORTH DOWN -// System.out.println("NORTH DOWN"); -// vol = BoundingVolume.newFilledVolume(); -// vol.carveVolume(0, 0, 8, 15, 7, 15); -// vol.bake(); -// selectionVolumes.put(0b1011, vol); -// } +public class BlockLogicStairs extends BlockLogic implements BlockLogic.MatcherDataEquivalency.Masked { public static final int MASK_ROTATION_HORIZONTAL = 0b0000_0011; public static final int MASK_ROTATION_VERTICAL = 0b0000_1000; @@ -176,6 +116,44 @@ public class BlockLogicStairs extends BlockLogic { PartialSupport.INSTANCE.up().right(), // South }; + private static AABBd @NotNull [] stairLocalParts(int hRotation, float stepYOffset) { + return switch (hRotation) { + case H_ROTATION_WEST -> new AABBd[]{ + new AABBd(0.0, stepYOffset, 0.0, 0.5, 0.5 + stepYOffset, 1.0), + new AABBd(0.5, 0.0, 0.0, 1.0, 1.0, 1.0) + }; + case H_ROTATION_EAST -> new AABBd[]{ + new AABBd(0.0, 0.0, 0.0, 0.5, 1.0, 1.0), + new AABBd(0.5, stepYOffset, 0.0, 1.0, 0.5 + stepYOffset, 1.0) + }; + case H_ROTATION_NORTH -> new AABBd[]{ + new AABBd(0.0, stepYOffset, 0.0, 1.0, 0.5 + stepYOffset, 0.5), + new AABBd(0.0, 0.0, 0.5, 1.0, 1.0, 1.0) + }; + default -> new AABBd[]{ + new AABBd(0.0, 0.0, 0.0, 1.0, 1.0, 0.5), + new AABBd(0.0, stepYOffset, 0.5, 1.0, 0.5 + stepYOffset, 1.0) + }; + }; + } + + private static int stairOrientIndex(int meta) { + return (meta & MASK_ROTATION_HORIZONTAL) | ((meta & MASK_ROTATION_VERTICAL) >> 1); + } + + private static BoundingVolume @NotNull [] bakeStairSelectionVolumes() { + BoundingVolume @NotNull [] out = new BoundingVolume[8]; + for (int orient = 0; orient < 8; orient++) { + int h = orient & MASK_ROTATION_HORIZONTAL; + float stepY = (orient & 4) != 0 ? 0.5f : 0.0f; + AABBd[] parts = stairLocalParts(h, stepY); + out[orient] = BoundingVolume.bakeFromBlockSpaceAabbs(parts[0], parts[1]); + } + return out; + } + + private static final BoundingVolume @NotNull [] STAIR_SELECTION_VOLUME = bakeStairSelectionVolumes(); + public @NotNull Block modelBlock; public BlockLogicStairs(@NotNull Block block, @NotNull Block modelBlock) { @@ -188,6 +166,11 @@ public class BlockLogicStairs extends BlockLogic { this.block.withHardness(this.modelBlock.blockHardness); this.block.withBlastResistance(this.modelBlock.blastResistance / 3F); } + + @Override + public int getMatcherDataEquivalencyMask() { + return ~MASK_ROTATION_HORIZONTAL; + } @Override public @NotNull Material getMaterial() { @@ -217,31 +200,48 @@ public class BlockLogicStairs extends BlockLogic { @Override public void getCollisionAABBs(@NotNull World world, @NotNull TilePosc tilePos, @NotNull AABBdc aabb, @NotNull List<@NotNull AABBdc> aabbList) { + ArrayList parts = new ArrayList<>(2); + collectStairPartAABBs(world, tilePos, parts); + for (AABBdc box : parts) { + addIntersectingBoundingBox(aabb, box, aabbList); + } + } + + public void collectStairPartAABBs(@NotNull World world, @NotNull TilePosc tilePos, @NotNull List<@NotNull AABBdc> out) { + int meta = world.getBlockData(tilePos); + int hRotation = meta & MASK_ROTATION_HORIZONTAL; + float stepYOffset = (meta & MASK_ROTATION_VERTICAL) != 0 ? 0.5f : 0.0f; + double px = tilePos.x(); + double py = tilePos.y(); + double pz = tilePos.z(); + for (AABBd part : stairLocalParts(hRotation, stepYOffset)) { + out.add(new AABBd(part).translate(px, py, pz)); + } + } + + @Override + public @Nullable BoundingVolume getBoundingVolume(@NotNull World world, @NotNull TilePosc tilePos) { + return STAIR_SELECTION_VOLUME[stairOrientIndex(world.getBlockData(tilePos))]; + } + + @Override + public @Nullable HitResult collisionRayTrace(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Vector3dc start, @NotNull Vector3dc end, boolean useSelectionAABB) { int meta = world.getBlockData(tilePos); int hRotation = meta & MASK_ROTATION_HORIZONTAL; - int vRotation = meta & MASK_ROTATION_VERTICAL; - - float stepYOffset = vRotation != 0 ? 0.5f : 0.0f; - - switch (hRotation) { - case H_ROTATION_WEST: - addIntersectingBoundingBox(aabb, new AABBd(0.0F, 0.0F + stepYOffset, 0.0F, 0.5F, 0.5F + stepYOffset, 1.0F).translate(tilePos.x(), tilePos.y(), tilePos.z()), aabbList); - addIntersectingBoundingBox(aabb, new AABBd(0.5F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F).translate(tilePos.x(), tilePos.y(), tilePos.z()), aabbList); - break; - case H_ROTATION_EAST: - addIntersectingBoundingBox(aabb, new AABBd(0.0F, 0.0F, 0.0F, 0.5F, 1.0F, 1.0F).translate(tilePos.x(), tilePos.y(), tilePos.z()), aabbList); - addIntersectingBoundingBox(aabb, new AABBd(0.5F, 0.0F + stepYOffset, 0.0F, 1.0F, 0.5F + stepYOffset, 1.0F).translate(tilePos.x(), tilePos.y(), tilePos.z()), aabbList); - break; - case H_ROTATION_NORTH: - addIntersectingBoundingBox(aabb, new AABBd(0.0F, 0.0F + stepYOffset, 0.0F, 1.0F, 0.5F + stepYOffset, 0.5F).translate(tilePos.x(), tilePos.y(), tilePos.z()), aabbList); - addIntersectingBoundingBox(aabb, new AABBd(0.0F, 0.0F, 0.5F, 1.0F, 1.0F, 1.0F).translate(tilePos.x(), tilePos.y(), tilePos.z()), aabbList); - break; - case H_ROTATION_SOUTH: - default: - addIntersectingBoundingBox(aabb, new AABBd(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.5F).translate(tilePos.x(), tilePos.y(), tilePos.z()), aabbList); - addIntersectingBoundingBox(aabb, new AABBd(0.0F, 0.0F + stepYOffset, 0.5F, 1.0F, 0.5F + stepYOffset, 1.0F).translate(tilePos.x(), tilePos.y(), tilePos.z()), aabbList); - break; + float stepYOffset = (meta & MASK_ROTATION_VERTICAL) != 0 ? 0.5f : 0.0f; + @Nullable HitResult closest = null; + double closestDistSq = Double.POSITIVE_INFINITY; + for (AABBd part : stairLocalParts(hRotation, stepYOffset)) { + @Nullable HitResult hit = traceRayAgainstLocalAabb(tilePos, start, end, part); + if (hit != null) { + double d2 = start.distanceSquared(hit.location); + if (d2 < closestDistSq) { + closestDistSq = d2; + closest = hit; + } + } } + return closest; } @Override @@ -277,12 +277,6 @@ public class BlockLogicStairs extends BlockLogic { public int tickDelay() { return this.modelBlock.tickDelay(); } -// @Override -// public BoundingVolume getBoundingVolume(World world, int x, int y, int z) -// { -// int meta = world.getBlockMetadata(x, y, z); -// return selectionVolumes.getOrDefault(meta & 0x0F, null); -// } @Override public void onEntityInside(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Entity entity, @NotNull Vector3d velocityDirection) { @@ -381,4 +375,106 @@ public class BlockLogicStairs extends BlockLogic { public @NotNull MaterialColor getMaterialColor() { return this.modelBlock.getMaterialColor(); } + + private static @Nullable HitResult traceRayAgainstLocalAabb(@NotNull TilePosc tilePos, @NotNull Vector3dc start, @NotNull Vector3dc end, @NotNull AABBdc bounds) { + double px = tilePos.x(); + double py = tilePos.y(); + double pz = tilePos.z(); + Vector3d startInBlock = start.add(-px, -py, -pz, new Vector3d()); + Vector3d endInBlock = end.add(-px, -py, -pz, new Vector3d()); + + @Nullable Vector3d minVX = MathHelper.vecClipX(startInBlock, endInBlock, bounds.minX(), new Vector3d()); + @Nullable Vector3d maxVX = MathHelper.vecClipX(startInBlock, endInBlock, bounds.maxX(), new Vector3d()); + @Nullable Vector3d minVY = MathHelper.vecClipY(startInBlock, endInBlock, bounds.minY(), new Vector3d()); + @Nullable Vector3d maxVY = MathHelper.vecClipY(startInBlock, endInBlock, bounds.maxY(), new Vector3d()); + @Nullable Vector3d minVZ = MathHelper.vecClipZ(startInBlock, endInBlock, bounds.minZ(), new Vector3d()); + @Nullable Vector3d maxVZ = MathHelper.vecClipZ(startInBlock, endInBlock, bounds.maxZ(), new Vector3d()); + + if (!isVecInsideYzBounds(bounds, minVX)) minVX = null; + if (!isVecInsideYzBounds(bounds, maxVX)) maxVX = null; + if (!isVecInsideXzBounds(bounds, minVY)) minVY = null; + if (!isVecInsideXzBounds(bounds, maxVY)) maxVY = null; + if (!isVecInsideXyBounds(bounds, minVZ)) minVZ = null; + if (!isVecInsideXyBounds(bounds, maxVZ)) maxVZ = null; + + @Nullable Vector3d clip = null; + @Nullable Side side = null; + double bestD2 = Double.POSITIVE_INFINITY; + + if (minVX != null) { + double d2 = startInBlock.distanceSquared(minVX); + if (d2 < bestD2) { + bestD2 = d2; + clip = minVX; + side = Side.WEST; + } + } + if (maxVX != null) { + double d2 = startInBlock.distanceSquared(maxVX); + if (d2 < bestD2) { + bestD2 = d2; + clip = maxVX; + side = Side.EAST; + } + } + if (minVY != null) { + double d2 = startInBlock.distanceSquared(minVY); + if (d2 < bestD2) { + bestD2 = d2; + clip = minVY; + side = Side.BOTTOM; + } + } + if (maxVY != null) { + double d2 = startInBlock.distanceSquared(maxVY); + if (d2 < bestD2) { + bestD2 = d2; + clip = maxVY; + side = Side.TOP; + } + } + if (minVZ != null) { + double d2 = startInBlock.distanceSquared(minVZ); + if (d2 < bestD2) { + bestD2 = d2; + clip = minVZ; + side = Side.NORTH; + } + } + if (maxVZ != null) { + double d2 = startInBlock.distanceSquared(maxVZ); + if (d2 < bestD2) { + bestD2 = d2; + clip = maxVZ; + side = Side.SOUTH; + } + } + + if (clip == null) { + return null; + } + + return new HitResult.Tile(tilePos, side, clip.add(px, py, pz, new Vector3d())); + } + + private static boolean isVecInsideYzBounds(AABBdc bounds, @Nullable Vector3dc v) { + if (v == null) { + return false; + } + return v.y() >= bounds.minY() && v.y() <= bounds.maxY() && v.z() >= bounds.minZ() && v.z() <= bounds.maxZ(); + } + + private static boolean isVecInsideXzBounds(AABBdc bounds, @Nullable Vector3dc v) { + if (v == null) { + return false; + } + return v.x() >= bounds.minX() && v.x() <= bounds.maxX() && v.z() >= bounds.minZ() && v.z() <= bounds.maxZ(); + } + + private static boolean isVecInsideXyBounds(AABBdc bounds, @Nullable Vector3dc v) { + if (v == null) { + return false; + } + return v.x() >= bounds.minX() && v.x() <= bounds.maxX() && v.y() >= bounds.minY() && v.y() <= bounds.maxY(); + } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java index 42addc6c8..e32728ada 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java @@ -25,7 +25,7 @@ import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; -public class BlockLogicStatue extends BlockLogic { +public class BlockLogicStatue extends BlockLogic implements BlockLogic.MatcherEntityEquivalency { private final boolean isBottom; public final @Nullable Supplier<@NotNull Item> droppedItem; @@ -264,19 +264,27 @@ public class BlockLogicStatue extends BlockLogic { } @Override - public boolean isEquivalent(@NotNull World world, @NotNull TilePosc thisPos, @NotNull TilePosc thatPos) { - assert world.getBlockType(thisPos) == this.block; - final var thatBlock = world.getBlockType(thatPos); - if (thatBlock != this.block) return false; - final var that = (BlockLogicStatue) thatBlock.getLogic(); - - final var query = new TilePos(); - if (!(world.getTileEntity(this.isBottom ? thisPos : thisPos.down(query)) instanceof TileEntityStatue thisStatue) || - !(world.getTileEntity(that.isBottom ? thatPos : thatPos.down(query)) instanceof TileEntityStatue thatStatue)) - return false; - + public boolean isEquivalent( + @NotNull WorldSource world, + @NotNull TilePosc thisPos, @NotNull TilePosc thatPos, + @NotNull Block thatBlock + ) { + return (this.isBottom) + ? super.isEquivalent(world, thisPos, thatPos, thatBlock) + : super.isEquivalent(world, thisPos.down(new TilePos()), thatPos.down(new TilePos()), thatBlock); + } + + @Override + public @NotNull Class getEntityEquivalencyClass() { + return TileEntityStatue.class; + } + + @Override + public boolean isEquivalentEntityForMatcherImpl( + @NotNull TileEntityStatue thisStatue, @NotNull TileEntityStatue thatStatue + ) { if (thisStatue.getPose() != thatStatue.getPose()) return false; - + // we assume (but not assert) all stacks to be of size 1 // TODO: Item.isEquivalent(ItemStack) if (!ItemStack.areItemsEqual(thisStatue.getHeldItem(), thatStatue.getHeldItem())) return false; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSugarcane.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSugarcane.java index 8af566e81..ac5abde80 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSugarcane.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSugarcane.java @@ -131,9 +131,4 @@ public class BlockLogicSugarcane extends BlockLogic implements IBonemealable { } return true; } - - @Override - protected int getMatcherEquivalenceData(int data) { - return 0; - } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSulfur.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSulfur.java index b904c1c85..4bbc1e14d 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSulfur.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSulfur.java @@ -32,7 +32,7 @@ public class BlockLogicSulfur extends BlockLogic { public ItemStack[] getBreakResult(@NotNull World world, @NotNull EnumDropCause dropCause, int data, @Nullable TileEntity tileEntity) { return switch (dropCause) { case PICK_BLOCK, SILK_TOUCH -> new ItemStack[]{new ItemStack(this)}; - default -> new ItemStack[]{new ItemStack(Items.SULFUR, 1 + world.rand.nextInt(2))}; + default -> new ItemStack[]{new ItemStack(Items.SULFUR, 4)}; }; } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicThermalVent.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicThermalVent.java index 04f08add0..a9753bd77 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicThermalVent.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicThermalVent.java @@ -2,6 +2,7 @@ package net.minecraft.core.block; import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; import net.minecraft.core.achievement.Achievements; +import net.minecraft.core.block.entity.TileEntityThermalVent; import net.minecraft.core.block.material.Materials; import net.minecraft.core.entity.Entity; import net.minecraft.core.entity.Mob; @@ -9,11 +10,9 @@ import net.minecraft.core.entity.player.Player; import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.Dimension; import net.minecraft.core.world.World; -import net.minecraft.core.world.particle.ParticleEmitterRange; 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 java.util.List; @@ -36,11 +35,11 @@ public class BlockLogicThermalVent extends BlockLogic { public BlockLogicThermalVent(final @NotNull Block block) { super(block, Materials.BASALT); block.setTicking(true); + block.withEntity(TileEntityThermalVent::new); } @Override public void animationTick(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Random rand) { - if (world.isClientSide) return; final int state = getVentState(world.getBlockData(tilePos)); final double xPos = (double) tilePos.x() + 0.5D; @@ -51,12 +50,12 @@ public class BlockLogicThermalVent extends BlockLogic { return; } - world.spawnParticle("ventsmoke", xPos, yPos, zPos, 0.0D, 0.005D, 0.0D, 1, 1000, true); + world.spawnParticle("ventsmoke", xPos, yPos, zPos, 0.0D, 0.005D, 0.0D, 1, 1000, false); if (hasVentBelow(world, tilePos) && state >= VENTING_STATE - 1) { for (int i = 0; i < 4; i++) { - world.spawnParticle("ventsmoke", xPos, yPos, zPos, 0.0D, 0.005D, 0.0D, 0, 1000.0, true); - world.spawnParticle("smoke", xPos + rand.nextFloat() - 0.5D, yPos, zPos + rand.nextFloat() - 0.5D, 0.0D, 0.005D, 0.0D, 1, 1000.0, true); + world.spawnParticle("ventsmoke", xPos, yPos, zPos, 0.0D, 0.005D, 0.0D, 0, 1000.0, false); + world.spawnParticle("smoke", xPos + rand.nextFloat() - 0.5D, yPos, zPos + rand.nextFloat() - 0.5D, 0.0D, 0.005D, 0.0D, 1, 1000.0, false); } } } @@ -72,16 +71,6 @@ public class BlockLogicThermalVent extends BlockLogic { return Block.hasLogicClass(world.getBlockType(tilePos.down(new TilePos())), BlockLogicThermalVent.class); } - @Override - protected boolean isSameBlockForMatcher(@NotNull Block other) { - return Block.hasLogicClass(other, BlockLogicThermalVent.class); - } - - @Override - protected int getMatcherEquivalenceData(int data) { - return 0; - } - @Override public void onNeighborChanged(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Block block) { if (!hasVentBelow(world, tilePos) && getVentState(world.getBlockData(tilePos)) != DORMANT_STATE) { @@ -198,9 +187,4 @@ public class BlockLogicThermalVent extends BlockLogic { world.setBlockData(tilePos, hasVentBelow(world, tilePos) ? world.rand.nextInt(VENTING_STATE) : DORMANT_STATE); } } - - @Override - public @Nullable ParticleEmitterRange getParticleEmitterRange() { - return ParticleEmitterRange.FAR; - } } \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTimer.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTimer.java index 068ddbb61..ab3dbeafc 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTimer.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTimer.java @@ -25,7 +25,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Random; -public class BlockLogicTimer extends BlockLogic implements ISupportable { +public class BlockLogicTimer extends BlockLogic implements ISupportable, BlockLogic.MatcherDataEquivalency.Masked { public static final double[] torchPosOffset = { -0.0625D, 0.0625D, 0.1875D, 0.3125D }; @@ -50,8 +50,8 @@ public class BlockLogicTimer extends BlockLogic implements ISupportable { public static final int MASK_TICK_DELAY = 0b0000_1100; @Override - protected int getMatcherEquivalenceData(final int data) { - return data & (MASK_TICK_DELAY | ~MASK_DIRECTION); + public int getMatcherDataEquivalencyMask() { + return ~MASK_DIRECTION; } public BlockLogicTimer(@NotNull Block block) { diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorch.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorch.java index 2b7a5f1b5..41b10f73c 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorch.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorch.java @@ -34,11 +34,6 @@ public class BlockLogicTorch extends BlockLogic implements ISupportable { block.setTicking(true); } - @Override - protected int getMatcherEquivalenceData(final int data) { - return data & ~MASK_DIRECTION; - } - @Override public @Nullable AABBdc getCollisionAABB(@NotNull WorldSource source, @NotNull TilePosc tilePos) { return null; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorchRedstone.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorchRedstone.java index 64912292e..5196b9ec6 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorchRedstone.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorchRedstone.java @@ -21,11 +21,6 @@ public class BlockLogicTorchRedstone extends BlockLogicTorch { this.torchActive = isActive; } - @Override - protected boolean isSameBlockForMatcher(final @NotNull Block other) { - return other.getLogic() instanceof BlockLogicTorchRedstone rtorch && rtorch.torchActive == this.torchActive; - } - @Override public int tickDelay() { return 2; diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoor.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoor.java index 4fc8ef0c6..0de34e5db 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoor.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoor.java @@ -26,7 +26,7 @@ import org.jetbrains.annotations.Nullable; import org.joml.primitives.AABBd; import org.joml.primitives.AABBdc; -public class BlockLogicTrapDoor extends BlockLogic implements IPaintable { +public class BlockLogicTrapDoor extends BlockLogic implements IPaintable, BlockLogic.MatcherDataEquivalency { public static final int DIRECTION_SOUTH = 0; public static final int DIRECTION_NORTH = 1; public static final int DIRECTION_EAST = 2; @@ -44,9 +44,10 @@ public class BlockLogicTrapDoor extends BlockLogic implements IPaintable { } @Override - protected int getMatcherEquivalenceData(final int data) { - assert (MASK_OPEN << 1) == MASK_UPPER_HALF; - return data & ~(MASK_DIRECTION | ((data & MASK_OPEN) << 1)); + public boolean isEquivalentDataForMatcherImpl(int thisData, int thatData) { + if ((thisData & MASK_OPEN) != (thatData & MASK_OPEN)) return false; + if ((thisData & MASK_OPEN) != 0) return true; + return (thisData & MASK_UPPER_HALF) == (thatData & MASK_UPPER_HALF); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoorPainted.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoorPainted.java index 2ccb6b7a0..cd98d5f9e 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoorPainted.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoorPainted.java @@ -53,4 +53,12 @@ public class BlockLogicTrapDoorPainted extends BlockLogicTrapDoor implements IPa public void setColor(@NotNull World world, @NotNull TilePosc tilePos, @NotNull DyeColor color) { IPainted.super.setColor(world, tilePos, color); } + + public static final int MASK_COLOR = 0xF0; + + @Override + public boolean isEquivalentDataForMatcherImpl(int thisData, int thatData) { + if ((thisData & MASK_COLOR) != (thatData & MASK_COLOR)) return false; + return super.isEquivalentDataForMatcherImpl(thisData, thatData); + } } diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicVeryRotatable.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicVeryRotatable.java index 0bfd57ee8..ef39e7d8e 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicVeryRotatable.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicVeryRotatable.java @@ -16,11 +16,6 @@ public abstract class BlockLogicVeryRotatable super(block, material); } - @Override - protected int getMatcherEquivalenceData(final int data) { - return data & ~MASK_DIRECTION; - } - @Override public void onPlacedByMob(final @NotNull World world, final @NotNull TilePosc tilePos, final @NotNull Side side, final @NotNull Mob mob, final double xHit, final double yHit) { final @NotNull Direction direction = mob.getPlacementDirection(side).opposite(); diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicWireRedstone.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicWireRedstone.java index 3621bd2a6..65755d6a8 100644 --- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicWireRedstone.java +++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicWireRedstone.java @@ -9,7 +9,6 @@ import net.minecraft.core.current.util.BlockState; import net.minecraft.core.enums.EnumDropCause; import net.minecraft.core.item.ItemStack; import net.minecraft.core.item.Items; -import net.minecraft.core.sound.SoundCategory; import net.minecraft.core.util.helper.Axis; import net.minecraft.core.util.helper.Side; import net.minecraft.core.world.World; @@ -26,7 +25,7 @@ import java.util.Random; import java.util.Set; import java.util.function.Predicate; -public class BlockLogicWireRedstone extends BlockLogic implements ISupportable { +public class BlockLogicWireRedstone extends BlockLogic implements ISupportable, BlockLogic.MatcherDataEquivalency.Masked { public static final int SIGNAL_MIN = 0; public static final int SIGNAL_MAX = 15; public static final int SIGNAL_STEP = 1; @@ -267,8 +266,8 @@ public class BlockLogicWireRedstone extends BlockLogic implements ISupportable { private int checkTarget(@NotNull World world, @NotNull TilePos tilePos, int sourceStrength) { if(world.getBlockType(tilePos) == Blocks.CONDUIT){ int cData = world.getBlockData(tilePos); - int cStrength = (cData >> BlockLogicConduit.POWER_SHIFT) & BlockLogicConduit.POWER_MASK; - return Math.max(BlockLogicConduit.signalConverter(cStrength, true), sourceStrength); + int cStrength = BlockLogicConduit.getPower(cData); + return Math.max(BlockLogicConduit.signalConverter(cStrength), sourceStrength); } if (world.getBlockType(tilePos) != this.block) { @@ -409,6 +408,7 @@ public class BlockLogicWireRedstone extends BlockLogic implements ISupportable { public static boolean shouldConnectTo(@NotNull WorldSource source, @NotNull TilePos tilePos, @NotNull Side side) { // TODO make connections handled per block rather then by the dust + // if handling this, the conduit has the same issue, and should be fixed in tandem with the dust final Block block = source.getBlockType(tilePos); if (block == null) { return false; @@ -559,4 +559,9 @@ public class BlockLogicWireRedstone extends BlockLogic implements ISupportable { public @NotNull ISupport getSupportConstraint(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Side side) { return side == Side.BOTTOM ? PartialSupport.INSTANCE.center() : PartialSupport.INSTANCE; } + + @Override + public int getMatcherDataEquivalencyMask() { + return MASK_POWER; + } } diff --git a/game/core/src/main/java/net/minecraft/core/block/Blocks.java b/game/core/src/main/java/net/minecraft/core/block/Blocks.java index adae62878..d8009b276 100644 --- a/game/core/src/main/java/net/minecraft/core/block/Blocks.java +++ b/game/core/src/main/java/net/minecraft/core/block/Blocks.java @@ -1488,7 +1488,7 @@ public final class Blocks { .withSound(BlockSounds.SAND).withHardness(0.7F) .withTags(BlockTags.MINEABLE_BY_SHOVEL, BlockTags.CAVES_CUT_THROUGH, BlockTags.NETHER_MOBS_SPAWN, BlockTags.NETHER_SURFACE_BLOCK, BlockTags.INFINITE_BURN_SULFURIC); public static final Block BRIMSTONE = register("brimstone", "minecraft:block/brimstone", 1086, block -> new BlockLogicBrimstone(block, Materials.STONE)) - .withSound(BlockSounds.STONE).withHardness(1.8F).withOverrideColor(MaterialColor.paintedBlack) + .withSound(BlockSounds.STONE).withHardness(1F).withOverrideColor(MaterialColor.paintedBlack) .withTags(BlockTags.CAVES_CUT_THROUGH, BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT, BlockTags.NETHER_MOBS_SPAWN, BlockTags.NETHER_SURFACE_BLOCK, BlockTags.INFINITE_BURN_SULFURIC); public static final Block SLAB_BRIMSTONE = register("slab.brimstone", "minecraft:block/slab_brimstone", 1087, block -> new BlockLogicSlab(block, BRIMSTONE)) .withSound(BlockSounds.STONE).withLitInteriorSurface(true).withOverrideColor(MaterialColor.paintedBlack) @@ -1497,7 +1497,7 @@ public final class Blocks { .withSound(BlockSounds.STONE).withLitInteriorSurface(true).withOverrideColor(MaterialColor.paintedBlack) .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.INFINITE_BURN_SULFURIC); public static final Block BRICK_BRIMSTONE = register("brick.brimstone", "minecraft:block/brick_brimstone", 1089, block -> new BlockLogicBrimstone(block, Materials.STONE)) - .withSound(BlockSounds.STONE).withHardness(1.8F).withOverrideColor(MaterialColor.paintedBlack) + .withSound(BlockSounds.STONE).withHardness(1F).withOverrideColor(MaterialColor.paintedBlack) .withTags(BlockTags.CAVES_CUT_THROUGH, BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CHAINLINK_FENCES_CONNECT, BlockTags.NETHER_MOBS_SPAWN, BlockTags.NETHER_SURFACE_BLOCK, BlockTags.INFINITE_BURN_SULFURIC); public static final Block SLAB_BRICK_BRIMSTONE = register("slab.brick.brimstone", "minecraft:block/slab_brick_brimstone", 1090, block -> new BlockLogicSlab(block, BRICK_BRIMSTONE)) .withSound(BlockSounds.STONE).withLitInteriorSurface(true).withOverrideColor(MaterialColor.paintedBlack) 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 dc471bfe8..bd6f2b385 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 @@ -4,6 +4,7 @@ import com.mojang.nbt.tags.CompoundTag; import net.minecraft.core.block.Blocks; import net.minecraft.core.block.motion.CarriedBlock; import net.minecraft.core.block.Block; +import net.minecraft.core.block.BlockLogicMatcher; import net.minecraft.core.block.tag.BlockTags; import net.minecraft.core.entity.Entity; import net.minecraft.core.entity.Mob; @@ -188,8 +189,12 @@ public abstract class TileEntity implements ICarriable return new CarriedBlock(holder, currentBlock, currentMeta, this); } - public void notifyBlocksOfNeighborChange() { + protected final void updateNeighboringMatchers() { if (this.worldObj == null) return; - this.worldObj.notifyBlocksOfNeighborChange(this.tilePos, this.getBlock()); + BlockLogicMatcher.updateNeighboringMatchers(this.worldObj, this.tilePos); + } + + public interface AnimationTicking { + void animationTick(int particleRenderDistance, double distSqr); } } diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityDispatcher.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityDispatcher.java index c43ced3f4..3f2d5ffdf 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityDispatcher.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityDispatcher.java @@ -91,6 +91,7 @@ public class TileEntityDispatcher { addMapping(TileEntityMeshGold.class, NamespaceID.fromPool("minecraft", "mesh_gold")); addMapping(TileEntityStatue.class, NamespaceID.fromPool("minecraft", "statue_stone")); addMapping(TileEntityTimer.class, NamespaceID.fromPool("minecraft", "timer")); + addMapping(TileEntityThermalVent.class, NamespaceID.fromPool("minecraft", "thermal_vent")); } @Deprecated diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFlag.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFlag.java index 8ebffe931..3910bf97c 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFlag.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFlag.java @@ -71,7 +71,7 @@ public class TileEntityFlag extends TileEntity public void setFlipped(boolean flag) { if (this.flipped == flag) return; this.flipped = flag; - this.notifyBlocksOfNeighborChange(); + this.updateNeighboringMatchers(); } public boolean getFlipped() { @@ -235,7 +235,7 @@ public class TileEntityFlag extends TileEntity items[slot] = stack; itemsChanged(); setChanged(); - this.notifyBlocksOfNeighborChange(); + this.updateNeighboringMatchers(); } private void itemsChanged() { @@ -255,7 +255,7 @@ public class TileEntityFlag extends TileEntity colorHash ^= flagColors[i] << (8 * (i & 0b11)); } isDirty = true; - this.notifyBlocksOfNeighborChange(); + this.updateNeighboringMatchers(); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityMeshGold.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityMeshGold.java index 2d8719ed7..bf755857a 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityMeshGold.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityMeshGold.java @@ -85,7 +85,7 @@ public class TileEntityMeshGold extends TileEntityMesh { } filterItem = null; setChanged(); - this.notifyBlocksOfNeighborChange(); + this.updateNeighboringMatchers(); return success | !wasNull; } diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityMobSpawner.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityMobSpawner.java index b6f43313c..da4799864 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityMobSpawner.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityMobSpawner.java @@ -45,7 +45,7 @@ public class TileEntityMobSpawner extends TileEntity { } catch (Exception e) { LOGGER.error("Failed to convert legacy mobspawner id!", e); } - this.notifyBlocksOfNeighborChange(); + this.updateNeighboringMatchers(); } public boolean anyPlayerInRange() { diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntitySign.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntitySign.java index d3f7f5568..63e7eeb6b 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntitySign.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntitySign.java @@ -93,7 +93,7 @@ public class TileEntitySign extends TileEntity public void setPicture(@Nullable EnumSignPicture picture) { this.selectedPicture = (picture == null) ? 0 : picture.getId(); - this.notifyBlocksOfNeighborChange(); + this.updateNeighboringMatchers(); } public TextFormatting getColor() @@ -106,7 +106,7 @@ public class TileEntitySign extends TileEntity public void setColor(TextFormatting color) { selectedColor = color.id; - this.notifyBlocksOfNeighborChange(); + this.updateNeighboringMatchers(); } public boolean isGlowing() { @@ -115,7 +115,7 @@ public class TileEntitySign extends TileEntity public void setGlowing(boolean glowing) { this.glowing = glowing; - this.notifyBlocksOfNeighborChange(); + this.updateNeighboringMatchers(); } public boolean isLocked() { @@ -124,7 +124,7 @@ public class TileEntitySign extends TileEntity public void setLocked(boolean locked) { this.locked = locked; - this.notifyBlocksOfNeighborChange(); + this.updateNeighboringMatchers(); } public void finalizeEditor(@NotNull Player editor) { @@ -135,7 +135,7 @@ public class TileEntitySign extends TileEntity if (!allowColorCode) for(int i = 0; i < 4; i++) { signText[i] = TextFormatting.removeAllColorFormatting(signText[i]); } - this.notifyBlocksOfNeighborChange(); + this.updateNeighboringMatchers(); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityStatue.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityStatue.java index 9489ce6a2..a8371cde4 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityStatue.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityStatue.java @@ -125,7 +125,7 @@ public class TileEntityStatue public void setPose(final @NotNull Pose pose) { this.pose = pose; setChanged(); - this.notifyBlocksOfNeighborChange(); + this.updateNeighboringMatchers(); } public void nextPose() { @@ -141,7 +141,7 @@ public class TileEntityStatue public void setItemInArmorSlot(final @NotNull HumanArmorShape slot, final @Nullable ItemStack item) { this.armorPieces[slot.getSlotIndex()] = item; setChanged(); - this.notifyBlocksOfNeighborChange(); + this.updateNeighboringMatchers(); } @Override @@ -165,7 +165,7 @@ public class TileEntityStatue @Override public void setHeldItem(@Nullable ItemStack item) { this.heldItem = item; - this.notifyBlocksOfNeighborChange(); + this.updateNeighboringMatchers(); } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityThermalVent.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityThermalVent.java new file mode 100644 index 000000000..db0dfdbe0 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityThermalVent.java @@ -0,0 +1,33 @@ +package net.minecraft.core.block.entity; + +import com.mojang.nbt.tags.CompoundTag; +import net.minecraft.core.net.packet.Packet; +import net.minecraft.core.net.packet.PacketTileEntityData; +import org.jetbrains.annotations.NotNull; + +public class TileEntityThermalVent extends TileEntity implements TileEntity.AnimationTicking { + @Override public void readAdditionalData(@NotNull CompoundTag compoundTag) {} + @Override public void writeAdditionalData(@NotNull CompoundTag compoundTag) {} + + @Override + public Packet getDescriptionPacket() { + return new PacketTileEntityData(this); + } + + @Override + public void animationTick(int particleRenderDistance, double distSqr) { + if (this.worldObj == null) return; + if (distSqr > particleRenderDistance * particleRenderDistance * 0.75f * 0.75f) return; // Skip if further than 75% of the render distance in blocks + + int throttle = 4; + if (distSqr > 4096) { + throttle = 64; + } else if (distSqr > 1024) { + throttle = 16; + } + + if (this.worldObj.rand.nextInt(throttle) == 0) { + getBlock().animationTick(this.worldObj, this.tilePos, this.worldObj.rand); + } + } +} diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java index 189a41fec..ee783315d 100644 --- a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java +++ b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java @@ -1,7 +1,6 @@ package net.minecraft.core.block.piston; import net.minecraft.core.block.Blocks; -import net.minecraft.core.block.entity.TileEntity; import net.minecraft.core.block.material.Material; import net.minecraft.core.Global; import net.minecraft.core.block.Block; @@ -34,9 +33,11 @@ import org.joml.Vector3d; import org.joml.primitives.AABBd; import org.joml.primitives.AABBdc; +import java.util.Random; + import static net.minecraft.core.block.piston.PistonCommon.*; -public class BlockLogicPistonBase extends BlockLogic { +public class BlockLogicPistonBase extends BlockLogic implements BlockLogic.MatcherDataEquivalency.Masked { public final byte typeId; final byte pushLimit, pullLimit, crushLimit; @@ -64,13 +65,8 @@ public class BlockLogicPistonBase extends BlockLogic { } @Override - protected boolean isSameBlockForMatcher(final @NotNull Block other) { - return other.getLogic() instanceof BlockLogicPistonBase otherBase && otherBase.typeId == this.typeId; - } - - @Override - protected int getMatcherEquivalenceData(final int data) { - return data & ~DIRECTION.mask; + public int getMatcherDataEquivalencyMask() { + return ~DIRECTION.mask; } // Piston updates: @@ -430,11 +426,22 @@ public class BlockLogicPistonBase extends BlockLogic { this.signalUpdate(world, tilePos); } + @Override + public void updateTick(@NotNull World world, @NotNull TilePosc tilePos, @NotNull Random rand, boolean isRandomTick) { + if (isRandomTick || world.isClientSide) return; + this.signalUpdate(world, tilePos); + } + @Override public void onNeighborChanged(@NotNull World world, @NotNull TilePosc tilePos, final @NotNull Block block) { if (world.isClientSide) return; - final var data = fixLegacyBaseData(world, tilePos); - this.signalUpdate(world, tilePos, data); + final int data = fixLegacyBaseData(world, tilePos); + + final boolean powered = hasNeighborSignal(world, tilePos, Direction.fromId(DIRECTION.get(data))); + final boolean extended = IS_EXTENDED.bool(data); + if (powered != extended) { + world.scheduleBlockUpdate(tilePos, this.block, 1); + } } @Override diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java index e6b2c4d44..279fb98c3 100644 --- a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java +++ b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java @@ -11,9 +11,7 @@ import net.minecraft.core.block.material.Materials; import net.minecraft.core.block.support.FullSupport; import net.minecraft.core.block.support.ISupport; import net.minecraft.core.block.support.PartialSupport; -import net.minecraft.core.entity.player.Player; import net.minecraft.core.enums.EnumDropCause; -import net.minecraft.core.item.Item; import net.minecraft.core.item.ItemStack; import net.minecraft.core.util.helper.Direction; import net.minecraft.core.util.helper.Side; @@ -29,7 +27,7 @@ import org.joml.primitives.AABBdc; import static net.minecraft.core.block.piston.PistonCommon.*; -public class BlockLogicPistonHead extends BlockLogic { +public class BlockLogicPistonHead extends BlockLogic implements BlockLogic.MatcherDataEquivalency.Masked { // "Good lord. This really is our most NSFW update" -- Jonk // "Daaayyymmnn boy! He thick boy! That's a thick ass boy, DAYMN!" -- Melon @@ -43,8 +41,8 @@ public class BlockLogicPistonHead extends BlockLogic { } @Override - protected int getMatcherEquivalenceData(final int data) { - return data & ~DIRECTION.mask; + public int getMatcherDataEquivalencyMask() { + return ~DIRECTION.mask; } @Override @@ -138,7 +136,6 @@ public class BlockLogicPistonHead extends BlockLogic { if (!(world.getBlockType(bpos).getLogic() instanceof BlockLogicPistonBase)) return; int bdat = fixLegacyBaseData(world, bpos); if (PAIR_COMPARISON.get(data ^ bdat) != 0) return; - final var b = world.getBlockType(bpos); world.setBlockTypeNotify(bpos, Blocks.AIR); } diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonMoving.java b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonMoving.java index fc2e937fc..a898d12c1 100644 --- a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonMoving.java +++ b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonMoving.java @@ -139,7 +139,11 @@ public class BlockLogicPistonMoving extends BlockLogic { } @Override - public boolean isEquivalent(@NotNull World world, @NotNull TilePosc thisPos, @NotNull TilePosc thatPos) { + public boolean isEquivalent( + @NotNull WorldSource world, + @NotNull TilePosc thisPos, @NotNull TilePosc thatPos, + @NotNull Block thatBlock + ) { return false; } } diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/MovingLine.java b/game/core/src/main/java/net/minecraft/core/block/piston/MovingLine.java index d97eda610..f35b038e1 100644 --- a/game/core/src/main/java/net/minecraft/core/block/piston/MovingLine.java +++ b/game/core/src/main/java/net/minecraft/core/block/piston/MovingLine.java @@ -174,6 +174,7 @@ public final class MovingLine { if (world.isBlockNormalCube(tilePos)) direct_sig: { if (block == Blocks.BLOCK_REDSTONE) break direct_sig; if (block == Blocks.PUMPKIN_REDSTONE) break direct_sig; + if (block == Blocks.MATCHER) break direct_sig; if (block == Blocks.MATCHER_ACTIVE) break direct_sig; if (world.hasDirectSignal(queryPos.set(tilePos).add(d1), d1.side())) return true; if (world.hasDirectSignal(queryPos.set(tilePos).add(d2), d2.side())) return true; diff --git a/game/core/src/main/java/net/minecraft/core/current/util/BlockState.java b/game/core/src/main/java/net/minecraft/core/current/util/BlockState.java index 044e534f0..5470cc82f 100644 --- a/game/core/src/main/java/net/minecraft/core/current/util/BlockState.java +++ b/game/core/src/main/java/net/minecraft/core/current/util/BlockState.java @@ -19,7 +19,7 @@ public class BlockState { private final @NotNull Block block; private final int metadata; - public BlockState(Block block, int metadata) { + public BlockState(@NotNull Block block, int metadata) { this.block = block; this.metadata = metadata; } diff --git a/game/core/src/main/java/net/minecraft/core/current/wire/ConduitHandler.java b/game/core/src/main/java/net/minecraft/core/current/wire/ConduitHandler.java deleted file mode 100644 index 2e53c3f8d..000000000 --- a/game/core/src/main/java/net/minecraft/core/current/wire/ConduitHandler.java +++ /dev/null @@ -1,188 +0,0 @@ -package net.minecraft.core.current.wire; - -import net.minecraft.core.block.Block; -import net.minecraft.core.block.Blocks; -import net.minecraft.core.block.BlockLogicConduit; -import net.minecraft.core.util.helper.Side; -import net.minecraft.core.world.World; -import net.minecraft.core.world.pos.TilePos; -import net.minecraft.core.world.pos.TilePosc; - -import java.util.*; -import java.util.PriorityQueue; - - -/** - * One-Dimensional Implementation of Alternate Current for conduits.
    - * Handles the logic and updates for any given conduit network and seamlessly integrates with other redstone components.
    - * - * @author Melon Mojito (@melon_mojito) - */ -public class ConduitHandler { - - private final World world; - private boolean updating = false; - private final Queue updateQueue = new LinkedList<>(); - - private record ConduitNode(TilePos tilePos, int currentPower) {} - - public ConduitHandler(World world) { - this.world = world; - } - - public void onConduitUpdated(TilePosc pos) { - queueUpdate(new TilePos(pos)); - } - - public void onConduitAdded(TilePosc pos) { - queueUpdate(new TilePos(pos)); - } - - public void onConduitRemoved(TilePosc pos, int oldData) { - //update the sides this conduit was connected to - for (Side side : BlockLogicConduit.getOpenSides(oldData)) { - TilePos nPos = new TilePos(pos).add(side); - if (world.getBlockType(nPos) == Blocks.CONDUIT) { - queueUpdate(nPos); - } - } - } - - private void queueUpdate(TilePos pos) { - updateQueue.add(pos); - if (!updating) { - processQueue(); - } - } - - private void processQueue() { - updating = true; - try { - while (!updateQueue.isEmpty()) { - TilePos startPos = updateQueue.poll(); - // Ensure the block is still a conduit before updating the network, - // as it could have been broken while sitting in the queue. - if (world.getBlockType(startPos) == Blocks.CONDUIT) { - updateNetwork(startPos); - } - } - } finally { - updating = false; - } - } - - private void updateNetwork(TilePos startPos) { - //build the network - - if ((world.getBlockData(startPos) & BlockLogicConduit.STATE_MASK) == 0) { - return; - } - - Set network = new HashSet<>(); - Queue toSearch = new LinkedList<>(); - toSearch.add(startPos); - - while (!toSearch.isEmpty()) { - TilePos pos = toSearch.poll(); - if (network.add(pos)) { - int data = world.getBlockData(pos); - for (Side side : BlockLogicConduit.getOpenSides(data)) { - TilePos nPos = new TilePos(pos).add(side); - if (world.getBlockType(nPos) == Blocks.CONDUIT && - BlockLogicConduit.isSideOpen(world.getBlockData(nPos), side.opposite())) { - toSearch.add(nPos); - } - } - } - } - - //external sources: levers, buttons, etc. - Map externalPower = new HashMap<>(); - for (TilePos tilePos : network) { - int data = world.getBlockData(tilePos); - int currentPower = (data >> BlockLogicConduit.POWER_SHIFT) & BlockLogicConduit.POWER_MASK; - int maxExternalPower = 0; - - for (Side side : BlockLogicConduit.getOpenSides(data)) { - TilePos nTilePos = new TilePos(tilePos).add(side); - Block nBlockType = world.getBlockType(nTilePos); - - if (nBlockType != Blocks.CONDUIT) { - int external = BlockLogicConduit.getAndConvertNeighborSignal(world, tilePos, side); - - //break the recursive loop for redstone dust - if (nBlockType == Blocks.WIRE_REDSTONE) { - if (external < currentPower) { - external = 0; - } - } - - if (external > maxExternalPower) maxExternalPower = external; - } - } - externalPower.put(tilePos, maxExternalPower); - } - - //propagate from roots with priority - Map newPowerLevels = new HashMap<>(); - for (TilePos tilePos : network) newPowerLevels.put(tilePos, 0); - - java.util.PriorityQueue powerQueue = new PriorityQueue<>((a, b) -> Integer.compare(b.currentPower, a.currentPower)); - for (Map.Entry entry : externalPower.entrySet()) { - if (entry.getValue() > 0) { - powerQueue.add(new ConduitNode(entry.getKey(), entry.getValue())); - } - } - - while (!powerQueue.isEmpty()) { - ConduitNode node = powerQueue.poll(); - //ignore weaker path - if (node.currentPower <= newPowerLevels.get(node.tilePos)) continue; - - newPowerLevels.put(node.tilePos, node.currentPower); - - //propagate power down the line - if (node.currentPower > 1) { - int data = world.getBlockData(node.tilePos); - for (Side side : BlockLogicConduit.getOpenSides(data)) { - TilePos nPos = new TilePos(node.tilePos).add(side); - if (network.contains(nPos)) { - powerQueue.add(new ConduitNode(nPos, node.currentPower - 1)); - } - } - } - } - - Set blocksToNotify = new HashSet<>(); - for (TilePos tilePos : network) { - int oldData = world.getBlockData(tilePos); - int oldPower = (oldData >> BlockLogicConduit.POWER_SHIFT) & BlockLogicConduit.POWER_MASK; - int newPower = newPowerLevels.get(tilePos); - - if (oldPower != newPower) { - int state = oldData & BlockLogicConduit.STATE_MASK; - - world.setBlockData(tilePos, (newPower << BlockLogicConduit.POWER_SHIFT) | state); - world.markBlockNeedsUpdate(tilePos); - - //queue updates ONLY for blocks facing the open sides that ARE NOT conduits in this network - for (Side side : BlockLogicConduit.getOpenSides(state)) { - TilePos targetPos = new TilePos(tilePos).add(side); - if (!network.contains(targetPos)) { - blocksToNotify.add(targetPos); - } - } - } - } - - //notify all neighbors after the network is done with its logic/updates - for (TilePos nTilePos : blocksToNotify) { - Block neighborBlockType = world.getBlockType(nTilePos); - neighborBlockType.onNeighborChanged(world, nTilePos, Blocks.CONDUIT); - - if (neighborBlockType != Blocks.WIRE_REDSTONE) { - world.notifyBlocksOfNeighborChange(nTilePos, Blocks.CONDUIT); - } - } - } -} \ No newline at end of file diff --git a/game/core/src/main/java/net/minecraft/core/current/wire/Node.java b/game/core/src/main/java/net/minecraft/core/current/wire/Node.java index efabe2edc..c16b1d4ec 100644 --- a/game/core/src/main/java/net/minecraft/core/current/wire/Node.java +++ b/game/core/src/main/java/net/minecraft/core/current/wire/Node.java @@ -6,6 +6,7 @@ import net.minecraft.core.world.World; import net.minecraft.core.block.Blocks; import net.minecraft.core.world.pos.TilePos; import net.minecraft.core.world.pos.TilePosc; +import org.jetbrains.annotations.NotNull; import java.util.Arrays; @@ -61,7 +62,7 @@ public class Node { return this.pos.hashCode(); } - Node set(TilePosc pos, BlockState state, boolean clearNeighbors) { + Node set(TilePosc pos, @NotNull BlockState state, boolean clearNeighbors) { if (state.is(Blocks.WIRE_REDSTONE)) { throw new IllegalStateException("Cannot update a regular Node to a WireNode!"); } @@ -97,6 +98,13 @@ public class Node { return false; } + public boolean isWireAndIs(WireNode.Medium medium) { + if (this.isWire()) { + return this.asWire().medium == medium; + } + return false; + } + public boolean isConductor() { return (this.flags & CONDUCTOR) != 0; } diff --git a/game/core/src/main/java/net/minecraft/core/current/wire/WireConnection.java b/game/core/src/main/java/net/minecraft/core/current/wire/WireConnection.java index 86c6fa7bd..bb4fcfa04 100644 --- a/game/core/src/main/java/net/minecraft/core/current/wire/WireConnection.java +++ b/game/core/src/main/java/net/minecraft/core/current/wire/WireConnection.java @@ -4,27 +4,35 @@ package net.minecraft.core.current.wire; * This class represents a connection between some WireNode (the 'owner') and a * neighboring WireNode. Two wires are considered to be connected if power can * flow from one wire to the other (and/or vice versa). - * + * + *

    A node here may be any {@link WireNode.Medium}. + * Power crosses every connection with a uniform step of {@link WireHandler}'s + * POWER_STEP. + * * @author Space Walker + * @author MelonMojito */ public class WireConnection { /** The connected wire. */ final WireNode wire; - /** Cardinal direction to the connected wire. */ + /** Cardinal (or vertical) direction to the connected wire. */ final int iDir; /** True if the owner of the connection can provide power to the connected wire. */ final boolean offer; /** True if the connected wire can provide power to the owner of the connection. */ final boolean accept; + /** True if this connection should contribute to the owner's horizontal flow direction.*/ + final boolean flow; /** The next connection in the sequence. */ WireConnection next; - WireConnection(WireNode wire, int iDir, boolean offer, boolean accept) { + WireConnection(WireNode wire, int iDir, boolean offer, boolean accept, boolean flow) { this.wire = wire; this.iDir = iDir; this.offer = offer; this.accept = accept; + this.flow = flow; } } diff --git a/game/core/src/main/java/net/minecraft/core/current/wire/WireConnectionManager.java b/game/core/src/main/java/net/minecraft/core/current/wire/WireConnectionManager.java index 2de7e2267..12ba77d71 100644 --- a/game/core/src/main/java/net/minecraft/core/current/wire/WireConnectionManager.java +++ b/game/core/src/main/java/net/minecraft/core/current/wire/WireConnectionManager.java @@ -5,16 +5,20 @@ import net.minecraft.core.block.Blocks; import net.minecraft.core.current.wire.WireHandler.Directions; import net.minecraft.core.current.wire.WireHandler.NodeProvider; import net.minecraft.core.util.helper.Side; +import org.jetbrains.annotations.NotNull; import java.util.Arrays; import java.util.function.Consumer; +import static net.minecraft.core.current.wire.WireNode.Medium.CONDUIT; +import static net.minecraft.core.current.wire.WireNode.Medium.DUST; + public class WireConnectionManager { /** The owner of these connections. */ final WireNode owner; - /** The first connection for each cardinal direction. */ + /** The first connection for each cardinal direction. (Flow only) */ private final WireConnection[] heads; private WireConnection head; @@ -23,10 +27,7 @@ public class WireConnectionManager { /** The total number of connections. */ int total; - /** - * A 4 bit number that encodes which in direction(s) the owner has connections - * to other wires. - */ + /** A 4 bit number that encodes direction(s) the owner has flow connections with other dust wires. */ private int flowTotal; /** The direction of flow based connections to other wires. */ int iFlowDir; @@ -47,6 +48,19 @@ public class WireConnectionManager { clear(); } + if (owner.is(CONDUIT)) { + setConduit(nodes); + } else { + setDust(nodes); + addConduitLinks(nodes); + } + + if (total > 0) { + iFlowDir = WireHandler.FLOW_IN_TO_FLOW_OUT[flowTotal]; + } + } + + private void setDust(@NotNull NodeProvider nodes) { //tried my best to keep original AltCurrent naming schemes when changing code here Node ownerDown = nodes.getNeighbor(owner, Directions.DOWN); @@ -60,8 +74,8 @@ public class WireConnectionManager { for (int iDir = 0; iDir < Directions.HORIZONTAL.length; iDir++) { Node neighbor = nodes.getNeighbor(owner, iDir); - if (neighbor.isWire()) { - add(neighbor.asWire(), iDir, true, true); + if (neighbor.isWireAndIs(DUST)) { + add(neighbor.asWire(), iDir, true, true, true); continue; } @@ -77,10 +91,10 @@ public class WireConnectionManager { if (!blockedDown) { Node node = nodes.getNeighbor(neighbor, Directions.DOWN); - if (node.isWire()) { + if (node.isWireAndIs(DUST)) { boolean offerDown = belowIsConductor || (ownerDown.state.is(Blocks.CONDUIT) && !isConduitOpenTowards(ownerDown, iDir)); - add(node.asWire(), iDir, offerDown, true); + add(node.asWire(), iDir, offerDown, true, true); } } @@ -92,16 +106,46 @@ public class WireConnectionManager { if (!blockedUp) { Node node = nodes.getNeighbor(neighbor, Directions.UP); - if (node.isWire()) { + if (node.isWireAndIs(DUST)) { boolean acceptUp = sideIsConductor || (neighbor.state.is(Blocks.CONDUIT) && !isConduitOpenTowards(neighbor, iOppDir)); - add(node.asWire(), iDir, true, acceptUp); + add(node.asWire(), iDir, true, acceptUp, true); } } } + } - if (total > 0) { - iFlowDir = WireHandler.FLOW_IN_TO_FLOW_OUT[flowTotal]; + private void addConduitLinks(NodeProvider nodes) { + for (int iDir = 0; iDir < Directions.ALL.length; iDir++) { + Node neighbor = nodes.getNeighbor(owner, iDir); + + if (neighbor.isWireAndIs(CONDUIT) && isConduitOpenTowards(neighbor, Directions.iOpposite(iDir))) { + add(neighbor.asWire(), iDir, true, true, false); + } + } + } + + private void setConduit(NodeProvider nodes) { + for (int iDir = 0; iDir < Directions.ALL.length; iDir++) { + if (!isConduitOpenTowards(owner, iDir)) { + continue; + } + + Node neighbor = nodes.getNeighbor(owner, iDir); + + if (!neighbor.isWire()) { + continue; + } + + WireNode wireNeighbor = neighbor.asWire(); + + if (wireNeighbor.is(CONDUIT)) { + if (isConduitOpenTowards(neighbor, Directions.iOpposite(iDir))) { + add(wireNeighbor, iDir, true, true, false); + } + } else { + add(wireNeighbor, iDir, true, true, false); + } } } @@ -111,7 +155,7 @@ public class WireConnectionManager { * @param iDir The Alternate Current direction we are querying * @return true if the node is a conduit AND the port facing iDir is open */ - private boolean isConduitOpenTowards(Node node, int iDir) { + private boolean isConduitOpenTowards(@NotNull Node node, int iDir) { if (node.state.is(Blocks.CONDUIT)) { Side face = Side.NONE; face = switch (iDir) { @@ -140,8 +184,8 @@ public class WireConnectionManager { iFlowDir = -1; } - private void add(WireNode wire, int iDir, boolean offer, boolean accept) { - add(new WireConnection(wire, iDir, offer, accept)); + private void add(WireNode wire, int iDir, boolean offer, boolean accept, boolean flow) { + add(new WireConnection(wire, iDir, offer, accept, flow)); } private void add(WireConnection connection) { @@ -155,7 +199,8 @@ public class WireConnectionManager { total++; - if (heads[connection.iDir] == null) { + // Only horizontal dust-flow connections are tracked for flow ordering. + if (connection.flow && heads[connection.iDir] == null) { heads[connection.iDir] = connection; flowTotal |= (1 << connection.iDir); } @@ -173,11 +218,20 @@ public class WireConnectionManager { /** * Iterate over all connections. Use this method if the iteration order is - * important. + * important. Horizontal dust-flow connections are visited first, in the order + * determined by the flow direction, then any conduit/vertical connections. */ void forEach(Consumer consumer, int iFlowDir) { for (int iDir : WireHandler.CARDINAL_UPDATE_ORDERS[iFlowDir]) { for (WireConnection c = heads[iDir]; c != null && c.iDir == iDir; c = c.next) { + if (c.flow) { + consumer.accept(c); + } + } + } + + for (WireConnection c = head; c != null; c = c.next) { + if (!c.flow) { consumer.accept(c); } } diff --git a/game/core/src/main/java/net/minecraft/core/current/wire/WireHandler.java b/game/core/src/main/java/net/minecraft/core/current/wire/WireHandler.java index 9565b40a6..b6e901fe4 100644 --- a/game/core/src/main/java/net/minecraft/core/current/wire/WireHandler.java +++ b/game/core/src/main/java/net/minecraft/core/current/wire/WireHandler.java @@ -1,6 +1,8 @@ package net.minecraft.core.current.wire; import net.minecraft.core.block.BlockLogicConduit; +import net.minecraft.core.block.BlockLogicMatcher; +import net.minecraft.core.block.BlockLogicVeryRotatable; import net.minecraft.core.block.BlockLogicWireRedstone; import net.minecraft.core.block.Block; import net.minecraft.core.block.Blocks; @@ -17,6 +19,8 @@ import java.util.Map; import java.util.Queue; import java.util.function.Consumer; +import static net.minecraft.core.current.wire.WireNode.Medium.CONDUIT; + /** * This class handles power changes for redstone wire. The algorithm was * designed with the following goals in mind: @@ -339,7 +343,18 @@ public class WireHandler { * cache and update it. */ private @NotNull Node getNextNode(@NotNull TilePosc pos, @NotNull BlockState state) { - return state.is(Blocks.WIRE_REDSTONE) ? new WireNode(this.world, pos, state) : getNextNode().set(pos, state, true); + return isPowerNodeState(state) ? new WireNode(this.world, pos, state) : getNextNode().set(pos, state, true); + } + + /** closed and inert conduits carry nothing and are treated as ordinary blocks. */ + private static boolean isPowerNodeState(@NotNull BlockState state) { + if (state.is(Blocks.WIRE_REDSTONE)) { + return true; + } + if (state.is(Blocks.CONDUIT)) { + return BlockLogicConduit.getOpenSides(state.get()).length > 0; + } + return false; } /** @@ -380,7 +395,7 @@ public class WireHandler { BlockState state = WorldHelper.getBlockState(this.world, pos); boolean wasWire = node.isWire(); - boolean isWire = state.is(Blocks.WIRE_REDSTONE); + boolean isWire = isPowerNodeState(state); if (wasWire != isWire) { return getNextNode(pos, state); @@ -680,7 +695,7 @@ public class WireHandler { wire.discovered = true; wire.searched = false; - if (!wire.removed && !wire.shouldBreak && !wire.state.canSurvive(this.world, wire.pos)) { + if (!wire.is(CONDUIT) && !wire.removed && !wire.shouldBreak && !wire.state.canSurvive(this.world, wire.pos)) { wire.shouldBreak = true; } @@ -732,7 +747,7 @@ public class WireHandler { int power = Math.max(POWER_MIN, neighbor.virtualPower - POWER_STEP); int iOpp = Directions.iOpposite(connection.iDir); - wire.offerPower(power, iOpp); + wire.offerPower(power, iOpp, connection.flow); } }); } @@ -741,11 +756,16 @@ public class WireHandler { * Determine the redstone signal the given wire receives from non-wire * components and update the virtual power accordingly. */ - private void findExternalPower(WireNode wire) { + private void findExternalPower(@NotNull WireNode wire) { if (wire.removed || wire.shouldBreak || wire.externalPower >= POWER_MAX) { return; } + if (wire.is(CONDUIT)) { + findExternalPowerConduit(wire); + return; + } + int maxExternalPower = POWER_MIN; for (int iDir = 0; iDir < Directions.ALL.length; iDir++) { @@ -755,32 +775,6 @@ public class WireHandler { continue; } - //conduit logic - if (neighboringNode.state.is(Blocks.CONDUIT)) { - int cData = neighboringNode.state.get(); - - Side conduitFace = getSide(iDir); - - if (BlockLogicConduit.isSideOpen(cData, conduitFace)) { - int cStrength = cData / BlockLogicConduit.STATE_COUNT; - int convertedStrength = BlockLogicConduit.signalConverter(cStrength, true); - - //step down the signal strength when passing from conduit to wire - convertedStrength = Math.max(0, convertedStrength - 1); - - //if signal is less than current power, set to 0 - if (convertedStrength < wire.currentPower) { - convertedStrength = 0; - } - - if (convertedStrength > maxExternalPower) { - maxExternalPower = convertedStrength; - } - } - //this continue took me hours to find. I hate my life - continue; - } - if (neighboringNode.isConductor() && hasDirectSignalTo(wire, neighboringNode, Directions.iOpposite(iDir))) { maxExternalPower = POWER_MAX; } @@ -796,19 +790,34 @@ public class WireHandler { } } - private static @NotNull Side getSide(int iDir) { - Side wireSide = Side.NONE; - wireSide = switch (iDir) { - case Directions.WEST -> Side.WEST; - case Directions.NORTH -> Side.NORTH; - case Directions.EAST -> Side.EAST; - case Directions.SOUTH -> Side.SOUTH; - case Directions.DOWN -> Side.BOTTOM; - case Directions.UP -> Side.TOP; - default -> wireSide; - }; + /** + * Determine the redstone signal a conduit node receives from non-network + * components through its open faces. Adjacent dust and conduits are skipped + * here because they are network nodes and reach this conduit via connections. + */ + private void findExternalPowerConduit(@NotNull WireNode conduit) { + int maxExternalPower = POWER_MIN; + + int data = conduit.state.get(); + for (Side side : BlockLogicConduit.getOpenSides(data)) { + TilePos nPos = new TilePos(conduit.pos).add(side); + Block nType = this.world.getBlockType(nPos); + + if (nType == Blocks.WIRE_REDSTONE || nType == Blocks.CONDUIT) { + continue; + } + + int external = BlockLogicConduit.getAndConvertNeighborSignal(this.world, conduit.pos, side); + if (external > maxExternalPower) { + maxExternalPower = external; + } + } - return wireSide.opposite(); + conduit.externalPower = conduit.clampPower(maxExternalPower); + + if (conduit.externalPower > conduit.virtualPower) { + conduit.virtualPower = conduit.externalPower; + } } /** @@ -841,8 +850,19 @@ public class WireHandler { * Determine whether the given wire receives a direct signal from non-wire * components through the given conductor node. */ - private boolean hasDirectSignalTo(WireNode wire, Node node, int except) { + private boolean hasDirectSignalTo(WireNode wire, @NotNull Node node, int except) { + if (node.state.is(Blocks.BLOCK_REDSTONE) || node.state.is(Blocks.MATCHER) || node.state.is(Blocks.MATCHER_ACTIVE)) { + return false; + } + Direction excludedFace = node.state.is(Blocks.PUMPKIN_REDSTONE) + ? BlockLogicVeryRotatable.metaToDirection(node.state.get()) + : null; + for (int iDir : Directions.I_EXCEPT[except]) { + if (Directions.ALL[iDir] == excludedFace) { + continue; + } + Node neighbor = getNeighbor(node, iDir); if (neighbor.state.is(Blocks.WIRE_REDSTONE) || neighbor.state.is(Blocks.CONDUIT)) { @@ -860,14 +880,14 @@ public class WireHandler { /** * Check if the given wire needs to update its state in the world. */ - private boolean needsUpdate(WireNode wire) { + private boolean needsUpdate(@NotNull WireNode wire) { return wire.removed || wire.shouldBreak || wire.virtualPower != wire.currentPower; } /** * Queue the given wire for the breadth-first search as a root. */ - private void searchRoot(WireNode wire) { + private void searchRoot(@NotNull WireNode wire) { int iBackupFlowDir; if (wire.connections.iFlowDir < 0) { @@ -985,15 +1005,18 @@ public class WireHandler { discover(neighbor); findPower(neighbor, false); - // If power from neighboring wires has decreased, check for power - // from non-wire components so as to determine how low power can - // fall. + /* If power from neighboring wires has decreased, check for power + from non-wire components to determine how low power can + fall. */ if (neighbor.virtualPower < neighbor.currentPower) { findExternalPower(neighbor); } if (needsUpdate(neighbor)) { - search(neighbor, false, connection.iDir); + /* The backup flow direction must be a horizontal direction. + Conduit/vertical connections are non-flow and may carry a vertical + iDir, so they fall back to a default rather than corrupting the flow. */ + search(neighbor, false, connection.flow ? connection.iDir : Directions.WEST); } }, wire.iFlowDir); } @@ -1057,6 +1080,10 @@ public class WireHandler { if (neighborWire != null) { updateBlock(node, neighborWire.state.getBlockType()); + + if (neighborWire.is(CONDUIT)) { + this.world.notifyBlocksOfNeighborChange(node.pos, Blocks.CONDUIT); + } } } } @@ -1096,7 +1123,7 @@ public class WireHandler { int power = Math.max(POWER_MIN, wire.virtualPower - POWER_STEP); int iDir = connection.iDir; - if (neighbor.offerPower(power, iDir)) { + if (neighbor.offerPower(power, iDir, connection.flow)) { queueWire(neighbor); } }, wire.iFlowDir); @@ -1105,16 +1132,56 @@ public class WireHandler { /** * Queue block updates to nodes around the given wire. */ - private void queueNeighbors(WireNode wire) { - forEachNeighbor(wire, neighbor -> { - queueNeighbor(neighbor, wire); - }); + private void queueNeighbors(@NotNull WireNode wire) { + if (wire.is(CONDUIT)) { + queueConduitNeighbors(wire); + } else { + forEachNeighbor(wire, neighbor -> { + queueNeighbor(neighbor, wire); + }); + } + } + + /** + * Queue block updates for the real components a conduit touches: the blocks on + * its open faces, plus matchers on any side. + * Network nodes are skipped, since power reaches them via connections. + */ + private void queueConduitNeighbors(@NotNull WireNode conduit) { + int data = conduit.state.get(); + + for (int iDir = 0; iDir < Directions.ALL.length; iDir++) { + Node neighbor = getNeighbor(conduit, iDir); + + if (neighbor.isWire()) { + continue; + } + + boolean isOpen = BlockLogicConduit.isSideOpen(data, iDirToSide(iDir)); + boolean isMatcher = neighbor.state.getBlockType().getLogic() instanceof BlockLogicMatcher; + + if (isOpen || isMatcher) { + queueNeighbor(neighbor, conduit); + } + } + } + + private static @NotNull Side iDirToSide(int iDir) { + return switch (iDir) { + case Directions.WEST -> Side.WEST; + case Directions.NORTH -> Side.NORTH; + case Directions.EAST -> Side.EAST; + case Directions.SOUTH -> Side.SOUTH; + case Directions.DOWN -> Side.BOTTOM; + case Directions.UP -> Side.TOP; + default -> Side.NONE; + }; } /** * Queue the given node for an update from the given neighboring wire. */ - private void queueNeighbor(Node node, WireNode neighborWire) { + private void queueNeighbor(@NotNull Node node, WireNode neighborWire) { // Updates to wires are queued when power is transmitted. if (!node.isWire()) { node.neighborWire = neighborWire; @@ -1139,7 +1206,7 @@ public class WireHandler { /** * Emit a block update to the given node. */ - private void updateBlock(Node node, Block neighborBlock) { + private void updateBlock(@NotNull Node node, Block neighborBlock) { TilePos pos = node.pos; BlockState state = WorldHelper.getBlockState(this.world, pos); diff --git a/game/core/src/main/java/net/minecraft/core/current/wire/WireNode.java b/game/core/src/main/java/net/minecraft/core/current/wire/WireNode.java index 0f8529fca..02e94bb74 100644 --- a/game/core/src/main/java/net/minecraft/core/current/wire/WireNode.java +++ b/game/core/src/main/java/net/minecraft/core/current/wire/WireNode.java @@ -1,6 +1,7 @@ package net.minecraft.core.current.wire; import com.mojang.logging.LogUtils; +import net.minecraft.core.block.BlockLogicConduit; import net.minecraft.core.block.BlockLogicWireRedstone; import net.minecraft.core.block.Blocks; import net.minecraft.core.current.util.BlockState; @@ -8,8 +9,12 @@ 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.pos.TilePosc; +import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; +import static net.minecraft.core.current.wire.WireNode.Medium.CONDUIT; +import static net.minecraft.core.current.wire.WireNode.Medium.DUST; + /** * A WireNode is a Node that represents a wire in the world. It stores all the * information about the wire that the WireHandler needs to calculate power @@ -20,6 +25,15 @@ import org.slf4j.Logger; public class WireNode extends Node { private static final Logger LOGGER = LogUtils.getLogger(); + /** Which kind of power-carrying block this node represents. */ + public enum Medium {DUST, CONDUIT} + + final Medium medium; + /** + * The highest power level this node can actually store. + */ + final int powerCeiling; + final WireConnectionManager connections; /** The power level this wire currently holds in the world. */ @@ -49,21 +63,31 @@ public class WireNode extends Node { /** The next wire in the simple queue. */ WireNode next_wire; - WireNode(World world, TilePosc pos, BlockState state) { + WireNode(World world, TilePosc pos, @NotNull BlockState state) { super(world); this.pos = new TilePos(pos); this.state = state; - this.connections = new WireConnectionManager(this); + this.medium = state.is(Blocks.CONDUIT) ? CONDUIT : DUST; + + if (is(CONDUIT)) { + int data = state.get(); + this.powerCeiling = BlockLogicConduit.isCap(data) ? 1 : BlockLogicWireRedstone.SIGNAL_MAX; + this.virtualPower = this.currentPower = BlockLogicConduit.getPower(data); + this.direction = 0; + } else { + this.powerCeiling = BlockLogicWireRedstone.SIGNAL_MAX; + this.virtualPower = this.currentPower = this.state.get() & BlockLogicWireRedstone.MASK_POWER; + this.direction = this.state.get() & BlockLogicWireRedstone.MASK_DIRECTION; + } - this.virtualPower = this.currentPower = this.state.get() & BlockLogicWireRedstone.MASK_POWER; - this.direction = this.state.get() & BlockLogicWireRedstone.MASK_DIRECTION; + this.connections = new WireConnectionManager(this); this.priority = priority(); } @Override - Node set(TilePosc pos, BlockState state, boolean clearNeighbors) { + Node set(TilePosc pos, @NotNull BlockState state, boolean clearNeighbors) { throw new UnsupportedOperationException("Cannot update a WireNode!"); } @@ -82,17 +106,30 @@ public class WireNode extends Node { return this; } - boolean offerPower(int power, int iDir) { + //leave non-inline for future proofing (any other mediums added) + boolean is(Medium medium) { + return this.medium == medium; + } + + /** Clamp a power level to what this node is actually able to hold. */ + int clampPower(int power) { + return Math.min(power, this.powerCeiling); + } + + boolean offerPower(int power, int iDir, boolean recordFlow) { if (this.removed || this.shouldBreak) { return false; } + if (power == this.virtualPower) { - this.flowIn |= (1 << iDir); + if (recordFlow) { + this.flowIn |= (1 << iDir); + } return false; } if (power > this.virtualPower) { this.virtualPower = power; - this.flowIn = (1 << iDir); + this.flowIn = recordFlow ? (1 << iDir) : 0; return true; } @@ -107,9 +144,23 @@ public class WireNode extends Node { this.state = WorldHelper.getBlockState(this.world, this.pos); + if (is(CONDUIT)) { + if (!this.state.is(Blocks.CONDUIT)) { + LOGGER.warn("Tried to update power of a conduit that is no longer there! This should never happen!", new RuntimeException()); + return false; // we should never get here + } + + int oldData = this.state.get(); + int newData = BlockLogicConduit.withPower(oldData, MathHelper.clamp(this.virtualPower, BlockLogicWireRedstone.SIGNAL_MIN, BlockLogicWireRedstone.SIGNAL_MAX)); + this.currentPower = BlockLogicConduit.getPower(newData); + this.state = this.state.set(newData); + + return WorldHelper.setWireState(this.world, this.pos, this.state); + } + if (!this.state.is(Blocks.WIRE_REDSTONE)) { LOGGER.warn("Tried to update power of non redstone dust! This should never happen!", new RuntimeException()); - return false; // we should never get here + return false; // we should also never get here } if (this.shouldBreak) { diff --git a/game/core/src/main/java/net/minecraft/core/entity/Entity.java b/game/core/src/main/java/net/minecraft/core/entity/Entity.java index d23c84461..06ce3d305 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/Entity.java +++ b/game/core/src/main/java/net/minecraft/core/entity/Entity.java @@ -109,6 +109,11 @@ public abstract class Entity public int pushesThisTick; public int acidJumpCooldown = 0; + // When true, move() writes the moved bounding box back into x/y/z even for a client-side Mob. + // Used while a client locally simulates a vehicle it is driving so position-derived + // logic like limbs, etc. tracks the real movement instead of staying frozen. + public boolean locallySimulated = false; + // Vehicle public @Nullable IVehicle vehicle; private double entityRiderPitchDelta; @@ -167,6 +172,7 @@ public abstract class Entity // Data public boolean sendAdditionalData = false; + public boolean additionalDataChanged = false; protected final @NotNull SynchedEntityData entityData = new SynchedEntityData(); public Entity(final @NotNull World world) { @@ -606,7 +612,7 @@ public abstract class Entity } } //fix for entity jitter when blasted by cannonballs (can cause some client-side jitter when entity is under a ceiling. unsure exactly why) - if (!this.world.isClientSide || this instanceof Player || !(this instanceof Mob)) { + if (!this.world.isClientSide || this instanceof Player || !(this instanceof Mob) || this.locallySimulated) { this.x = (this.bb.minX + this.bb.maxX) / 2D; this.y = (this.bb.minY + (double) this.heightOffset) - (double) this.ySlideOffset; this.z = (this.bb.minZ + this.bb.maxZ) / 2D; @@ -1144,6 +1150,10 @@ public abstract class Entity return isPickable(); } + public boolean passesThroughRiderTargeting(@Nullable ItemStack heldItem) { + return false; + } + public boolean isPushable() { return false; } @@ -1193,6 +1203,8 @@ public abstract class Entity tag.putShort("Air", (short) this.airSupply); tag.putBoolean("OnGround", this.onGround); tag.putFloat("PushTime", this.pushTime); + //MC-2025 fix by @theosib and @Kademlia. Persists the exact bounding box so it can be restored on load instead of being recomputed from position. + tag.put("AABB", newDoubleList(new double[]{this.bb.minX, this.bb.minY, this.bb.minZ, this.bb.maxX, this.bb.maxY, this.bb.maxZ})); addAdditionalSaveData(tag); } @@ -1226,6 +1238,10 @@ public abstract class Entity setPos(this.x, this.y, this.z); setRot(this.yRot, this.xRot); readAdditionalSaveData(tag); + if (tag.containsKey("AABB")) {ListTag aabbTag = tag.getList("AABB"); + this.bb.setMin(((DoubleTag) aabbTag.tagAt(0)).getValue(), ((DoubleTag) aabbTag.tagAt(1)).getValue(), ((DoubleTag) aabbTag.tagAt(2)).getValue()); + this.bb.setMax(((DoubleTag) aabbTag.tagAt(3)).getValue(), ((DoubleTag) aabbTag.tagAt(4)).getValue(), ((DoubleTag) aabbTag.tagAt(5)).getValue()); + } } public final @Nullable NamespaceID getDispatcherId() { @@ -1585,12 +1601,14 @@ public abstract class Entity return true; } - public void handleSpecialVehicleControl() { + public void handleSpecialVehicleControl() {} - } + public void sendSpecialVehiclePacket() {} - public void sendSpecialVehiclePacket() { + public void handleControlDirect(double xd, double yd, double zd, float yRot) {} + public boolean relaysVehicleControl() { + return false; } public boolean deferVehicleBehavior() { diff --git a/game/core/src/main/java/net/minecraft/core/entity/EntityFishingBobber.java b/game/core/src/main/java/net/minecraft/core/entity/EntityFishingBobber.java index 3de7f1161..22b02aef4 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/EntityFishingBobber.java +++ b/game/core/src/main/java/net/minecraft/core/entity/EntityFishingBobber.java @@ -177,9 +177,7 @@ public class EntityFishingBobber extends Entity { double distance = MathHelper.sqrt(dx * dx + dy * dy + dz * dz); if (distance > 10) { double scale = 0.01D; - this.hookedEntity.xd += dx * scale; - this.hookedEntity.yd += dy * scale; - this.hookedEntity.zd += dz * scale; + this.hookedEntity.fling(dx * scale, dy * scale, dz * scale, 0f); } return; } @@ -374,9 +372,7 @@ public class EntityFishingBobber extends Entity { double dz = this.owner.z - this.z; double distance = MathHelper.sqrt(dx * dx + dy * dy + dz * dz); double scale = 0.1D; - this.hookedEntity.xd += dx * scale; - this.hookedEntity.yd += dy * scale + (double) MathHelper.sqrt(distance) * 0.08D; - this.hookedEntity.zd += dz * scale; + this.hookedEntity.fling(dx * scale, dy * scale + (double) MathHelper.sqrt(distance) * 0.08D, dz * scale, 0f); damage = 3; } else if (this.ticksCatchable > 0) { if (!this.world.isClientSide) { diff --git a/game/core/src/main/java/net/minecraft/core/entity/EntityItem.java b/game/core/src/main/java/net/minecraft/core/entity/EntityItem.java index 67cee9925..9f1ca5610 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/EntityItem.java +++ b/game/core/src/main/java/net/minecraft/core/entity/EntityItem.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.Objects; import com.mojang.nbt.tags.CompoundTag; +import net.minecraft.core.Global; import net.minecraft.core.achievement.Achievements; import net.minecraft.core.achievement.stat.StatList; import net.minecraft.core.block.Block; @@ -20,6 +21,7 @@ import net.minecraft.core.item.ItemStack; import net.minecraft.core.item.tag.ItemTags; import net.minecraft.core.util.helper.DamageType; import net.minecraft.core.util.helper.Direction; +import net.minecraft.core.util.helper.LightIndexHelper; import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePos; @@ -38,6 +40,33 @@ public class EntityItem extends Entity public float bobOffset; public int basketPickupDelay = 0; public static boolean enableItemClumping = true; + private static final int BASE_DESPAWN_TICKS = 10 * 60 * 20; + private static final int BASE_FADE_TICKS = 2 * 60 * 20; + public static final float DESPAWN_ALPHA_THRESHOLD = 0.01f; + private static final int DESPAWN_FORCE_REMOVE_BUFFER = 20; + + public static int getDespawnFadeTicks(final int lifetime) { + if (lifetime <= 0) { + return 0; + } + return Math.max(1, lifetime * BASE_FADE_TICKS / BASE_DESPAWN_TICKS); + } + + public static float getDespawnFadeAlpha(final int age, final int lifetime, final float partialTick) { + if (lifetime < 0) { + return 1.0f; + } + final float adjustedAge = age + partialTick; + final int fadeWindow = getDespawnFadeTicks(lifetime); + final float fadeStart = lifetime - fadeWindow; + if (adjustedAge <= fadeStart) { + return 1.0f; + } + final float elapsed = adjustedAge - fadeStart; + final float toDeath = 1.0f - elapsed / fadeWindow; + final double period = 6.8 + 1.2 * toDeath; + return (float) (0.5 + 0.5 * Math.cos((elapsed * Math.PI) / period)); + } public EntityItem(@NotNull World world, double x, double y, double z, @NotNull ItemStack itemstack) { super(world); @@ -131,9 +160,13 @@ public class EntityItem extends Entity } this.age++; - if(this.age >= this.lifetime && this.lifetime >= 0 && !this.item.getItem().hasTag(ItemTags.IS_PERSISTENT)) // Negative lifetime indicates items should last forever - { - remove(); + if (this.lifetime >= 0 && !this.item.getItem().hasTag(ItemTags.IS_PERSISTENT)) { + if (this.age >= this.lifetime) { + if (getDespawnFadeAlpha(this.age, this.lifetime, 0f) <= DESPAWN_ALPHA_THRESHOLD + || this.age >= this.lifetime + DESPAWN_FORCE_REMOVE_BUFFER) { + remove(); + } + } } } @@ -207,6 +240,9 @@ public class EntityItem extends Entity player.inventory.insertItem(this.item, true); if(this.item.stackSize < previousStackSize) { + if(this.item.stackSize > 0) { + this.additionalDataChanged = true; + } if(this.item.itemID < 16384) { Block b = Blocks.blocksList[this.item.itemID]; if(b != null && b.getLogic() instanceof BlockLogicLog) { @@ -369,7 +405,7 @@ public class EntityItem extends Entity this.yd += 0.001; } - if(blockUnderItem == Blocks.MESH) + if(blockUnderItem == Blocks.MESH || blockUnderItem == Blocks.SPIKES) { this.yd -= 0.02D; } @@ -383,6 +419,7 @@ public class EntityItem extends Entity } } } + this.yd -= 0.02D; } //gravity out of water else @@ -410,12 +447,34 @@ public class EntityItem extends Entity public boolean isBeingSiphoned(){ return siphonDirection != Direction.NONE; } - + + @Override + public byte calcLightIndex(float partialTick) { + if (Global.accessor.isFullbrightEnabled()) return LightIndexHelper.lightIndex2i(15, 15); + TilePos blockPos = new TilePos(this.x, this.y - this.heightOffset + this.ySlideOffset + this.bbHeight * 0.66D, this.z); + + byte lightIndex = 0; + if (this.world.getBlockLitInteriorSurface(blockPos) || this.world.getBlockType(blockPos).isSolidRender()) { + TilePos queryPos = new TilePos(); + + lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.up(queryPos))); + lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.west(queryPos))); + lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.east(queryPos))); + lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.south(queryPos))); + lightIndex = LightIndexHelper.max(lightIndex, this.world.getSavedLightIndex(blockPos.north(queryPos))); + } else { + lightIndex = this.world.getSavedLightIndex(blockPos); + } + + return lightIndex; + } + private static void combineItems(EntityItem entityItem1, EntityItem entityItem2) { entityItem1.item.stackSize += entityItem2.item.stackSize; entityItem2.item.stackSize = 0; entityItem1.age = Math.min(entityItem1.age, entityItem2.age); entityItem1.pickupDelay = Math.max(entityItem1.pickupDelay, entityItem2.pickupDelay); + entityItem1.additionalDataChanged = true; entityItem2.remove(); } } diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobPig.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobPig.java index de875eca7..26ae0ce10 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobPig.java +++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobPig.java @@ -5,6 +5,7 @@ import net.minecraft.core.achievement.Achievements; import net.minecraft.core.block.Blocks; import net.minecraft.core.block.tag.BlockTags; import net.minecraft.core.entity.AgedMob; +import net.minecraft.core.entity.Entity; import net.minecraft.core.entity.EntityLightning; import net.minecraft.core.entity.MobAge; import net.minecraft.core.entity.monster.MobZombiePig; @@ -13,6 +14,7 @@ import net.minecraft.core.item.ItemStack; import net.minecraft.core.item.Items; import com.mojang.nbt.tags.CompoundTag; import net.minecraft.core.util.collection.NamespaceID; +import net.minecraft.core.util.helper.DamageType; import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.world.World; import net.minecraft.core.world.pos.TilePos; @@ -26,6 +28,7 @@ public class MobPig // implements AgedMob { public static final int DATA_SADDLE_ID = 16; + public static final int DATA_SIT_ID = 17; public List burningMobDrops = new ArrayList<>(); // private final @NotNull MobAge age; @@ -50,6 +53,7 @@ public class MobPig @Override protected void defineSynchedData() { this.entityData.define(DATA_SADDLE_ID, (byte) 0, Byte.class); + this.entityData.define(DATA_SIT_ID, (byte) 0, Byte.class); } @Override @@ -57,6 +61,7 @@ public class MobPig { super.addAdditionalSaveData(tag); tag.putBoolean("Saddle", getSaddled()); + tag.putBoolean("Sit", getSitting()); // this.age.writeTag(tag); } @@ -65,16 +70,208 @@ public class MobPig { super.readAdditionalSaveData(tag); setSaddled(tag.getBoolean("Saddle")); + setSitting(tag.getBoolean("Sit")); // this.age.readTag(tag); } + @Override + public boolean save(@NotNull CompoundTag tag) { + if (this.passenger instanceof Player) { + return false; + } + return super.save(tag); + } + + private static final double MAX_CONTROL_HORIZONTAL_STEP = 1.0D; + private static final double MAX_CONTROL_VERTICAL_STEP = 2.0D; + + private double controlTargetX; + private double controlTargetY; + private double controlTargetZ; + private boolean hasControlTarget; + private float pendingFallDistance; + + private double lastStandingY; + private boolean wasGrounded; + private boolean airborneFromJump; + + private static final float JUMP_LANDING_KEEP = 0.1f; + private static final float WALL_HIT_SPEED_LOSS = 0.12f; + + private static final float NORMAL_MOVE_SPEED = 0.7f; + private static final float PANIC_MOVE_SPEED = 1.3f; + private static final int PANIC_DURATION_TICKS = 60; + private int panicTicks = 0; + + public float lookFadeAlpha = 1.0f; + public long lookFadeLastRenderNanos = 0L; + + @Override + public void setPassenger(Entity passenger) { + super.setPassenger(passenger); + this.hasControlTarget = false; + this.airborneFromJump = false; + if (passenger != null) { + setSitting(false); + this.panicTicks = 0; + } + if (passenger == null) { + this.xd = 0.0D; + this.yd = 0.0D; + this.zd = 0.0D; + this.speedProgress = 0f; + this.fallDistance = 0f; + if (getSaddled()) { + setSitting(true); + } + } + } + @Override public void onLivingUpdate() { + if (this.passenger instanceof Player driver) { + if (!driver.lerpVehicleMotion()) { + this.newPosRotationIncrements = 0; + boolean wasMultiplayerEntity = this.isMultiplayerEntity; + boolean wasLocallySimulated = this.locallySimulated; + this.isMultiplayerEntity = false; + this.locallySimulated = true; + super.onLivingUpdate(); + this.isMultiplayerEntity = wasMultiplayerEntity; + this.locallySimulated = wasLocallySimulated; + driver.sendSpecialVehiclePacket(); + return; + } + if (!this.world.isClientSide) { + this.target = null; + this.pathToEntity = null; + this.yBodyRot = this.yRot; + this.xRot = driver.xRot; + this.fallDistance = 0f; + if (this.hasControlTarget) { + double trueY = this.bb.minY + (double) this.heightOffset; + double dx = MathHelper.clamp(this.controlTargetX - this.x, -MAX_CONTROL_HORIZONTAL_STEP, MAX_CONTROL_HORIZONTAL_STEP); + double dy = MathHelper.clamp(this.controlTargetY - trueY, -MAX_CONTROL_VERTICAL_STEP, MAX_CONTROL_VERTICAL_STEP); + double dz = MathHelper.clamp(this.controlTargetZ - this.z, -MAX_CONTROL_HORIZONTAL_STEP, MAX_CONTROL_HORIZONTAL_STEP); + move(dx, dy, dz); + } + this.xd = 0.0D; + this.yd = 0.0D; + this.zd = 0.0D; + return; + } + } super.onLivingUpdate(); // this.age.tick(this.world); } + @Override + public void handleControlDirect(double x, double y, double z, float yRot) { + this.yRot = yRot; + this.yBodyRot = yRot; + this.controlTargetX = x; + this.controlTargetY = y; + this.controlTargetZ = z; + this.hasControlTarget = true; + } + + @Override + public boolean isInWall() { + if (!this.world.isClientSide && this.passenger instanceof Player) { + return false; + } + return super.isInWall(); + } + + @Override + public void move(double dx, double dy, double dz) { + if (!hasNoPhysics() && this.passenger instanceof Player rider && rider.bb.maxY > this.bb.maxY) { + final double pigHeight = this.bb.maxY - this.bb.minY; + this.bb.maxY = rider.bb.maxY; + super.move(dx, dy, dz); + this.bb.maxY = this.bb.minY + pigHeight; + return; + } + super.move(dx, dy, dz); + } + + @Override + public boolean passesThroughRiderTargeting(ItemStack heldItem) { + boolean canFeed = heldItem != null + && (heldItem.itemID == Blocks.MUSHROOM_BROWN.id() || heldItem.itemID == Blocks.MUSHROOM_RED.id()) + && getHealth() < getMaxHealth(); + return !canFeed; + } + + @Override + public boolean hurt(Entity attacker, int damage, DamageType type) { + if (attacker != null && attacker == this.passenger) { + return false; + } + boolean hurt = super.hurt(attacker, damage, type); + if (hurt) { + this.speedProgress = 0f; + if (!this.world.isClientSide && this.passenger == null && (getSitting() || this.panicTicks > 0)) { + setSitting(false); + this.panicTicks = PANIC_DURATION_TICKS; + } + } + return hurt; + } + + @Override + public void handleEntityEvent(byte event, float attackedAtYaw) { + super.handleEntityEvent(event, attackedAtYaw); + if (event == 2) { + this.speedProgress = 0f; + } + } + + @Override + protected void jump() { + super.jump(); + if (this.passenger instanceof Player) { + this.airborneFromJump = true; + } + } + + @Override + public void fling(double xd, double yd, double zd, float pushTime) { + super.fling(xd, yd, zd, pushTime); + if (!this.world.isClientSide && this.passenger instanceof Player rider) { + rider.onVehicleFlung(this); + } + } + + @Override + public Entity ejectRider() { + Entity rider = super.ejectRider(); + this.xd = 0.0D; + this.yd = 0.0D; + this.zd = 0.0D; + this.speedProgress = 0f; + this.fallDistance = 0f; + this.airborneFromJump = false; + if (getSaddled()) { + setSitting(true); + } + return rider; + } + + /** + * Drops <= 0.5 of a block lose no speed, past that the speed loss starts at ~25% and curves up to ~85% at a full + * block, and capped at 95% around 1.5 blocks. + */ + private static float landingSpeedKeep(float netDrop) { + if (netDrop <= 0.5f) { + return 1f; + } + float x = (netDrop - 0.5f) / 0.5f; + float loss = 0.25f + 0.6f * x * x; + return MathHelper.clamp(1f - loss, 0.05f, 1f); + } + @Override protected void updateAI() { if (this.passenger instanceof Player) { @@ -84,9 +281,27 @@ public class MobPig this.moveForward = 0f; this.moveStrafing = 0f; + if (this.onGround && !this.wasGrounded) { + float keep = this.airborneFromJump + ? JUMP_LANDING_KEEP + : landingSpeedKeep((float) (this.lastStandingY - this.y)); + this.xd *= keep; + this.zd *= keep; + this.speedProgress *= keep; + this.airborneFromJump = false; + } + if (this.onGround) { + this.lastStandingY = this.y; + } + this.wasGrounded = this.onGround; + + if (this.horizontalCollision) { + this.speedProgress = Math.max(0f, this.speedProgress - WALL_HIT_SPEED_LOSS); + } + var friction = this.world.getBlockType(this.queryPos.set(MathHelper.floor(this.x), MathHelper.floor(this.y - 1), MathHelper.floor(this.z))).friction; final float accel = MathHelper.lerp(3, 10f * (1 + (0.6f - friction)), this.speedProgress) * (!this.onGround ? 0.25f : 1f) * (isInWater() ? 0.5f : 1f); - final float maxSpeed = MathHelper.lerp(0.15f, 0.5f * (1 - (0.6f - friction)/2.5f), this.speedProgress) * (!(this.onGround || this.yd < 0) ? 0.25f : 1f) * (isInWater() ? 0.5f : 1f); + final float maxSpeed = MathHelper.lerp(0.15f, 0.5f * (1 - (0.6f - friction)/2.5f), this.speedProgress) * (isInWater() ? 0.5f : 1f); double pXd = this.passenger.xd; double pZd = this.passenger.zd; @@ -103,14 +318,17 @@ public class MobPig pZd *= vel; } + double externalSpeed = Math.sqrt(this.xd * this.xd + this.zd * this.zd); + double effectiveMax = Math.max(maxSpeed, externalSpeed); + this.xd += pXd * accel; this.zd += pZd * accel; double spdsqrd = this.xd * this.xd + this.zd * this.zd; - if (spdsqrd > maxSpeed * maxSpeed) { + if (spdsqrd > effectiveMax * effectiveMax) { double speed = Math.sqrt(spdsqrd); - this.xd = (this.xd / speed) * maxSpeed; - this.zd = (this.zd / speed) * maxSpeed; + this.xd = (this.xd / speed) * effectiveMax; + this.zd = (this.zd / speed) * effectiveMax; } this.xRot = this.passenger.xRot; @@ -119,7 +337,9 @@ public class MobPig this.isJumping = isInWater() || ((Player) this.passenger).isJumping(); - if ((this.onGround || this.yd < 0) && !isInWater() && !this.isJumping) { + if (isInWater()) { + this.speedProgress = 0f; + } else if (this.onGround && !this.isJumping) { if (pXd * pXd + pZd * pZd > 0.000005f) { this.speedProgress += (1/200f) * (1 + (0.6f - friction) * 1.5f); this.speedProgress *= (1.000f + 0.025f * (1 + (0.6f - friction) * 1.5f)); @@ -127,15 +347,35 @@ public class MobPig this.speedProgress *= 0.9f; } this.speedProgress = MathHelper.clamp(this.speedProgress, 0, 1); - } else { - this.speedProgress = 0f; + } + } else if (this.panicTicks > 0) { + this.footSize = 0.5f; + this.panicTicks--; + this.moveSpeed = PANIC_MOVE_SPEED; + if (this.pathToEntity == null || this.random.nextInt(10) == 0) { + roamRandomPath(); + } + super.updateAI(); + if (this.panicTicks <= 0 && getSaddled() && this.passenger == null) { + setSitting(true); } } else { this.footSize = 0.5f; + this.moveSpeed = NORMAL_MOVE_SPEED; super.updateAI(); } } + @Override + protected void checkForPlayerHoldingItem() { + if (this.panicTicks > 0) { + setTarget(null); + this.closestPlayer = null; + return; + } + super.checkForPlayerHoldingItem(); + } + @Override public void positionRider() { super.positionRider(); @@ -189,30 +429,40 @@ public class MobPig { if (super.interact(player)) return true; ItemStack heldItem = player.getHeldItem(); - if (heldItem != null && (heldItem.itemID == Blocks.MUSHROOM_BROWN.id() || heldItem.itemID == Blocks.MUSHROOM_RED.id()) && heldItem.consumeItem(player)) { + if (heldItem != null && (heldItem.itemID == Blocks.MUSHROOM_BROWN.id() || heldItem.itemID == Blocks.MUSHROOM_RED.id()) + && getHealth() < getMaxHealth() && heldItem.consumeItem(player)) { heal(4); + + this.world.playSoundAtEntity(player, this, "random.bite", + 0.2f + (this.random.nextFloat() - this.random.nextFloat()) * 0.1f, + 0.8f + (this.random.nextFloat() - this.random.nextFloat()) * 0.1f); return true; } - if (!this.world.isClientSide) { - if (getSaddled()) { - if (player.isSneaking()) { - if (this.passenger == null) { - setSaddled(false); - ItemStack toInsert = new ItemStack(Items.SADDLE); - player.inventory.insertItem(toInsert, true); - if (toInsert.stackSize > 0) { - dropItem(toInsert, 0.0f); - } - return true; - } - } - if (this.passenger == null || this.passenger == player) { - player.startRiding(this); - return true; - } + if (this.passenger == player) { + return false; + } + if (!getSaddled()) { + return false; + } + if (this.passenger != null) { + return false; + } + if (this.world.isClientSide) { + return true; + } + if (player.isSneaking()) { + setSaddled(false); + setSitting(false); + this.panicTicks = 0; + ItemStack toInsert = new ItemStack(Items.SADDLE); + player.inventory.insertItem(toInsert, true); + if (toInsert.stackSize > 0) { + dropItem(toInsert, 0.0f); } + } else { + player.startRiding(this); } - return false; + return true; } @Override @@ -257,6 +507,29 @@ public class MobPig } } + public boolean getSitting() + { + return (this.entityData.getByte(DATA_SIT_ID) & 1) != 0; + } + + public void setSitting(boolean flag) + { + this.entityData.set(DATA_SIT_ID, (byte) (flag ? 1 : 0)); + if (flag) { + this.xd = 0.0D; + this.zd = 0.0D; + this.moveForward = 0f; + this.moveStrafing = 0f; + this.pathToEntity = null; + this.panicTicks = 0; + } + } + + @Override + protected boolean isMovementCeased() { + return getSitting() || super.isMovementCeased(); + } + @Override public void thunderHit(EntityLightning bolt) { @@ -273,9 +546,33 @@ public class MobPig @Override protected void causeFallDamage(float distance) { + if (this.passenger instanceof Player driver) { + if (this.world.isClientSide) { + this.pendingFallDistance = distance; + } else if (!driver.lerpVehicleMotion()) { + applyRiderFallDamage(distance); + } + return; + } super.causeFallDamage(distance); - if(distance > 5F && (this.passenger instanceof Player)) { - ((Player) this.passenger).triggerAchievement(Achievements.FLY_PIG); + } + + public float consumePendingFallDistance() { + float distance = this.pendingFallDistance; + this.pendingFallDistance = 0f; + return distance; + } + + public void applyRiderFallDamage(float distance) { + if (this.world.isClientSide) { + return; + } + if (distance > 5F && this.passenger instanceof Player rider) { + rider.triggerAchievement(Achievements.FLY_PIG); + } + int damage = (int) Math.ceil(distance - 3F); + if (damage > 0) { + hurt(null, damage, DamageType.FALL); } } @Override 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 6edabf547..a06599cbe 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 @@ -127,6 +127,7 @@ public abstract class Player public float timeInPortal; public float prevTimeInPortal; public @Nullable EntityFishingBobber bobberEntity; + private @Nullable CompoundTag pendingVehicleTag; protected @Nullable ICarriable heldObject; public volatile String skinURL; public volatile String capeURL; @@ -257,6 +258,15 @@ public abstract class Player @Override public void tick() { + if (this.pendingVehicleTag != null && !this.world.isClientSide) { + CompoundTag vehicleTag = this.pendingVehicleTag; + this.pendingVehicleTag = null; + Entity vehicle = EntityDispatcher.getInstance().createEntityFromNBT(vehicleTag, this.world); + if (vehicle instanceof MobPig pig) { + this.world.entityJoinedWorld(pig); + startRiding(pig); + } + } if (this.world.getDimension() == Dimension.NETHER) { addStat(Achievements.ENTER_NETHER, 1); if (random.nextInt(20) == 0) { @@ -287,7 +297,7 @@ public abstract class Player final boolean wSneak = wantSneak(); - if (wSneak || hasNoPhysics()) { + if (wSneak || hasNoPhysics() || this.vehicle != null) { this.sneaking = wSneak; } else { if (boundsClear(getBoundsForState(MOTION_STATE_DEFAULT))) { @@ -373,6 +383,9 @@ public abstract class Player addMountedMovementStat(this.x - xdO, this.y - ydO, this.z - zdO); } + public void onVehicleFlung(Entity vehicle) { + } + @Override public void resetPos() { setupScale(); @@ -955,6 +968,9 @@ public abstract class Player CompoundTag heldTag = tag.getCompound("HeldObject"); this.heldObject = ICarriable.createAndLoadCarriable(this, heldTag); } + if (tag.containsKey("Vehicle")) { + this.pendingVehicleTag = tag.getCompound("Vehicle"); + } } @Override @@ -986,6 +1002,16 @@ public abstract class Player this.heldObject.writeToNBT(heldTag); tag.put("HeldObject", heldTag); } + + if (this.vehicle instanceof MobPig pig) { + var vehicleId = pig.getDispatcherId(); + if (vehicleId != null) { + CompoundTag vehicleTag = new CompoundTag(); + vehicleTag.putString("id", vehicleId.toString()); + pig.saveWithoutId(vehicleTag); + tag.put("Vehicle", vehicleTag); + } + } } @Override @@ -1000,6 +1026,10 @@ public abstract class Player public void displayContainerScreen(Container container) { } + public void clearPendingVehicleTag() { + this.pendingVehicleTag = null; + } + public void displayChestScreen(Container container, double x, double y, double z) { } @@ -1180,12 +1210,12 @@ public abstract class Player return false; } - public boolean useCurrentItemOnEntity(Entity entity) { - boolean flag = false; + public boolean useCurrentItemOnEntity(@NotNull Entity entity) { if (entity.interact(this)) { swingItem(); - flag = true; + return true; } + boolean flag = false; ItemStack itemstack = getCurrentEquippedItem(); if (itemstack != null && (entity instanceof Mob)) { if (itemstack.useItemOnEntity(this, (Mob) entity)) { @@ -1689,6 +1719,9 @@ public abstract class Player } public void setNoclip(final boolean noclip) { + if (noclip && this.vehicle != null) { + return; + } setNoPhysics(noclip); if (hasNoPhysics()) { this.yd += 0.079f; diff --git a/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityBoat.java b/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityBoat.java index 1536ee0d6..f0a9a8e52 100644 --- a/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityBoat.java +++ b/game/core/src/main/java/net/minecraft/core/entity/vehicle/EntityBoat.java @@ -396,8 +396,14 @@ public class EntityBoat extends Entity implements ICollidable { this.pendingZDChange = Math.sin(Math.toRadians(this.yRot)) * velOff; } - public void handleControlDirect(float xd, float zd, float yRot) { - this.yRot = (float) MathHelper.clamp(yRot, this.yRot - MAX_PACKET_ROTATION_CHANGE, this.yRot + MAX_PACKET_ROTATION_CHANGE); + @Override + public boolean relaysVehicleControl() { + return true; + } + + @Override + public void handleControlDirect(double xd, double yd, double zd, float yRot) { + this.yRot = (float) MathHelper.clamp((double) yRot, this.yRot - MAX_PACKET_ROTATION_CHANGE, this.yRot + MAX_PACKET_ROTATION_CHANGE); this.xd = MathHelper.clamp(xd, this.xd - MAX_PACKET_SPEED_CHANGE, this.xd + MAX_PACKET_SPEED_CHANGE); this.zd = MathHelper.clamp(zd, this.zd - MAX_PACKET_SPEED_CHANGE, this.zd + MAX_PACKET_SPEED_CHANGE); } diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemSaddle.java b/game/core/src/main/java/net/minecraft/core/item/ItemSaddle.java index 3675e69d9..bfc022998 100644 --- a/game/core/src/main/java/net/minecraft/core/item/ItemSaddle.java +++ b/game/core/src/main/java/net/minecraft/core/item/ItemSaddle.java @@ -16,6 +16,7 @@ public class ItemSaddle extends Item { public boolean useOnEntity(@NotNull ItemStack selfStack, @NotNull Player player, @NotNull Mob mob) { if(!player.isSneaking() && mob instanceof MobPig pig && !pig.getSaddled() && selfStack.consumeItem(player)) { pig.setSaddled(true); + pig.setSitting(true); return true; } return false; diff --git a/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandTeleport.java b/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandTeleport.java index d1f1e7ad8..171d645df 100644 --- a/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandTeleport.java +++ b/game/core/src/main/java/net/minecraft/core/net/command/commands/CommandTeleport.java @@ -101,9 +101,19 @@ public class CommandTeleport implements CommandManager.CommandRegistry { EntitySelector targetEntitySelector = c.getArgument("target", EntitySelector.class); Entity targetEntity = targetEntitySelector.get(c.getSource()).get(0); + double x = targetEntity.x; + double y = targetEntity.y - targetEntity.heightOffset; + double z = targetEntity.z; + int targetDimension = targetEntity instanceof Player ? ((Player) targetEntity).dimension : targetEntity.world.dimension.id; + List entities = entitySelector.get(c.getSource()); for (Entity entity : entities) { - entity.moveTo(targetEntity.x, targetEntity.y - targetEntity.heightOffset, targetEntity.z, entity.yRot, entity.xRot); + if (entity instanceof Player player) { + if (player.dimension != targetDimension) source.movePlayerToDimension(player, targetDimension); + source.teleportPlayerToPos(player, x, y, z); + } else { + entity.moveTo(x, y, z, entity.yRot, entity.xRot); + } } if (entities.size() == 1) source.sendTranslatableMessage("command.commands.teleport.entity.success_single_entity", CommandHelper.getEntityName(entities.get(0)), CommandHelper.getEntityName(targetEntity)); diff --git a/game/core/src/main/java/net/minecraft/core/net/handler/PacketHandler.java b/game/core/src/main/java/net/minecraft/core/net/handler/PacketHandler.java index e4ebde803..609a47978 100644 --- a/game/core/src/main/java/net/minecraft/core/net/handler/PacketHandler.java +++ b/game/core/src/main/java/net/minecraft/core/net/handler/PacketHandler.java @@ -211,6 +211,7 @@ public abstract class PacketHandler { handleInvalidPacket(packetSetHeldObject); } + @Deprecated public void handleContainerAck(@NotNull PacketContainerAck packetContainerAck) { handleInvalidPacket(packetContainerAck); } @@ -219,8 +220,8 @@ public abstract class PacketHandler { handleInvalidPacket(packetAddPainting); } - public void handleBoatControl(@NotNull PacketBoatControl packetBoatControl) { - handleInvalidPacket(packetBoatControl); + public void handleVehicleControl(@NotNull PacketVehicleControl packetVehicleControl) { + handleInvalidPacket(packetVehicleControl); } public void handleBlockEvent(@NotNull PacketBlockEvent packetBlockEvent) { diff --git a/game/core/src/main/java/net/minecraft/core/net/packet/Packet.java b/game/core/src/main/java/net/minecraft/core/net/packet/Packet.java index 8e3aaf97f..c871d0372 100644 --- a/game/core/src/main/java/net/minecraft/core/net/packet/Packet.java +++ b/game/core/src/main/java/net/minecraft/core/net/packet/Packet.java @@ -279,7 +279,7 @@ public abstract class Packet addMapping(23, true, false, PacketAddEntity.class); addMapping(24, true, false, PacketAddMob.class); addMapping(25, true, false, PacketAddPainting.class); - addMapping(26, true, true, PacketBoatControl.class); + addMapping(26, true, true, PacketVehicleControl.class); addMapping(27, true, true, PacketSetHeldObject.class); addMapping(28, true, false, PacketSetEntityMotion.class); addMapping(29, true, false, PacketRemoveEntity.class); diff --git a/game/core/src/main/java/net/minecraft/core/net/packet/PacketBoatControl.java b/game/core/src/main/java/net/minecraft/core/net/packet/PacketBoatControl.java deleted file mode 100644 index ae29725cb..000000000 --- a/game/core/src/main/java/net/minecraft/core/net/packet/PacketBoatControl.java +++ /dev/null @@ -1,47 +0,0 @@ -package net.minecraft.core.net.packet; - -import net.minecraft.core.entity.Entity; -import net.minecraft.core.net.handler.PacketHandler; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -public class PacketBoatControl extends Packet{ - public int entityId; - public float targetXD; - public float targetZD; - public float targetYRot; - public PacketBoatControl(){} - public PacketBoatControl(Entity entity){ - entityId = entity.id; - targetXD = (float) entity.xd; - targetZD = (float) entity.zd; - targetYRot = entity.yRot; - } - @Override - public void read(DataInputStream dis) throws IOException { - entityId = dis.readInt(); - targetXD = dis.readFloat(); - targetZD = dis.readFloat(); - targetYRot = dis.readFloat(); - } - - @Override - public void write(DataOutputStream dos) throws IOException { - dos.writeInt(entityId); - dos.writeFloat(targetXD); - dos.writeFloat(targetZD); - dos.writeFloat(targetYRot); - } - - @Override - public void handlePacket(PacketHandler packetHandler) { - packetHandler.handleBoatControl(this); - } - - @Override - public int getEstimatedSize() { - return 12; - } -} diff --git a/game/core/src/main/java/net/minecraft/core/net/packet/PacketContainerAck.java b/game/core/src/main/java/net/minecraft/core/net/packet/PacketContainerAck.java index fae9fde6b..7ed15eb4c 100644 --- a/game/core/src/main/java/net/minecraft/core/net/packet/PacketContainerAck.java +++ b/game/core/src/main/java/net/minecraft/core/net/packet/PacketContainerAck.java @@ -1,9 +1,11 @@ package net.minecraft.core.net.packet; import net.minecraft.core.net.handler.PacketHandler; +import org.jetbrains.annotations.NotNull; import java.io.*; +@Deprecated public class PacketContainerAck extends Packet { @@ -19,13 +21,13 @@ public class PacketContainerAck extends Packet } @Override - public void handlePacket(PacketHandler packetHandler) + public void handlePacket(@NotNull PacketHandler packetHandler) { packetHandler.handleContainerAck(this); } @Override - public void read(DataInputStream dis) + public void read(@NotNull DataInputStream dis) throws IOException { windowId = dis.readByte(); @@ -34,7 +36,7 @@ public class PacketContainerAck extends Packet } @Override - public void write(DataOutputStream dos) + public void write(@NotNull DataOutputStream dos) throws IOException { dos.writeByte(windowId); diff --git a/game/core/src/main/java/net/minecraft/core/net/packet/PacketContainerClick.java b/game/core/src/main/java/net/minecraft/core/net/packet/PacketContainerClick.java index 6fb4232e6..3afb71bb0 100644 --- a/game/core/src/main/java/net/minecraft/core/net/packet/PacketContainerClick.java +++ b/game/core/src/main/java/net/minecraft/core/net/packet/PacketContainerClick.java @@ -1,58 +1,72 @@ package net.minecraft.core.net.packet; +import com.mojang.nbt.tags.CompoundTag; +import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.minecraft.core.InventoryAction; import net.minecraft.core.item.ItemStack; import net.minecraft.core.net.handler.PacketHandler; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.*; public class PacketContainerClick extends Packet { + public int window_Id; + public InventoryAction action; + public int[] args; + public int stateId; + public Int2ObjectMap changedSlots; + public ItemStack carriedItem; + public PacketContainerClick() { } - public PacketContainerClick(int windowId, InventoryAction action, int[] args, ItemStack itemstack, short actionId) { + public PacketContainerClick(int windowId, InventoryAction action, int[] args, int stateId, Int2ObjectMap changedSlots, ItemStack carriedItem) { this.window_Id = windowId; this.action = action; this.args = args; - this.itemStack = itemstack; - this.actionId = actionId; + this.stateId = stateId; + this.changedSlots = changedSlots; + this.carriedItem = carriedItem; } @Override - public void handlePacket(PacketHandler packetHandler) { + public void handlePacket(@NotNull PacketHandler packetHandler) { packetHandler.handleContainerClick(this); } @Override - public void read(DataInputStream dis) throws IOException { + public void read(@NotNull DataInputStream dis) throws IOException { window_Id = dis.readByte(); action = InventoryAction.get(dis.readByte()); - + int size = dis.readByte(); args = new int[size]; for(int i=0; i < size; i++) { args[i] = dis.read(); } - - actionId = dis.readShort(); - short word0 = dis.readShort(); - if(word0 >= 0) { - byte byte0 = dis.readByte(); - short word1 = dis.readShort(); - itemStack = new ItemStack(word0, byte0, word1); - } else { - itemStack = null; + + stateId = dis.readInt(); + + int changedCount = dis.readShort(); + changedSlots = new Int2ObjectArrayMap<>(changedCount); + for(int i=0; i < changedCount; i++) { + int slot = dis.readShort(); + changedSlots.put(slot, readStack(dis)); } + + carriedItem = readStack(dis); } @Override - public void write(DataOutputStream dos) + public void write(@NotNull DataOutputStream dos) throws IOException { dos.writeByte(window_Id); dos.writeByte(action.getId()); - + if(args != null) { if(args.length > 255) { System.err.println("Too many args!"); @@ -68,27 +82,46 @@ public class PacketContainerClick extends Packet { }else { dos.write(0); } - - dos.writeShort(actionId); - if(itemStack == null) - { - dos.writeShort(-1); - } else - { - dos.writeShort(itemStack.itemID); - dos.writeByte(itemStack.stackSize); - dos.writeShort(itemStack.getMetadata()); - } - } + + dos.writeInt(stateId); + + if(changedSlots == null) { + dos.writeShort(0); + } else { + dos.writeShort(changedSlots.size()); + for(Int2ObjectMap.Entry entry : changedSlots.int2ObjectEntrySet()) { + dos.writeShort(entry.getIntKey()); + writeStack(dos, entry.getValue()); + } + } + + writeStack(dos, carriedItem); + } + + private static @Nullable ItemStack readStack(@NotNull DataInputStream dis) throws IOException { + short itemId = dis.readShort(); + if(itemId >= 0) { + byte size = dis.readByte(); + short meta = dis.readShort(); + CompoundTag tag = readCompressedCompoundTag(dis); + return new ItemStack(itemId, size, meta, tag); + } + return null; + } + + private static void writeStack(DataOutputStream dos, ItemStack stack) throws IOException { + if(stack == null) { + dos.writeShort(-1); + } else { + dos.writeShort(stack.itemID); + dos.writeByte(stack.stackSize); + dos.writeShort(stack.getMetadata()); + writeCompressedCompoundTag(stack.getData(), dos); + } + } @Override public int getEstimatedSize() { - return 7 + (args != null ? args.length : 0); + return 11 + (args != null ? args.length : 0) + (changedSlots != null ? changedSlots.size() * 7 : 0); } - - public int window_Id; - public InventoryAction action; - public int[] args; - public short actionId; - public ItemStack itemStack; } diff --git a/game/core/src/main/java/net/minecraft/core/net/packet/PacketContainerSetContent.java b/game/core/src/main/java/net/minecraft/core/net/packet/PacketContainerSetContent.java index 29378c678..533f27578 100644 --- a/game/core/src/main/java/net/minecraft/core/net/packet/PacketContainerSetContent.java +++ b/game/core/src/main/java/net/minecraft/core/net/packet/PacketContainerSetContent.java @@ -3,6 +3,8 @@ package net.minecraft.core.net.packet; import com.mojang.nbt.tags.CompoundTag; import net.minecraft.core.item.ItemStack; import net.minecraft.core.net.handler.PacketHandler; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.*; import java.util.List; @@ -10,16 +12,20 @@ import java.util.List; public class PacketContainerSetContent extends Packet { public int windowId; + public int stateId; public ItemStack[] stackList; + public ItemStack carriedItem; public PacketContainerSetContent() { } - public PacketContainerSetContent(int i, List list) + public PacketContainerSetContent(int windowId, int stateId, List list, ItemStack carriedItem) { - windowId = i; + this.windowId = windowId; + this.stateId = stateId; + this.carriedItem = carriedItem != null ? carriedItem.copy() : null; stackList = new ItemStack[list.size()]; for(int j = 0; j < stackList.length; j++) { @@ -30,54 +36,60 @@ public class PacketContainerSetContent extends Packet } @Override - public void read(DataInputStream dis) + public void read(@NotNull DataInputStream dis) throws IOException { windowId = dis.readByte(); + stateId = dis.readInt(); + carriedItem = readStack(dis); short listSize = dis.readShort(); stackList = new ItemStack[listSize]; for(int i = 0; i < listSize; i++) { - short itemId = dis.readShort(); - if(itemId >= 0) - { - byte size = dis.readByte(); - short meta = dis.readShort(); - CompoundTag tag = readCompressedCompoundTag(dis); - ItemStack s = new ItemStack(itemId, size, meta, tag); - stackList[i] = s; -// System.out.printf("Received|| Name:%s, ID:%s, CustomName:%s, Tag:%s\n", s.getItemKey(), s.itemID, s.getCustomName(), s.getData()); - } + stackList[i] = readStack(dis); } } @Override - public void write(DataOutputStream dos) + public void write(@NotNull DataOutputStream dos) throws IOException { dos.writeByte(windowId); + dos.writeInt(stateId); + writeStack(dos, carriedItem); dos.writeShort(stackList.length); for(int i = 0; i < stackList.length; i++) { - if(stackList[i] == null) - { - dos.writeShort(-1); - } else - { - dos.writeShort((short) stackList[i].itemID); - dos.writeByte((byte) stackList[i].stackSize); - dos.writeShort((short) stackList[i].getMetadata()); - writeCompressedCompoundTag(stackList[i].getData(), dos); -// ItemStack s = stackList[i]; -// System.out.printf("Sent|| Name:%s, ID:%s, CustomName:%s, Tag:%s\n", s.getItemKey(), s.itemID, s.getCustomName(), s.getData()); - } + writeStack(dos, stackList[i]); } } + private static @Nullable ItemStack readStack(@NotNull DataInputStream dis) throws IOException { + short itemId = dis.readShort(); + if(itemId >= 0) { + byte size = dis.readByte(); + short meta = dis.readShort(); + CompoundTag tag = readCompressedCompoundTag(dis); + return new ItemStack(itemId, size, meta, tag); + } + return null; + } + + private static void writeStack(DataOutputStream dos, ItemStack stack) throws IOException { + if(stack == null) { + dos.writeShort(-1); + } else { + dos.writeShort((short) stack.itemID); + dos.writeByte((byte) stack.stackSize); + dos.writeShort((short) stack.getMetadata()); + writeCompressedCompoundTag(stack.getData(), dos); + } + } + @Override - public void handlePacket(PacketHandler packetHandler) + public void handlePacket(@NotNull PacketHandler packetHandler) { packetHandler.handleContainerSetContent(this); } @@ -85,6 +97,6 @@ public class PacketContainerSetContent extends Packet @Override public int getEstimatedSize() { - return 3 + stackList.length * 5; + return 12 + stackList.length * 5; } } diff --git a/game/core/src/main/java/net/minecraft/core/net/packet/PacketContainerSetSlot.java b/game/core/src/main/java/net/minecraft/core/net/packet/PacketContainerSetSlot.java index 4d879790a..99bf584c3 100644 --- a/game/core/src/main/java/net/minecraft/core/net/packet/PacketContainerSetSlot.java +++ b/game/core/src/main/java/net/minecraft/core/net/packet/PacketContainerSetSlot.java @@ -3,6 +3,7 @@ package net.minecraft.core.net.packet; import net.minecraft.core.item.ItemStack; import com.mojang.nbt.tags.CompoundTag; import net.minecraft.core.net.handler.PacketHandler; +import org.jetbrains.annotations.NotNull; import java.io.*; @@ -14,23 +15,25 @@ public class PacketContainerSetSlot extends Packet } @Override - public void handlePacket(PacketHandler packetHandler) + public void handlePacket(@NotNull PacketHandler packetHandler) { packetHandler.handleContainerSetSlot(this); } - - public PacketContainerSetSlot(int i, int j, ItemStack itemstack) + + public PacketContainerSetSlot(int windowId, int stateId, int slot, ItemStack itemstack) { - windowId = i; - itemSlot = j; - myItemStack = itemstack != null ? itemstack.copy() : itemstack; + this.windowId = windowId; + this.stateId = stateId; + this.itemSlot = slot; + this.myItemStack = itemstack != null ? itemstack.copy() : itemstack; } @Override - public void read(DataInputStream dis) + public void read(@NotNull DataInputStream dis) throws IOException { windowId = dis.readByte(); + stateId = dis.readInt(); itemSlot = dis.readShort(); short word0 = dis.readShort(); if(word0 >= 0) @@ -46,10 +49,11 @@ public class PacketContainerSetSlot extends Packet } @Override - public void write(DataOutputStream dos) + public void write(@NotNull DataOutputStream dos) throws IOException { dos.writeByte(windowId); + dos.writeInt(stateId); dos.writeShort(itemSlot); if(myItemStack == null) { @@ -66,10 +70,11 @@ public class PacketContainerSetSlot extends Packet @Override public int getEstimatedSize() { - return 8; + return 12; } public int windowId; + public int stateId; public int itemSlot; public ItemStack myItemStack; } diff --git a/game/core/src/main/java/net/minecraft/core/net/packet/PacketVehicleControl.java b/game/core/src/main/java/net/minecraft/core/net/packet/PacketVehicleControl.java new file mode 100644 index 000000000..de104e8a0 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/net/packet/PacketVehicleControl.java @@ -0,0 +1,71 @@ +package net.minecraft.core.net.packet; + +import net.minecraft.core.entity.Entity; +import net.minecraft.core.net.handler.PacketHandler; +import org.jetbrains.annotations.NotNull; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Sent by the client driving a vehicle. The server applies it, and may send it to nearby players. + *

    + * The meaning of the three values changes based on the vehicle: + *

  • {@code EntityBoat} treats xd/yd/zd as velocity
  • + *
  • {@code MobPig} treats xd/yd/zd as the pig's absolute position
  • + */ +public class PacketVehicleControl extends Packet { + public int entityId; + public double targetXD; + public double targetYD; + public double targetZD; + public float targetYRot; + public float fallDistance; + + public PacketVehicleControl() { + } + + public PacketVehicleControl(@NotNull Entity entity) { + this(entity.id, entity.xd, entity.yd, entity.zd, entity.yRot, 0f); + } + + public PacketVehicleControl(int entityId, double targetXD, double targetYD, double targetZD, float targetYRot, float fallDistance) { + this.entityId = entityId; + this.targetXD = targetXD; + this.targetYD = targetYD; + this.targetZD = targetZD; + this.targetYRot = targetYRot; + this.fallDistance = fallDistance; + } + + @Override + public void read(@NotNull DataInputStream dis) throws IOException { + entityId = dis.readInt(); + targetXD = dis.readDouble(); + targetYD = dis.readDouble(); + targetZD = dis.readDouble(); + targetYRot = dis.readFloat(); + fallDistance = dis.readFloat(); + } + + @Override + public void write(@NotNull DataOutputStream dos) throws IOException { + dos.writeInt(entityId); + dos.writeDouble(targetXD); + dos.writeDouble(targetYD); + dos.writeDouble(targetZD); + dos.writeFloat(targetYRot); + dos.writeFloat(fallDistance); + } + + @Override + public void handlePacket(@NotNull PacketHandler packetHandler) { + packetHandler.handleVehicleControl(this); + } + + @Override + public int getEstimatedSize() { + return 4 + 8 * 3 + 4 + 4; + } +} diff --git a/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuAbstract.java b/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuAbstract.java index f558bd76f..7f02e44c3 100644 --- a/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuAbstract.java +++ b/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuAbstract.java @@ -31,18 +31,17 @@ public abstract class MenuAbstract public List lastSlots; public List slots; public int containerId; - private short changeUid; + public int stateId; + private boolean suppressRemoteUpdates; protected List containerListeners; - private final Set unSynchedPlayers; public MenuAbstract() { lastSlots = new ArrayList<>(); slots = new ArrayList<>(); containerId = 0; - changeUid = 0; + stateId = 0; containerListeners = new ArrayList<>(); - unSynchedPlayers = new HashSet<>(); } protected final void addSlot(Slot slot) @@ -62,6 +61,7 @@ public abstract class MenuAbstract { containerListeners.add(containerListener); containerListener.updateCraftingInventory(this, getSlotStackList()); + resetRemoteSlots(); broadcastChanges(); } } @@ -79,6 +79,11 @@ public abstract class MenuAbstract public void broadcastChanges() { + if(suppressRemoteUpdates) + { + return; + } + boolean bumpedState = false; for(int i = 0; i < slots.size(); i++) { @@ -88,6 +93,11 @@ public abstract class MenuAbstract { continue; } + if(!bumpedState) + { + incrementStateId(); + bumpedState = true; + } itemstack1 = itemstack != null ? itemstack.copy() : null; lastSlots.set(i, itemstack1); for (ContainerListener crafter : containerListeners) { @@ -98,6 +108,36 @@ public abstract class MenuAbstract } + public int getStateId() + { + return stateId; + } + + public int incrementStateId() + { + this.stateId++; + return this.stateId; + } + + public void setRemoteSlot(int index, ItemStack stack) + { + lastSlots.set(index, stack != null ? stack.copy() : null); + } + + public void resetRemoteSlots() + { + for(int i = 0; i < slots.size(); i++) + { + ItemStack stack = slots.get(i).getItemStack(); + lastSlots.set(i, stack != null ? stack.copy() : null); + } + } + + public void setRemoteUpdatesSuppressed(boolean suppressed) + { + this.suppressRemoteUpdates = suppressed; + } + /** * @param container ContainerInventory * @param index integer index of slot in container @@ -801,22 +841,6 @@ public abstract class MenuAbstract broadcastChanges(); } - public boolean isSynched(Player entityplayer) - { - return !unSynchedPlayers.contains(entityplayer); - } - - public void setSynched(Player entityplayer, boolean flag) - { - if(flag) - { - unSynchedPlayers.remove(entityplayer); - } else - { - unSynchedPlayers.add(entityplayer); - } - } - public void setItem(int i, ItemStack itemstack) { getSlot(i).set(itemstack); @@ -835,20 +859,6 @@ public abstract class MenuAbstract { } - public short backup(ContainerInventory inventoryplayer) - { - changeUid++; - return changeUid; - } - - public void deleteBackup(short word0) - { - } - - public void rollbackToBackup(short word0) - { - } - public abstract boolean stillValid(@NotNull Player player); /** diff --git a/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuInventoryCreative.java b/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuInventoryCreative.java index d28f2b8f8..d91a68214 100644 --- a/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuInventoryCreative.java +++ b/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuInventoryCreative.java @@ -155,6 +155,11 @@ public class MenuInventoryCreative extends MenuInventory inventory.player.updateCreativeInventory(page, searchText); } + public void broadcastInventoryStatus() + { + inventory.player.updateCreativeInventory(page, searchText); + } + public String getSearchText(){ return searchText; } diff --git a/game/core/src/main/java/net/minecraft/core/util/phys/BoundingVolume.java b/game/core/src/main/java/net/minecraft/core/util/phys/BoundingVolume.java index 6f653673f..236a8860e 100644 --- a/game/core/src/main/java/net/minecraft/core/util/phys/BoundingVolume.java +++ b/game/core/src/main/java/net/minecraft/core/util/phys/BoundingVolume.java @@ -9,6 +9,9 @@ import java.util.ArrayList; import java.util.EnumSet; import java.util.List; +import org.jetbrains.annotations.NotNull; +import org.joml.primitives.AABBdc; + public class BoundingVolume { private enum Line @@ -79,6 +82,46 @@ public class BoundingVolume return volume; } + public static @NotNull BoundingVolume bakeFromBlockSpaceAabbs(AABBdc @NotNull ... boxes) + { + BoundingVolume vol = BoundingVolume.newEmptyVolume(); + if (boxes.length == 0) + { + vol.bake(); + return vol; + } + double inv = 1.0 / SIZE; + for (int iy = 0; iy < SIZE; iy++) + { + for (int iz = 0; iz < SIZE; iz++) + { + for (int ix = 0; ix < SIZE; ix++) + { + double x = (ix + 0.5) * inv; + double y = (iy + 0.5) * inv; + double z = (iz + 0.5) * inv; + for (AABBdc box : boxes) + { + if (pointInsideBlockSpaceAabb(box, x, y, z)) + { + vol.fillVolume(ix, iy, iz, ix, iy, iz); + break; + } + } + } + } + } + vol.bake(); + return vol; + } + + private static boolean pointInsideBlockSpaceAabb(@NotNull AABBdc box, double x, double y, double z) + { + return x >= box.minX() && x <= box.maxX() + && y >= box.minY() && y <= box.maxY() + && z >= box.minZ() && z <= box.maxZ(); + } + private boolean isCarved(int x, int y, int z) { if (x < 0 || x >= SIZE) return true; diff --git a/game/core/src/main/java/net/minecraft/core/world/World.java b/game/core/src/main/java/net/minecraft/core/world/World.java index e892660e7..5f4aa2f35 100644 --- a/game/core/src/main/java/net/minecraft/core/world/World.java +++ b/game/core/src/main/java/net/minecraft/core/world/World.java @@ -3,7 +3,6 @@ package net.minecraft.core.world; import com.mojang.logging.LogUtils; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.minecraft.core.Global; import net.minecraft.core.NextTickListEntry; @@ -14,7 +13,6 @@ import net.minecraft.core.block.material.Material; import net.minecraft.core.block.material.Materials; import net.minecraft.core.block.support.ISupport; import net.minecraft.core.block.tag.BlockTags; -import net.minecraft.core.current.wire.ConduitHandler; import net.minecraft.core.current.wire.WireHandler; import net.minecraft.core.data.gamerule.GameRule; import net.minecraft.core.data.gamerule.GameRules; @@ -49,7 +47,6 @@ import net.minecraft.core.world.chunk.provider.ChunkProvider; import net.minecraft.core.world.config.spawning.SpawnerConfig; import net.minecraft.core.world.lighting.LightingEngine; import net.minecraft.core.world.lighting.LightingEngineLegacy; -import net.minecraft.core.world.particle.ParticleEmitterRegistry; import net.minecraft.core.world.pathfinder.Path; import net.minecraft.core.world.pathfinder.PathFinder; import net.minecraft.core.world.pos.*; @@ -120,14 +117,13 @@ public abstract class World implements MutableWorldSource { private final @NotNull List<@NotNull Entity> entityBuffer = new ObjectArrayList<>(); private final @NotNull Set<@NotNull NextTickListEntry> immediatelyUpdatedPositions = new ObjectOpenHashSet<>(); - public final ParticleEmitterRegistry particleEmitters = new ParticleEmitterRegistry(); - public final @NotNull Random rand = new Random(); private final AABBd workingBox = new AABBd(); public final @NotNull Dimension dimension; public final boolean isNewWorld; public boolean scheduledUpdatesAreImmediate = false; + public boolean isDecorating = false; public int skyDarken = 0; protected int updateLCG = new Random().nextInt(); public int lightningFlicker = 0; @@ -156,7 +152,6 @@ public abstract class World implements MutableWorldSource { private final @NotNull WeatherManager weatherManager; private final @NotNull CommandManager commandManager = new CommandManager(isServer); private final @NotNull WireHandler wireHandler = new WireHandler(this); - private final @NotNull ConduitHandler conduitHandler = new ConduitHandler(this); private final @NotNull LightingEngine lightingEngine = new LightingEngineLegacy(this); protected World( @@ -314,10 +309,6 @@ public abstract class World implements MutableWorldSource { return this.wireHandler; } - public @NotNull ConduitHandler getConduitHandler() { - return this.conduitHandler; - } - protected abstract @NotNull ChunkProvider createChunkProvider(@NotNull LevelStorage levelStorage); /* { final ChunkLoader chunkLoader = this.levelStorage.getChunkLoader(this.dimension); return accessor.createChunkProvider(this, chunkLoader); @@ -586,8 +577,8 @@ public abstract class World implements MutableWorldSource { final @NotNull ChunkPos chunkPos = new ChunkPos(minX, minZ); - for (; chunkPos.x <= maxX; chunkPos.x++) { - for (; chunkPos.z <= maxZ; chunkPos.z++) { + for (chunkPos.x = minX; chunkPos.x <= maxX; chunkPos.x++) { + for (chunkPos.z = minZ; chunkPos.z <= maxZ; chunkPos.z++) { if (!this.isChunkLoaded(chunkPos)) { return false; } @@ -633,12 +624,20 @@ public abstract class World implements MutableWorldSource { return this.getChunk(new ChunkPos(x, z)); } + private boolean notifyDecorationWrite(final @NotNull Chunk chunk, final @NotNull TilePosc tilePos, final boolean changed) { + if (changed && this.isDecorating && chunk.sentToClients) { + this.markBlockNeedsUpdate(tilePos); + } + return changed; + } + @Override public boolean setBlockTypeData(final @NotNull TilePosc tilePos, final @NotNull Block block, final int data) { if (!tilePos.inBounds(this)) { return false; } else { - return this.getChunk(tilePos).setBlockIdData(new ChunkTilePos(tilePos), block.id(), data); + final Chunk chunk = this.getChunk(tilePos); + return this.notifyDecorationWrite(chunk, tilePos, chunk.setBlockIdData(new ChunkTilePos(tilePos), block.id(), data)); } } @@ -650,6 +649,7 @@ public abstract class World implements MutableWorldSource { final var prevBlock = c.getBlock(ctp); final var prevData = c.getBlockData(ctp); if (!c.setBlockIdDataRaw(ctp, block.id(), data)) return false; + this.notifyDecorationWrite(c, tilePos, true); this.replaceTileEntity(tilePos, entity); prevBlock.getLogic().onRemoved(this, tilePos, prevData); @@ -671,7 +671,8 @@ public abstract class World implements MutableWorldSource { if (!tilePos.inBounds(this)) { return false; } else { - return this.getChunk(tilePos).setBlockIdDataRaw(new ChunkTilePos(tilePos), block.id(), data); + final Chunk chunk = this.getChunk(tilePos); + return this.notifyDecorationWrite(chunk, tilePos, chunk.setBlockIdDataRaw(new ChunkTilePos(tilePos), block.id(), data)); } } @@ -689,7 +690,8 @@ public abstract class World implements MutableWorldSource { if (!tilePos.inBounds(this)) { return false; } else { - return this.getChunk(tilePos).setBlockId(new ChunkTilePos(tilePos), block.id()); + final Chunk chunk = this.getChunk(tilePos); + return this.notifyDecorationWrite(chunk, tilePos, chunk.setBlockId(new ChunkTilePos(tilePos), block.id())); } } @@ -1637,20 +1639,21 @@ public abstract class World implements MutableWorldSource { } this.updatingTileEntities = true; + updateTileEntities(); + this.updatingTileEntities = false; + } + + protected void updateTileEntities() { for (int i = this.tileEntityList.size() - 1; i >= 0; i--) { final TileEntity tileEntity = this.tileEntityList.get(i); - if (!tileEntity.isInvalid() && this.isBlockLoaded(tileEntity.tilePos.x, tileEntity.tilePos.y, tileEntity.tilePos.z)) { + if (!tileEntity.isInvalid() && this.isBlockLoaded(tileEntity.tilePos)) { tileEntity.tick(); } if (tileEntity.isInvalid()) { this.tileEntityList.remove(i); - final Chunk chunk = this.getChunkFromChunkCoords(Math.floorDiv(tileEntity.tilePos.x, Chunk.CHUNK_SIZE_X), Math.floorDiv(tileEntity.tilePos.z, Chunk.CHUNK_SIZE_Z)); - if (chunk != null) { - chunk.removeTileEntity(tileEntity); - } + this.getChunk(tileEntity.tilePos).removeTileEntity(tileEntity); } } - this.updatingTileEntities = false; } public void addAllBlockEntities(final Collection blockEntities) { @@ -2550,6 +2553,7 @@ public abstract class World implements MutableWorldSource { if (this.isBlockNormalCube(tilePos)) direct_sig: { if (block == Blocks.BLOCK_REDSTONE) break direct_sig; if (block == Blocks.PUMPKIN_REDSTONE) break direct_sig; + if (block == Blocks.MATCHER) break direct_sig; if (block == Blocks.MATCHER_ACTIVE) break direct_sig; if (this.hasDirectSignal(tilePos)) return true; } @@ -2997,9 +3001,9 @@ public abstract class World implements MutableWorldSource { } public @NotNull EntityItem dropItem(double x, double y, double z, final @NotNull ItemStack itemStack, double radius) { - x += this.rand.nextFloat() * radius; - y += this.rand.nextFloat() * radius; - z += this.rand.nextFloat() * radius; + x += 0.5 + (this.rand.nextDouble() - 0.5) * radius; + y += 0.5 + this.rand.nextDouble() * radius * 0.25; + z += 0.5 + (this.rand.nextDouble() - 0.5) * radius; final @NotNull EntityItem item = new EntityItem(this, x, y, z, itemStack); item.pickupDelay = 10; diff --git a/game/core/src/main/java/net/minecraft/core/world/chunk/Chunk.java b/game/core/src/main/java/net/minecraft/core/world/chunk/Chunk.java index b3675369c..4d678cdf0 100644 --- a/game/core/src/main/java/net/minecraft/core/world/chunk/Chunk.java +++ b/game/core/src/main/java/net/minecraft/core/world/chunk/Chunk.java @@ -12,7 +12,6 @@ import net.minecraft.core.enums.LightLayer; import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.world.World; import net.minecraft.core.world.biome.Biome; -import net.minecraft.core.world.particle.ParticleEmitterRange; import net.minecraft.core.world.pos.ChunkSectionTilePos; import net.minecraft.core.world.pos.ChunkPos; import net.minecraft.core.world.pos.ChunkPosc; @@ -68,6 +67,7 @@ public class Chunk { public int averageBlockHeight; public boolean isTerrainPopulated = false; public boolean isModified = false; + public boolean sentToClients = false; public boolean neverSave; public boolean hasEntities = false; public long lastSaveTime = 0L; @@ -684,42 +684,6 @@ public class Chunk { for (ChunkSection section : this.sections) { section.onLoad(this.world); } - - if (!this.world.isClientSide) { - this.registerParticleEmittersFromLoadedBlocks(); - } - } - - /** - * Registers particle emitter blocks in this chunk on the server. - */ - private void registerParticleEmittersFromLoadedBlocks() { - final ChunkSectionTilePos sectionTile = new ChunkSectionTilePos(); - for (final ChunkSection section : this.sections) { - if (section.blocks == null) { - continue; - } - final int baseY = section.yPosition * ChunkSection.SECTION_SIZE_Y; - for (sectionTile.y = 0; sectionTile.y < ChunkSection.SECTION_SIZE_Y; sectionTile.y++) { - for (sectionTile.z = 0; sectionTile.z < CHUNK_SIZE_Z; sectionTile.z++) { - for (sectionTile.x = 0; sectionTile.x < CHUNK_SIZE_X; sectionTile.x++) { - final int id = section.getBlockId(sectionTile); - if (id == 0) { - continue; - } - final Block block = Blocks.getBlock(id); - final ParticleEmitterRange range = block.getLogic().getParticleEmitterRange(); - if (range == null) { - continue; - } - final int wx = this.pos.x * CHUNK_SIZE_X + sectionTile.x; - final int wy = baseY + sectionTile.y; - final int wz = this.pos.z * CHUNK_SIZE_Z + sectionTile.z; - this.world.particleEmitters.add(new TilePos(wx, wy, wz), range); - } - } - } - } } public void onUnload() { diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/PositionSelectors.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/PositionSelectors.java index 59064ac5a..2f87042a9 100644 --- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/PositionSelectors.java +++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/PositionSelectors.java @@ -8,6 +8,8 @@ import org.jetbrains.annotations.NotNull; import java.util.Random; public class PositionSelectors { + private static final int DECORATION_OFFSET = 8; + public static class HeightRangeUniform implements PositionSelector { private final int range; @@ -19,59 +21,59 @@ public class PositionSelectors { @Override public TilePos getValue(@NotNull World world, @NotNull Chunk chunk, @NotNull Random random, int minY, int maxY, int rangeY) { - int x = (chunk.pos.x() * 16) + random.nextInt(16); - int z = (chunk.pos.z() * 16) + random.nextInt(16); + int x = (chunk.pos.x() * 16) + random.nextInt(16) + DECORATION_OFFSET; + int z = (chunk.pos.z() * 16) + random.nextInt(16) + DECORATION_OFFSET; int y = minY + random.nextInt(rangeY / range); return new TilePos(x, y, z); } } public static PositionSelector MinY = (world, chunk, random, minY, maxY, rangeY) -> { - int x = (chunk.pos.x() * 16) + random.nextInt(16); - int z = (chunk.pos.z() * 16) + random.nextInt(16); + int x = (chunk.pos.x() * 16) + random.nextInt(16) + DECORATION_OFFSET; + int z = (chunk.pos.z() * 16) + random.nextInt(16) + DECORATION_OFFSET; return new TilePos(x, minY, z); }; public static PositionSelector MaxY = (world, chunk, random, minY, maxY, rangeY) -> { - int x = (chunk.pos.x() * 16) + random.nextInt(16); - int z = (chunk.pos.z() * 16) + random.nextInt(16); + int x = (chunk.pos.x() * 16) + random.nextInt(16) + DECORATION_OFFSET; + int z = (chunk.pos.z() * 16) + random.nextInt(16) + DECORATION_OFFSET; return new TilePos(x, maxY, z); }; public static PositionSelector HeightRangeUniform = (world, chunk, random, minY, maxY, rangeY) -> { - int x = (chunk.pos.x() * 16) + random.nextInt(16); - int z = (chunk.pos.z() * 16) + random.nextInt(16); + int x = (chunk.pos.x() * 16) + random.nextInt(16) + DECORATION_OFFSET; + int z = (chunk.pos.z() * 16) + random.nextInt(16) + DECORATION_OFFSET; int y = minY + random.nextInt(rangeY); return new TilePos(x, y, z); }; public static PositionSelector HeightRangeUniformFromOcean = (world, chunk, random, minY, maxY, rangeY) -> { - int x = (chunk.pos.x() * 16) + random.nextInt(16); - int z = (chunk.pos.z() * 16) + random.nextInt(16); + int x = (chunk.pos.x() * 16) + random.nextInt(16) + DECORATION_OFFSET; + int z = (chunk.pos.z() * 16) + random.nextInt(16) + DECORATION_OFFSET; int y = world.getWorldType().getOceanY() + random.nextInt(rangeY - 8) + 4; return new TilePos(x, y, z); }; public static PositionSelector UpperHeightRangeUniform = (world, chunk, random, minY, maxY, rangeY) -> { - int x = (chunk.pos.x() * 16) + random.nextInt(16); - int z = (chunk.pos.z() * 16) + random.nextInt(16); + int x = (chunk.pos.x() * 16) + random.nextInt(16) + DECORATION_OFFSET; + int z = (chunk.pos.z() * 16) + random.nextInt(16) + DECORATION_OFFSET; int y = rangeY / 2 + random.nextInt(rangeY - 8) + 4; return new TilePos(x, y, z); }; public static PositionSelector HeightRangeBiasedTop = (world, chunk, random, minY, maxY, rangeY) -> { - int x = (chunk.pos.x() * 16) + random.nextInt(16); - int z = (chunk.pos.z() * 16) + random.nextInt(16); + int x = (chunk.pos.x() * 16) + random.nextInt(16) + DECORATION_OFFSET; + int z = (chunk.pos.z() * 16) + random.nextInt(16) + DECORATION_OFFSET; int y = minY + random.nextInt(random.nextInt(rangeY - (rangeY / 16)) + (rangeY / 16)); return new TilePos(x, y, z); }; public static PositionSelector SurfaceBlock = (world, chunk, random, minY, maxY, rangeY) -> { - int x = (chunk.pos.x() * 16) + random.nextInt(16); - int z = (chunk.pos.z() * 16) + random.nextInt(16); + int x = (chunk.pos.x() * 16) + random.nextInt(16) + DECORATION_OFFSET; + int z = (chunk.pos.z() * 16) + random.nextInt(16) + DECORATION_OFFSET; int y = world.getHeightValue(x, z); return new TilePos(x, y, z); }; diff --git a/game/core/src/main/java/net/minecraft/core/world/particle/ParticleEmitterRange.java b/game/core/src/main/java/net/minecraft/core/world/particle/ParticleEmitterRange.java deleted file mode 100644 index 5ce6e423d..000000000 --- a/game/core/src/main/java/net/minecraft/core/world/particle/ParticleEmitterRange.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.minecraft.core.world.particle; - -public enum ParticleEmitterRange { - // BASIC fixed 16-block radius - BASIC(0.0f), - - // SHORT scales to 25% of the players' particle render distance - SHORT(0.25f), - - // MEDIUM scales to 50% - MEDIUM(0.5f), - - // FAR scales to 75% - FAR(0.75f), - - // EXTREME uses 100% - EXTREME(1.0f); - - public final float multiplier; - - ParticleEmitterRange(float multiplier) { - this.multiplier = multiplier; - } - - public double getMaxDistanceSq(int renderDistanceChunks) { - if (this == BASIC) { - return 16.0 * 16.0; - } - - double maxBlocks = (renderDistanceChunks * 16.0) * this.multiplier; - maxBlocks = Math.max(maxBlocks, 16.0); - return maxBlocks * maxBlocks; - } -} diff --git a/game/core/src/main/java/net/minecraft/core/world/particle/ParticleEmitterRegistry.java b/game/core/src/main/java/net/minecraft/core/world/particle/ParticleEmitterRegistry.java deleted file mode 100644 index 14016cc2d..000000000 --- a/game/core/src/main/java/net/minecraft/core/world/particle/ParticleEmitterRegistry.java +++ /dev/null @@ -1,161 +0,0 @@ -package net.minecraft.core.world.particle; - -import it.unimi.dsi.fastutil.longs.Long2ObjectMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import net.minecraft.core.block.Block; -import net.minecraft.core.entity.player.Player; -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 java.util.concurrent.ConcurrentLinkedQueue; - -public final class ParticleEmitterRegistry { - - private record EmitterNode(TilePos pos, ParticleEmitterRange type) { } - - private final Long2ObjectOpenHashMap emitters = new Long2ObjectOpenHashMap<>(); - - private final ConcurrentLinkedQueue pendingAdds = new ConcurrentLinkedQueue<>(); - private final ConcurrentLinkedQueue pendingRemoves = new ConcurrentLinkedQueue<>(); - - private long getPosHash(int x, int y, int z) { - long hash = x & 0x3FFFFFF; - hash |= ((long)(z & 0x3FFFFFF)) << 26; - hash |= ((long)(y & 0xFFF)) << 52; - return hash; - } - - public void add(TilePos pos) { - this.add(pos, ParticleEmitterRange.BASIC); - } - - public void add(@NotNull TilePos pos, ParticleEmitterRange type) { - this.pendingAdds.add(new EmitterNode(new TilePos(pos), type)); - } - - public void add(TilePosc pos) { - this.add(pos, ParticleEmitterRange.BASIC); - } - - public void add(@NotNull TilePosc pos, ParticleEmitterRange type) { - this.pendingAdds.add(new EmitterNode(new TilePos(pos), type)); - } - - public void remove(@NotNull TilePos pos) { - this.pendingRemoves.add(getPosHash(pos.x(), pos.y(), pos.z())); - } - - public void remove(@NotNull TilePosc pos) { - this.pendingRemoves.add(getPosHash(pos.x(), pos.y(), pos.z())); - } - - private void drainPendingQueues() { - while (!this.pendingRemoves.isEmpty()) { - this.emitters.remove(this.pendingRemoves.poll().longValue()); - } - while (!this.pendingAdds.isEmpty()) { - EmitterNode node = this.pendingAdds.poll(); - this.emitters.put(getPosHash(node.pos.x(), node.pos.y(), node.pos.z()), node); - } - } - - public void tick(World world, Player player, int renderDistanceChunks) { - this.drainPendingQueues(); - - if (this.emitters.isEmpty()) return; - - var iterator = this.emitters.long2ObjectEntrySet().fastIterator(); - - while (iterator.hasNext()) { - Long2ObjectMap.Entry entry = iterator.next(); - EmitterNode node = entry.getValue(); - TilePos pos = node.pos; - ParticleEmitterRange type = node.type; - - if (!world.isBlockLoaded(pos)) { - iterator.remove(); - continue; - } - - double dx = pos.x() - player.x; - double dy = pos.y() - player.y; - double dz = pos.z() - player.z; - double distSq = dx * dx + dy * dy + dz * dz; - - if (distSq > type.getMaxDistanceSq(renderDistanceChunks)) continue; - - int throttle = 4; - if (distSq > 4096) { - throttle = 64; - } else if (distSq > 1024) { - throttle = 16; - } - - if (world.rand.nextInt(throttle) == 0) { - Block block = world.getBlockType(pos); - - if (block.getLogic().getParticleEmitterRange() != null) { - block.animationTick(world, pos, world.rand); - } else { - iterator.remove(); - } - } - } - } - - /** - * runs/ticks emitters if any player is within range. - */ - public void tickServer(World world, Iterable players, int renderDistanceChunks) { - this.drainPendingQueues(); - - if (this.emitters.isEmpty()) return; - - var iterator = this.emitters.long2ObjectEntrySet().fastIterator(); - - while (iterator.hasNext()) { - Long2ObjectMap.Entry entry = iterator.next(); - EmitterNode node = entry.getValue(); - TilePos pos = node.pos; - ParticleEmitterRange type = node.type; - - if (!world.isBlockLoaded(pos)) { - iterator.remove(); - continue; - } - - double maxDistSq = type.getMaxDistanceSq(renderDistanceChunks); - double distSq = Double.POSITIVE_INFINITY; - for (Player player : players) { - double dx = pos.x() - player.x; - double dy = pos.y() - player.y; - double dz = pos.z() - player.z; - double d = dx * dx + dy * dy + dz * dz; - if (d <= maxDistSq && d < distSq) { - distSq = d; - } - } - - if (distSq == Double.POSITIVE_INFINITY) continue; - - int throttle = 4; - if (distSq > 4096) { - throttle = 64; - } else if (distSq > 1024) { - throttle = 16; - } - - if (world.rand.nextInt(throttle) == 0) { - Block block = world.getBlockType(pos); - - if (block.getLogic().getParticleEmitterRange() != null) { - block.animationTick(world, pos, world.rand); - } else { - iterator.remove(); - } - } - } - } -} \ No newline at end of file diff --git a/game/core/src/main/resources/assets/minecraft/lang/en_US/gui.lang b/game/core/src/main/resources/assets/minecraft/lang/en_US/gui.lang index de2a55a7a..d97a06674 100644 --- a/game/core/src/main/resources/assets/minecraft/lang/en_US/gui.lang +++ b/game/core/src/main/resources/assets/minecraft/lang/en_US/gui.lang @@ -292,6 +292,7 @@ gui.options.page.debug.button.crash.hard=Crash Hard gui.options.page.debug.button.music.skip=Force Ambient Music gui.options.page.debug.button.garbage_collect=Run Garbage Collector gui.options.page.debug.button.reload_commands=Reload Commands +gui.options.page.debug.button.reset_hud_onboarding=Reset HUD Editor Onboarding gui.options.page.hidden.title=Hidden Options gui.options.page.hidden.category.general=General diff --git a/game/server/src/main/java/net/minecraft/server/MinecraftServer.java b/game/server/src/main/java/net/minecraft/server/MinecraftServer.java index 0c5ac011d..971a45f1e 100644 --- a/game/server/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/game/server/src/main/java/net/minecraft/server/MinecraftServer.java @@ -134,7 +134,6 @@ public class MinecraftServer public int sleepPercentage = 100; public int maxPlayers = 20; public int viewDistance = 10; - public int particleRenderDistance = 10; public Gamemode defaultGamemode; public static String statsToken; public static boolean statsStatus; @@ -243,7 +242,6 @@ public class MinecraftServer NetworkManager.TIMEOUT_TIME = propertyManager.getIntProperty("login-timeout-time", 1800 * 50); maxPlayers = propertyManager.getIntProperty("max-players", 20); viewDistance = propertyManager.getIntProperty("view-distance", 10); - particleRenderDistance = Math.max(1, Math.min(24, propertyManager.getIntProperty("particle-render-distance", 10))); language = propertyManager.getStringProperty("language", "en_US"); disablePhotoMode = propertyManager.getBooleanProperty("disable-photomode", false); name = propertyManager.getStringProperty("name", ""); diff --git a/game/server/src/main/java/net/minecraft/server/entity/EntityTrackerEntryImpl.java b/game/server/src/main/java/net/minecraft/server/entity/EntityTrackerEntryImpl.java index ddcd470ec..8bcccd211 100644 --- a/game/server/src/main/java/net/minecraft/server/entity/EntityTrackerEntryImpl.java +++ b/game/server/src/main/java/net/minecraft/server/entity/EntityTrackerEntryImpl.java @@ -6,9 +6,12 @@ import net.minecraft.core.entity.player.Player; import net.minecraft.core.item.ItemStack; import net.minecraft.core.net.entity.EntityTrackerEntry; import net.minecraft.core.net.entity.NetEntityHandler; +import net.minecraft.core.block.entity.TileEntity; import net.minecraft.core.net.packet.PacketMoveEntity; import net.minecraft.core.net.packet.Packet; +import net.minecraft.core.net.packet.PacketSetRiding; import net.minecraft.core.net.packet.PacketSleep; +import net.minecraft.core.world.IVehicle; import net.minecraft.core.net.packet.PacketSetEntityMotion; import net.minecraft.core.net.packet.PacketRemoveEntity; import net.minecraft.core.net.packet.PacketTeleportEntity; @@ -19,6 +22,7 @@ import net.minecraft.core.net.packet.PacketSetEquippedItem; import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.world.data.SynchedEntityData; import net.minecraft.server.entity.player.PlayerServer; +import org.jetbrains.annotations.NotNull; import java.util.HashSet; import java.util.List; @@ -43,6 +47,7 @@ public class EntityTrackerEntryImpl implements EntityTrackerEntry { private boolean firstUpdateDone; private final boolean shouldSendMotionUpdates; private int ticksSinceLastTeleport; + private IVehicle lastTrackedVehicle; private final SynchedEntityData synchedEntityData; public boolean playerEntitiesUpdated; public Set trackedPlayers; @@ -62,6 +67,7 @@ public class EntityTrackerEntryImpl implements EntityTrackerEntry { encodedPosZ = MathHelper.floor(entity.z * 32D); encodedRotationYaw = MathHelper.floor_float((entity.yRot * 256F) / 360F); encodedRotationPitch = MathHelper.floor_float((entity.xRot * 256F) / 360F); + lastTrackedVehicle = entity.vehicle; } @Override @@ -97,7 +103,7 @@ public class EntityTrackerEntryImpl implements EntityTrackerEntry { int dy = entityY - encodedPosY; int dz = entityZ - encodedPosZ; Packet packet = null; - boolean hasMoved = java.lang.Math.abs(entityX) >= 8 || java.lang.Math.abs(entityY) >= 8 || java.lang.Math.abs(entityZ) >= 8; + boolean hasMoved = java.lang.Math.abs(dx) >= 2 || java.lang.Math.abs(dy) >= 2 || java.lang.Math.abs(dz) >= 2; boolean hasLooked = java.lang.Math.abs(entityYaw - encodedRotationYaw) >= 8 || java.lang.Math.abs(entityPitch - encodedRotationPitch) >= 8; if(dx < -128 || dx >= 128 || dy < -128 || dy >= 128 || dz < -128 || dz >= 128 || ticksSinceLastTeleport > 400) { ticksSinceLastTeleport = 0; @@ -149,6 +155,24 @@ public class EntityTrackerEntryImpl implements EntityTrackerEntry { sendPacketToTrackedPlayersAndTrackedEntity(new PacketEntityNickname(trackedEntity.id, ((Mob) trackedEntity).nickname, ((Mob) trackedEntity).chatColor)); trackedEntity.hadNicknameSet = false; } + if (trackedEntity.additionalDataChanged) { + sendPacketToTrackedPlayers(new PacketEntityTagData(trackedEntity)); + trackedEntity.additionalDataChanged = false; + } + + if (trackedEntity.vehicle != lastTrackedVehicle) { + lastTrackedVehicle = trackedEntity.vehicle; + sendPacketToTrackedPlayers(createRidingPacket()); + } + } + + private @NotNull PacketSetRiding createRidingPacket() { + if (trackedEntity.vehicle instanceof Entity) { + return new PacketSetRiding(trackedEntity, (Entity) trackedEntity.vehicle); + } else if (trackedEntity.vehicle instanceof TileEntity tileEntity) { + return new PacketSetRiding(trackedEntity, tileEntity.tilePos.x, tileEntity.tilePos.y, tileEntity.tilePos.z); + } + return new PacketSetRiding(trackedEntity, null); // dismount } public void sendPacketToTrackedPlayers(Packet packet) { @@ -178,8 +202,10 @@ public class EntityTrackerEntryImpl implements EntityTrackerEntry { if(playerServer == trackedEntity) { return; } - double dx = playerServer.x - (double)(encodedPosX / 32); - double dz = playerServer.z - (double)(encodedPosZ / 32); + + double dx = playerServer.x - trackedEntity.x; + double dz = playerServer.z - trackedEntity.z; + if(dx >= (double)(-trackingDistance) && dx <= (double)trackingDistance && dz >= (double)(-trackingDistance) && dz <= (double)trackingDistance) { if(!trackedPlayers.contains(playerServer)) { trackedPlayers.add(playerServer); @@ -203,6 +229,12 @@ public class EntityTrackerEntryImpl implements EntityTrackerEntry { playerServer.playerNetServerHandler.sendPacket(new PacketSleep(trackedEntity, 0, MathHelper.floor(trackedEntity.x), MathHelper.floor(trackedEntity.y), MathHelper.floor(trackedEntity.z))); } } + if (trackedEntity.vehicle != null) { + playerServer.playerNetServerHandler.sendPacket(createRidingPacket()); + } + if (trackedEntity.passenger != null) { + playerServer.playerNetServerHandler.sendPacket(new PacketSetRiding(trackedEntity.passenger, trackedEntity)); + } } } else if(trackedPlayers.contains(playerServer)) { trackedPlayers.remove(playerServer); diff --git a/game/server/src/main/java/net/minecraft/server/entity/player/PlayerServer.java b/game/server/src/main/java/net/minecraft/server/entity/player/PlayerServer.java index a9dd6427b..676660862 100644 --- a/game/server/src/main/java/net/minecraft/server/entity/player/PlayerServer.java +++ b/game/server/src/main/java/net/minecraft/server/entity/player/PlayerServer.java @@ -6,6 +6,7 @@ import net.minecraft.core.block.Blocks; import net.minecraft.core.block.entity.*; import net.minecraft.core.crafting.ContainerListener; import net.minecraft.core.entity.*; +import net.minecraft.core.entity.animal.MobPig; import net.minecraft.core.entity.player.Player; import net.minecraft.core.entity.projectile.ProjectileArrow; import net.minecraft.core.enums.EnumSleepStatus; @@ -22,6 +23,7 @@ import net.minecraft.core.world.ICarriable; import net.minecraft.core.world.IVehicle; import net.minecraft.core.world.chunk.Chunk; import net.minecraft.core.world.chunk.ChunkSection; +import net.minecraft.core.world.pos.ChunkPos; import net.minecraft.core.world.pos.TilePos; import net.minecraft.core.world.pos.TilePosc; import net.minecraft.server.entity.EntityTrackerImpl; @@ -183,17 +185,7 @@ public class PlayerServer extends Player implements ContainerListener { playerController.tick(); ticksOfInvuln--; containerMenu.broadcastChanges(); - - ItemStack heldItem = inventory.getHeldItemStack(); - if (!ItemStack.areItemStacksEqual(heldItem, lastHeldItem)) - { - if (playerNetServerHandler != null) - { - playerNetServerHandler.sendPacket(new PacketContainerSetSlot(-1, -1, heldItem)); - } - lastHeldItem = heldItem == null ? null : heldItem.copy(); - } - + broadcastCarried(containerMenu); for (int i = 0; i < 5; i++) { ItemStack itemstack = getEquipmentInSlot(i); @@ -310,7 +302,7 @@ public class PlayerServer extends Player implements ContainerListener { { usePersonalCraftingInventory(); } - if (vehicle != null) + if (vehicle != null && !(vehicle instanceof MobPig)) { startRiding(vehicle); } @@ -372,6 +364,10 @@ public class PlayerServer extends Player implements ContainerListener { { WorldServer worldserver = mcServer.getDimensionWorld(dimension); loadedChunks.remove(chunkCoord); + ChunkPos sentChunkPos = new ChunkPos(chunkCoord.x, chunkCoord.z); + if (worldserver.isChunkLoaded(sentChunkPos)) { + worldserver.getChunk(sentChunkPos, true).sentToClients = true; + } playerNetServerHandler.sendPacket(new PacketBlockRegionUpdate(chunkCoord.x * Chunk.CHUNK_SIZE_X, 0, chunkCoord.z * Chunk.CHUNK_SIZE_Z, Chunk.CHUNK_SIZE_X, Chunk.CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y, Chunk.CHUNK_SIZE_Z, worldserver)); List list = worldserver.getBlockEntitiesWithinBounds(chunkCoord.x * Chunk.CHUNK_SIZE_X, 0, chunkCoord.z * Chunk.CHUNK_SIZE_Z, chunkCoord.x * Chunk.CHUNK_SIZE_X + Chunk.CHUNK_SIZE_X, Chunk.CHUNK_SECTIONS * ChunkSection.SECTION_SIZE_Y, chunkCoord.z * Chunk.CHUNK_SIZE_Z + Chunk.CHUNK_SIZE_Z); for (int j = 0; j < list.size(); j++) @@ -616,17 +612,9 @@ public class PlayerServer extends Player implements ContainerListener { { return; } - if (isChangingQuantityOnly) + if (playerNetServerHandler != null) { - return; - } - else - { - if (playerNetServerHandler != null) - { - playerNetServerHandler.sendPacket(new PacketContainerSetSlot(container.containerId, i, itemstack)); - } - return; + playerNetServerHandler.sendPacket(new PacketContainerSetSlot(container.containerId, container.getStateId(), i, itemstack)); } } @@ -638,13 +626,12 @@ public class PlayerServer extends Player implements ContainerListener { @Override public void updateCraftingInventory(MenuAbstract container, List list) { - - //playernetserverhandler returning false? + ItemStack held = inventory.getHeldItemStack(); if (playerNetServerHandler != null) { - playerNetServerHandler.sendPacket(new PacketContainerSetContent(container.containerId, list)); -// playerNetServerHandler.sendPacket(new ContainerSetSlotPacket(-1, -1, inventory.getHeldItemStack())); + playerNetServerHandler.sendPacket(new PacketContainerSetContent(container.containerId, container.getStateId(), list, held)); } + remoteCarried = held == null ? null : held.copy(); } @Override @@ -659,23 +646,39 @@ public class PlayerServer extends Player implements ContainerListener { closeCraftingGui(); } - public void updateHeldItem() + public void setRemoteCarried(ItemStack stack) { - if (isChangingQuantityOnly) + remoteCarried = stack == null ? null : stack.copy(); + } + + public void broadcastCarried(MenuAbstract container) + { + if (playerNetServerHandler == null) { return; } - else + ItemStack held = inventory.getHeldItemStack(); + if (ItemStack.areItemStacksEqual(held, remoteCarried)) { - playerNetServerHandler.sendPacket(new PacketContainerSetSlot(-1, -1, inventory.getHeldItemStack())); return; } + container.incrementStateId(); + playerNetServerHandler.sendPacket(new PacketContainerSetSlot(-1, container.getStateId(), -1, held)); + remoteCarried = held == null ? null : held.copy(); + } + + public void broadcastFullState(MenuAbstract container) + { + container.incrementStateId(); + updateCraftingInventory(container, container.getSlotStackList()); + container.resetRemoteSlots(); } public void closeCraftingGui() { containerMenu.onCraftGuiClosed(this); containerMenu = inventoryMenu; + broadcastFullState(containerMenu); } public void setMovementType(float f, float f1, boolean flag, boolean flag1, float f2, float f3) @@ -758,6 +761,11 @@ public class PlayerServer extends Player implements ContainerListener { this.playerNetServerHandler.sendPacket(new PacketEntityFling(this.id, this.xd, this.yd, this.zd, this.pushTime, this.pushesThisTick)); } + @Override + public void onVehicleFlung(final Entity vehicle) { + this.playerNetServerHandler.sendPacket(new PacketEntityFling(vehicle.id, vehicle.xd, vehicle.yd, vehicle.zd, vehicle.pushTime, vehicle.pushesThisTick)); + } + @Override public void setHeldObject(@Nullable ICarriable heldObject) { super.setHeldObject(heldObject); @@ -816,7 +824,6 @@ public class PlayerServer extends Player implements ContainerListener { private ItemStack[] playerInventory = { null, null, null, null, null }; - private ItemStack lastHeldItem; private int currentWindowId; - public boolean isChangingQuantityOnly; + private ItemStack remoteCarried; } diff --git a/game/server/src/main/java/net/minecraft/server/net/PlayerList.java b/game/server/src/main/java/net/minecraft/server/net/PlayerList.java index 8719b4eab..5c0b843da 100644 --- a/game/server/src/main/java/net/minecraft/server/net/PlayerList.java +++ b/game/server/src/main/java/net/minecraft/server/net/PlayerList.java @@ -6,6 +6,8 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.minecraft.core.achievement.Achievements; import net.minecraft.core.block.entity.TileEntity; import net.minecraft.core.data.registry.Registries; +import net.minecraft.core.entity.Entity; +import net.minecraft.core.entity.animal.MobPig; import net.minecraft.core.entity.player.Player; import net.minecraft.core.util.helper.DyeColor; import net.minecraft.core.util.helper.UUIDHelper; @@ -122,6 +124,19 @@ public class PlayerList world.getChunkProvider().prepareChunk((int) player.x >> 4, (int) player.z >> 4); } + public void resendChunksAfterTeleport(PlayerServer player) + { + int viewChunkX = (int) player.viewingX >> 4; + int viewChunkZ = (int) player.viewingZ >> 4; + int chunkX = (int) player.x >> 4; + int chunkZ = (int) player.z >> 4; + if (viewChunkX == chunkX && viewChunkZ == chunkZ) + { + return; + } + syncPlayerDimension(player); + } + public int getMaxTrackingDistance() { return playerManagers.get(0).getMaxTrackingDistance(); @@ -163,8 +178,13 @@ public class PlayerList public void playerLoggedOut(PlayerServer entityplayermp) { + Entity mount = entityplayermp.vehicle instanceof MobPig ? (Entity) entityplayermp.vehicle : null; playerIo.save(entityplayermp); - server.getDimensionWorld(entityplayermp.dimension).setEntityDead(entityplayermp); + WorldServer worldserver = server.getDimensionWorld(entityplayermp.dimension); + worldserver.setEntityDead(entityplayermp); + if (mount != null) { + worldserver.setEntityDead(mount); + } playerEntities.remove(entityplayermp); getPlayerManager(entityplayermp.dimension).removePlayer(entityplayermp); } @@ -217,12 +237,15 @@ public class PlayerList newPlayer.id = previousPlayer.id; newPlayer.chatColor = previousPlayer.chatColor; newPlayer.nickname = previousPlayer.nickname; - newPlayer.gamemode = previousPlayer.gamemode; + newPlayer.setGamemodeOnLogin(previousPlayer.gamemode); + newPlayer.rotationLock = previousPlayer.rotationLock; + newPlayer.rotationLockHorizontal = previousPlayer.rotationLockHorizontal; + newPlayer.rotationLockVertical = previousPlayer.rotationLockVertical; + newPlayer.placementModeOverride = previousPlayer.placementModeOverride; newPlayer.playerNetServerHandler = previousPlayer.playerNetServerHandler; newPlayer.inventory.transferAllContents(previousPlayer.inventory); newPlayer.playerConfig.config = previousPlayer.playerConfig.config; WorldServer worldserver = server.getDimensionWorld(previousPlayer.dimension); - //entityplayermp1.setGamemodeOnLogin(entityplayermp.gamemode); if (chunkcoordinates != null) { final TilePos bedCoordinates = Player.getValidBedSpawnCoordinates(this.server.getDimensionWorld(previousPlayer.dimension), chunkcoordinates); @@ -260,10 +283,15 @@ public class PlayerList Dimension lastDim = Dimension.getDimensionList().get(playerServer.dimension); Dimension newDim = Dimension.getDimensionList().get(targetDim); + Entity mount = playerServer.vehicle instanceof MobPig ? (Entity) playerServer.vehicle : null; + playerServer.dimension = targetDim; WorldServer worldserver1 = server.getDimensionWorld(playerServer.dimension); playerServer.playerNetServerHandler.sendPacket(new PacketRespawn((byte) playerServer.dimension, (byte) Registries.WORLD_TYPES.getNumericIdOfItem(worldserver1.getWorldType()))); worldserver.removePlayer(playerServer); + if (mount != null) { + worldserver.removePlayer(mount); + } playerServer.removed = false; double x = playerServer.x; double y = playerServer.y; @@ -306,6 +334,16 @@ public class PlayerList setTime(playerServer, worldserver1); initializePlayerObject(playerServer); playerServer.playerNetServerHandler.sendPacket(new PacketGameRule(server.getDimensionWorld(0).getLevelData().getGameRules())); + playerServer.playerNetServerHandler.sendPacket(new PacketSetHotbarOffset(playerServer.inventory.getHotbarOffset())); + playerServer.playerNetServerHandler.sendPacket(new PacketSetCarriedItem(playerServer.inventory.getCurrentSlot())); + + if (mount != null && playerServer.isAlive()) { + mount.removed = false; + mount.world = worldserver1; + mount.moveTo(playerServer.x, playerServer.y, playerServer.z, playerServer.yRot, mount.xRot); + worldserver1.entityJoinedWorld(mount); + playerServer.playerNetServerHandler.sendPacket(new PacketSetRiding(playerServer, mount)); + } } public void onTick() diff --git a/game/server/src/main/java/net/minecraft/server/net/command/ConsoleCommandSource.java b/game/server/src/main/java/net/minecraft/server/net/command/ConsoleCommandSource.java index 930940cd7..57c76d7fe 100644 --- a/game/server/src/main/java/net/minecraft/server/net/command/ConsoleCommandSource.java +++ b/game/server/src/main/java/net/minecraft/server/net/command/ConsoleCommandSource.java @@ -121,16 +121,18 @@ public class ConsoleCommandSource implements CommandSource, IServerCommandSource @Override public void teleportPlayerToPos(Player player, double x, double y, double z) { - if (player instanceof PlayerServer) + if (player instanceof PlayerServer) { ((PlayerServer) player).playerNetServerHandler.teleport(x, y, z); - else throw new IllegalStateException("Player is not an instance of PlayerServer"); + this.server.playerList.resendChunksAfterTeleport((PlayerServer) player); + } else throw new IllegalStateException("Player is not an instance of PlayerServer"); } @Override public void teleportPlayerToPosAndRot(Player player, double x, double y, double z, float yaw, float pitch) { - if (player instanceof PlayerServer) + if (player instanceof PlayerServer) { ((PlayerServer) player).playerNetServerHandler.teleportAndRotate(x, y, z, yaw, pitch); - else throw new IllegalStateException("Player is not an instance of PlayerServer"); + this.server.playerList.resendChunksAfterTeleport((PlayerServer) player); + } else throw new IllegalStateException("Player is not an instance of PlayerServer"); } @Override diff --git a/game/server/src/main/java/net/minecraft/server/net/command/ServerCommandSource.java b/game/server/src/main/java/net/minecraft/server/net/command/ServerCommandSource.java index 9475420f2..b07067416 100644 --- a/game/server/src/main/java/net/minecraft/server/net/command/ServerCommandSource.java +++ b/game/server/src/main/java/net/minecraft/server/net/command/ServerCommandSource.java @@ -125,16 +125,18 @@ public class ServerCommandSource implements CommandSource, IServerCommandSource @Override public void teleportPlayerToPos(Player player, double x, double y, double z) { - if (player instanceof PlayerServer) + if (player instanceof PlayerServer) { ((PlayerServer) player).playerNetServerHandler.teleport(x, y, z); - else throw new IllegalStateException("Player is not an instance of PlayerServer"); + this.server.playerList.resendChunksAfterTeleport((PlayerServer) player); + } else throw new IllegalStateException("Player is not an instance of PlayerServer"); } @Override public void teleportPlayerToPosAndRot(Player player, double x, double y, double z, float yaw, float pitch) { - if (player instanceof PlayerServer) + if (player instanceof PlayerServer) { ((PlayerServer) player).playerNetServerHandler.teleportAndRotate(x, y, z, yaw, pitch); - else throw new IllegalStateException("Player is not an instance of PlayerServer"); + this.server.playerList.resendChunksAfterTeleport((PlayerServer) player); + } else throw new IllegalStateException("Player is not an instance of PlayerServer"); } @Override diff --git a/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerServer.java b/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerServer.java index 2bb059989..ae6bce942 100644 --- a/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerServer.java +++ b/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerServer.java @@ -2,14 +2,13 @@ package net.minecraft.server.net.handler; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.logging.LogUtils; -import it.unimi.dsi.fastutil.ints.Int2ShortArrayMap; -import it.unimi.dsi.fastutil.ints.Int2ShortMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.minecraft.core.block.entity.TileEntity; import net.minecraft.core.block.entity.TileEntityFlag; import net.minecraft.core.block.entity.TileEntityMobSpawner; import net.minecraft.core.block.entity.TileEntitySign; import net.minecraft.core.entity.Entity; -import net.minecraft.core.entity.vehicle.EntityBoat; +import net.minecraft.core.entity.animal.MobPig; import net.minecraft.core.enums.ArtType; import net.minecraft.core.enums.EnumSignPicture; import net.minecraft.core.enums.PlacementMode; @@ -26,6 +25,7 @@ import net.minecraft.core.world.pos.TilePos; import net.minecraft.server.net.command.ServerCommandSource; import net.minecraft.core.net.handler.PacketHandler; import net.minecraft.core.net.packet.*; +import net.minecraft.core.player.inventory.menu.MenuAbstract; import net.minecraft.core.player.inventory.menu.MenuFlag; import net.minecraft.core.player.inventory.menu.MenuInventoryCreative; import net.minecraft.core.player.inventory.slot.Slot; @@ -62,13 +62,11 @@ public class PacketHandlerServer extends PacketHandler private double lastPosY; private double lastPosZ; private boolean hasMoved; - private final Int2ShortMap guiIdMap; public PacketHandlerServer(MinecraftServer minecraftserver, NetworkManager networkManager, PlayerServer player) { this.connectionClosed = false; this.hasMoved = true; - this.guiIdMap = new Int2ShortArrayMap(); this.mcServer = minecraftserver; this.netManager = networkManager; networkManager.setNetHandler(this); @@ -434,18 +432,19 @@ public class PacketHandlerServer extends PacketHandler if (itemstack != null && itemstack.stackSize <= 0) { this.playerEntity.inventory.mainInventory[this.playerEntity.inventory.getCurrentSlot()] = null; } - this.playerEntity.isChangingQuantityOnly = true; this.playerEntity.inventory.mainInventory[this.playerEntity.inventory.getCurrentSlot()] = ItemStack.copyItemStack(this.playerEntity.inventory.mainInventory[this.playerEntity.inventory.getCurrentSlot()]); - Slot slot = this.playerEntity.containerMenu.getSlotFor(this.playerEntity.inventory, this.playerEntity.inventory.getCurrentSlot()); - this.playerEntity.containerMenu.broadcastChanges(); - this.playerEntity.isChangingQuantityOnly = false; + MenuAbstract menu = this.playerEntity.containerMenu; + Slot slot = menu.getSlotFor(this.playerEntity.inventory, this.playerEntity.inventory.getCurrentSlot()); if (slot == null) { - LOGGER.warn("Couldn't find slot for index '{}' in {}'s inventory while they were in the {} container!", this.playerEntity.inventory.getCurrentSlot(), this.playerEntity.username, this.playerEntity.containerMenu.getClass().getSimpleName()); + LOGGER.warn("Couldn't find slot for index '{}' in {}'s inventory while they were in the {} container!", this.playerEntity.inventory.getCurrentSlot(), this.playerEntity.username, menu.getClass().getSimpleName()); return; } - if (!ItemStack.areItemStacksEqual(this.playerEntity.inventory.getCurrentItem(), packet.itemStack)) { - sendPacket(new PacketContainerSetSlot(this.playerEntity.containerMenu.containerId, slot.index, this.playerEntity.inventory.getCurrentItem())); + ItemStack current = this.playerEntity.inventory.getCurrentItem(); + if (!ItemStack.areItemStacksEqual(current, packet.itemStack)) { + menu.incrementStateId(); + sendPacket(new PacketContainerSetSlot(menu.containerId, menu.getStateId(), slot.index, current)); } + menu.setRemoteSlot(slot.index, current); } @Override @@ -570,13 +569,21 @@ public class PacketHandlerServer extends PacketHandler } @Override - public void handleBoatControl(@NotNull PacketBoatControl packetBoatControl) { - if (!canInteract() || Double.isNaN(packetBoatControl.targetXD) || Double.isNaN(packetBoatControl.targetZD)) + public void handleVehicleControl(@NotNull PacketVehicleControl packetVehicleControl) { + if (!canInteract() + || Double.isNaN(packetVehicleControl.targetXD) + || Double.isNaN(packetVehicleControl.targetYD) + || Double.isNaN(packetVehicleControl.targetZD)) return; - if (this.playerEntity.vehicle != null && this.playerEntity.vehicle instanceof EntityBoat boat) { - boat.handleControlDirect(packetBoatControl.targetXD, packetBoatControl.targetZD, packetBoatControl.targetYRot); - packetBoatControl.entityId = boat.id; - this.mcServer.playerList.sendPacketToOtherPlayersAroundPoint(this.playerEntity, boat.x, boat.y, boat.z, 128, boat.world.dimension.id, packetBoatControl); + if (this.playerEntity.vehicle instanceof Entity vehicle) { + vehicle.handleControlDirect(packetVehicleControl.targetXD, packetVehicleControl.targetYD, packetVehicleControl.targetZD, packetVehicleControl.targetYRot); + if (vehicle instanceof MobPig pig && packetVehicleControl.fallDistance > 0f) { + pig.applyRiderFallDamage(packetVehicleControl.fallDistance); + } + if (vehicle.relaysVehicleControl()) { + packetVehicleControl.entityId = vehicle.id; + this.mcServer.playerList.sendPacketToOtherPlayersAroundPoint(this.playerEntity, vehicle.x, vehicle.y, vehicle.z, 128, vehicle.world.dimension.id, packetVehicleControl); + } } } @@ -661,34 +668,38 @@ public class PacketHandlerServer extends PacketHandler @Override public void handleContainerClick(@NotNull PacketContainerClick packetContainerClick) { - if (this.playerEntity.containerMenu.containerId == packetContainerClick.window_Id && this.playerEntity.containerMenu.isSynched(this.playerEntity)) { - ItemStack itemstack = this.playerEntity.containerMenu.clicked(packetContainerClick.action, packetContainerClick.args, this.playerEntity); - if (ItemStack.areItemStacksEqual(packetContainerClick.itemStack, itemstack)) { - this.playerEntity.playerNetServerHandler.sendPacket(new PacketContainerAck(packetContainerClick.window_Id, packetContainerClick.actionId, true)); - this.playerEntity.isChangingQuantityOnly = true; - this.playerEntity.containerMenu.broadcastChanges(); - this.playerEntity.updateHeldItem(); - this.playerEntity.isChangingQuantityOnly = false; - } else { - this.guiIdMap.put(this.playerEntity.containerMenu.containerId, packetContainerClick.actionId); - this.playerEntity.playerNetServerHandler.sendPacket(new PacketContainerAck(packetContainerClick.window_Id, packetContainerClick.actionId, false)); - this.playerEntity.containerMenu.setSynched(this.playerEntity, false); - ArrayList arraylist = new ArrayList<>(); - for (int i = 0; i < this.playerEntity.containerMenu.slots.size(); i++) { - arraylist.add(this.playerEntity.containerMenu.slots.get(i).getItemStack()); - } + MenuAbstract menu = this.playerEntity.containerMenu; + if (menu.containerId != packetContainerClick.window_Id) { + return; + } + + boolean stale = packetContainerClick.stateId != menu.getStateId(); - this.playerEntity.updateCraftingInventory(this.playerEntity.containerMenu, arraylist); + menu.setRemoteUpdatesSuppressed(true); + menu.clicked(packetContainerClick.action, packetContainerClick.args, this.playerEntity); + menu.setRemoteUpdatesSuppressed(false); + + if (packetContainerClick.changedSlots != null) { + for (Int2ObjectMap.Entry entry : packetContainerClick.changedSlots.int2ObjectEntrySet()) { + int slot = entry.getIntKey(); + if (slot >= 0 && slot < menu.slots.size()) { + menu.setRemoteSlot(slot, entry.getValue()); + } } } + this.playerEntity.setRemoteCarried(packetContainerClick.carriedItem); + + if (stale) { + this.playerEntity.broadcastFullState(menu); + } else { + menu.broadcastChanges(); + this.playerEntity.broadcastCarried(menu); + } } @Override public void handleContainerAck(@NotNull PacketContainerAck packet) { - short short1 = this.guiIdMap.get(this.playerEntity.containerMenu.containerId); - if (packet.shortWindowId == short1 && this.playerEntity.containerMenu.containerId == packet.windowId && !this.playerEntity.containerMenu.isSynched(this.playerEntity)) { - this.playerEntity.containerMenu.setSynched(this.playerEntity, true); - } + //reconciliation of state ids and delta corrections render container ack deprecated } @Override diff --git a/game/server/src/main/java/net/minecraft/server/player/PlayerManager.java b/game/server/src/main/java/net/minecraft/server/player/PlayerManager.java index 5db1056dd..ebdc7e658 100644 --- a/game/server/src/main/java/net/minecraft/server/player/PlayerManager.java +++ b/game/server/src/main/java/net/minecraft/server/player/PlayerManager.java @@ -1,6 +1,7 @@ package net.minecraft.server.player; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import com.mojang.logging.LogUtils; @@ -160,13 +161,14 @@ public class PlayerManager { return; } + List chunksToAdd = new ArrayList<>(); for(int _cx = chunkX - viewRadius; _cx <= chunkX + viewRadius; _cx++) { for(int _cz = chunkZ - viewRadius; _cz <= chunkZ + viewRadius; _cz++) { if(!chunkWithinViewRadius(_cx, _cz, playerChunkX, playerChunkZ)) // If chunk was not in previous render radius add the chunk to the player { - getPlayerInstance(_cx, _cz, true).addPlayer(player); + chunksToAdd.add(new ChunkCoordinate(_cx, _cz)); } if(chunkWithinViewRadius(_cx - cDX, _cz - cDZ, chunkX, chunkZ)) { @@ -181,6 +183,16 @@ public class PlayerManager } + chunksToAdd.sort(Comparator.comparingInt(c -> { + int ddx = c.x - chunkX; + int ddz = c.z - chunkZ; + return ddx * ddx + ddz * ddz; + })); + for(ChunkCoordinate chunk : chunksToAdd) + { + getPlayerInstance(chunk.x, chunk.z, true).addPlayer(player); + } + player.viewingX = player.x; player.viewingZ = player.z; } diff --git a/game/server/src/main/java/net/minecraft/server/world/WorldServer.java b/game/server/src/main/java/net/minecraft/server/world/WorldServer.java index 04cc95bc3..216a26b2b 100644 --- a/game/server/src/main/java/net/minecraft/server/world/WorldServer.java +++ b/game/server/src/main/java/net/minecraft/server/world/WorldServer.java @@ -278,10 +278,6 @@ public class WorldServer extends World { public void tick() { super.tick(); - if (!this.players.isEmpty()) { - this.particleEmitters.tickServer(this, this.players, this.mcServer.particleRenderDistance); - } - if (System.currentTimeMillis() - lastWeatherSend > 1000) { mcServer.playerList.sendPacketToAllPlayers(new PacketWeatherStatus(dimension.id, getCurrentWeather() != null ? getCurrentWeather().getId() : -1, getWeatherManager().getNextWeather() != null ? getWeatherManager().getNextWeather().getId() : -1, getWeatherManager().getWeatherDuration(), getWeatherManager().getWeatherIntensity(), getWeatherManager().getWeatherPower())); lastWeatherSend = System.currentTimeMillis(); diff --git a/game/server/src/main/java/net/minecraft/server/world/chunk/provider/ChunkProviderServer.java b/game/server/src/main/java/net/minecraft/server/world/chunk/provider/ChunkProviderServer.java index 5652e2676..92fef2466 100644 --- a/game/server/src/main/java/net/minecraft/server/world/chunk/provider/ChunkProviderServer.java +++ b/game/server/src/main/java/net/minecraft/server/world/chunk/provider/ChunkProviderServer.java @@ -27,6 +27,8 @@ public class ChunkProviderServer private final Map chunkMap; private final List chunkList; private final WorldServer world; + private boolean decorating = false; + private boolean warnedRecursiveGeneration = false; public ChunkProviderServer(WorldServer world, ChunkLoader chunkLoader, ChunkGenerator chunkGenerator) { this.droppedChunksSet = new HashSet<>(); @@ -159,6 +161,13 @@ public class ChunkProviderServer public @NotNull Chunk provideChunk(@NotNull ChunkPosc chunkPos, boolean priority) { Chunk chunk = this.chunkMap.get(chunkPos); if (chunk == null) { + if (this.decorating) { + if (!this.warnedRecursiveGeneration) { + this.warnedRecursiveGeneration = true; + LOGGER.warn("Blocked recursive chunk generation at X:{}, Z:{} during decoration!", chunkPos.x(), chunkPos.z(), new Throwable("Stack trace")); + } + return this.emptyChunk; + } if (this.world.findingSpawnPoint || this.chunkLoadOverride) { return prepareChunk(chunkPos, true); } else { @@ -203,7 +212,13 @@ public class ChunkProviderServer if (!chunk.isTerrainPopulated) { chunk.isTerrainPopulated = true; if (this.chunkGenerator != null) { - this.chunkGenerator.decorate(chunk); + this.decorating = true; + this.warnedRecursiveGeneration = false; + try { + this.chunkGenerator.decorate(chunk); + } finally { + this.decorating = false; + } chunk.setChunkModified(); } } diff --git a/util/datagen/src/main/java/net/minecraft/datagen/TrommelGenerator.java b/util/datagen/src/main/java/net/minecraft/datagen/TrommelGenerator.java index 095655ba5..81de6c796 100644 --- a/util/datagen/src/main/java/net/minecraft/datagen/TrommelGenerator.java +++ b/util/datagen/src/main/java/net/minecraft/datagen/TrommelGenerator.java @@ -51,7 +51,7 @@ public class TrommelGenerator { RecipeBuilder.Trommel(RecipesGenerator.CORE_NAMESPACE) .setInput(Blocks.DIRT_SCORCHED_RICH) - .addEntry(new WeightedRandomLootObject(new ItemStack(Items.ORE_RAW_GOLD), 1), 10) + .addEntry(new WeightedRandomLootObject(new ItemStack(Items.ORE_RAW_GOLD), 1, 2), 10) .addEntry(new WeightedRandomLootObject(new ItemStack(Items.ORE_RAW_IRON), 1, 2), 15) .addEntry(new WeightedRandomLootObject(new ItemStack(Items.QUARTZ), 1, 4), 25) .addEntry(new WeightedRandomLootObject(new ItemStack(Items.OLIVINE), 1, 4), 25) @@ -80,24 +80,24 @@ public class TrommelGenerator { .addEntry(new WeightedRandomLootObject(new ItemStack(Items.DUST_GLOWSTONE), 1, 6), 5) .addEntry(new WeightedRandomLootObject(new ItemStack(Items.NETHERCOAL), 1), 2) .addEntry(new WeightedRandomLootObject(new ItemStack(Items.AMMO_PEBBLE), 1, 2), 15) - .create("soul_sand"); + .create("soulsand"); RecipeBuilder.Trommel(RecipesGenerator.CORE_NAMESPACE) .setInput(Blocks.BRIMSAND) .addEntry(new WeightedRandomLootObject(new ItemStack(Items.AMMO_PEBBLE), 2, 3), 35) .addEntry(new WeightedRandomLootObject(new ItemStack(Items.GUNPOWDER), 1, 2), 25) - .addEntry(new WeightedRandomLootObject(new ItemStack(Items.BONE), 1, 2), 10) + .addEntry(new WeightedRandomLootObject(new ItemStack(Items.BONE), 1, 2), 5) .addEntry(new WeightedRandomLootObject(new ItemStack(Items.DUST_GLOWSTONE), 1, 2), 10) .addEntry(new WeightedRandomLootObject(new ItemStack(Items.FLINT), 1, 2), 5) - .addEntry(new WeightedRandomLootObject(new ItemStack(Items.SULFUR), 1, 2), 5) + .addEntry(new WeightedRandomLootObject(new ItemStack(Items.SULFUR), 1, 2), 10) .addEntry(new WeightedRandomLootObject(new ItemStack(Items.NETHERCOAL), 1), 5) .addEntry(new WeightedRandomLootObject(new ItemStack(Items.ORE_RAW_GOLD), 1), 0.5) .create("brimsand"); RecipeBuilder.Trommel(RecipesGenerator.CORE_NAMESPACE) .setInput(Blocks.SULFUR) - .addEntry(new WeightedRandomLootObject(new ItemStack(Items.SULFUR), 2, 5), 30) - .addEntry(new WeightedRandomLootObject(new ItemStack(Items.DUST_GLOWSTONE), 1, 3), 20) + .addEntry(new WeightedRandomLootObject(new ItemStack(Items.DUST_GLOWSTONE), 2, 5), 30) + .addEntry(new WeightedRandomLootObject(new ItemStack(Items.SULFUR), 2, 4), 20) .addEntry(new WeightedRandomLootObject(new ItemStack(Items.BONE), 1, 2), 10) .addEntry(new WeightedRandomLootObject(new ItemStack(Items.FLINT), 1, 2), 5) .addEntry(new WeightedRandomLootObject(new ItemStack(Items.ORE_RAW_IRON), 1, 2), 4)