diff --git a/api/src/main/java/org/geysermc/geyser/api/bedrock/gui/GuiData.java b/api/src/main/java/org/geysermc/geyser/api/bedrock/gui/GuiData.java
new file mode 100644
index 000000000..706a29d79
--- /dev/null
+++ b/api/src/main/java/org/geysermc/geyser/api/bedrock/gui/GuiData.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.api.bedrock.gui;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+import java.util.Set;
+
+public interface GuiData {
+ /**
+ * Hides a {@link GuiElement} on the client's side.
+ *
+ * @param element the {@link GuiElement} to hide
+ */
+ void hideElement(@NonNull GuiElement... element);
+
+ /**
+ * Resets a {@link GuiElement} on the client's side.
+ * This makes the client decide on its own - e.g. based on client settings -
+ * whether to show or hide the gui element.
+ *
+ * If no elements are specified, this will reset all currently hidden elements
+ *
+ * @param element the {@link GuiElement} to reset
+ */
+ void resetElement(@NonNull GuiElement @Nullable ... element);
+
+ /**
+ * Determines whether a {@link GuiElement} is currently hidden.
+ *
+ * @param element the {@link GuiElement} to check
+ */
+ boolean isHudElementHidden(@NonNull GuiElement element);
+
+ /**
+ * Returns the currently hidden {@link GuiElement}s.
+ *
+ * @return an unmodifiable view of all currently hidden {@link GuiElement}s
+ */
+ @NonNull Set hiddenElements();
+
+ /**
+ * Sends a notification toast to the client.
+ */
+ void sendToast(@NonNull String title, @NonNull String content);
+}
diff --git a/api/src/main/java/org/geysermc/geyser/api/bedrock/gui/GuiElement.java b/api/src/main/java/org/geysermc/geyser/api/bedrock/gui/GuiElement.java
new file mode 100644
index 000000000..c90c917ba
--- /dev/null
+++ b/api/src/main/java/org/geysermc/geyser/api/bedrock/gui/GuiElement.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.api.bedrock.gui;
+
+/**
+ * Represent GUI elements on the players HUD display.
+ * These can be hidden using {@link GuiData#hideElement(GuiElement...)},
+ * and one can reset their visibility using {@link GuiData#resetElement(GuiElement...)}.
+ */
+public class GuiElement {
+ public static final GuiElement PAPER_DOLL = new GuiElement(0);
+ public static final GuiElement ARMOR = new GuiElement(1);
+ public static final GuiElement TOOL_TIPS = new GuiElement(2);
+ public static final GuiElement TOUCH_CONTROLS = new GuiElement(3);
+ public static final GuiElement CROSSHAIR = new GuiElement(4);
+ public static final GuiElement HOTBAR = new GuiElement(5);
+ public static final GuiElement HEALTH = new GuiElement(6);
+ public static final GuiElement PROGRESS_BAR = new GuiElement(7);
+ public static final GuiElement FOOD_BAR = new GuiElement(8);
+ public static final GuiElement AIR_BUBBLES_BAR = new GuiElement(9);
+ public static final GuiElement VEHICLE_HEALTH = new GuiElement(10);
+ public static final GuiElement EFFECTS_BAR = new GuiElement(11);
+ public static final GuiElement ITEM_TEXT_POPUP = new GuiElement(12);
+
+ public GuiElement(int id) {
+ this.id = id;
+ }
+
+ private final int id;
+
+ /**
+ * Internal use only; don't depend on these values being consistent.
+ */
+ public int id() {
+ return this.id;
+ }
+}
diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/BlockPlaceMixin.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/BlockPlaceMixin.java
new file mode 100644
index 000000000..98620588e
--- /dev/null
+++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/BlockPlaceMixin.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.platform.mod.mixin.server;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.InteractionResult;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.BlockItem;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.item.context.BlockPlaceContext;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.SoundType;
+import net.minecraft.world.level.block.state.BlockState;
+import org.cloudburstmc.math.vector.Vector3f;
+import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
+import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket;
+import org.geysermc.geyser.GeyserImpl;
+import org.geysermc.geyser.session.GeyserSession;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
+
+@Mixin(BlockItem.class)
+public class BlockPlaceMixin {
+
+ @Inject(method = "place", locals = LocalCapture.CAPTURE_FAILSOFT, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;playSound(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/core/BlockPos;Lnet/minecraft/sounds/SoundEvent;Lnet/minecraft/sounds/SoundSource;FF)V"))
+ private void geyser$hijackPlaySound(BlockPlaceContext blockPlaceContext, CallbackInfoReturnable cir, BlockPlaceContext blockPlaceContext2, BlockState blockState, BlockPos blockPos, Level level, Player player, ItemStack itemStack, BlockState blockState2, SoundType soundType) {
+ if (player == null) {
+ return;
+ }
+
+ GeyserSession session = GeyserImpl.getInstance().connectionByUuid(player.getUUID());
+ if (session == null) {
+ return;
+ }
+
+ Vector3f position = Vector3f.from(
+ blockPos.getX(),
+ blockPos.getY(),
+ blockPos.getZ()
+ );
+
+ LevelSoundEventPacket placeBlockSoundPacket = new LevelSoundEventPacket();
+ placeBlockSoundPacket.setSound(SoundEvent.PLACE);
+ placeBlockSoundPacket.setPosition(position);
+ placeBlockSoundPacket.setBabySound(false);
+ placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(Block.BLOCK_STATE_REGISTRY.getId(blockState2)));
+ placeBlockSoundPacket.setIdentifier(":");
+ session.sendUpstreamPacket(placeBlockSoundPacket);
+ session.setLastBlockPlacePosition(null);
+ session.setLastBlockPlaced(null);
+ }
+}
diff --git a/core/src/main/java/org/geysermc/geyser/impl/gui/GeyserGuiData.java b/core/src/main/java/org/geysermc/geyser/impl/gui/GeyserGuiData.java
new file mode 100644
index 000000000..42b2c44b0
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/impl/gui/GeyserGuiData.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.impl.gui;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.cloudburstmc.protocol.bedrock.data.HudElement;
+import org.cloudburstmc.protocol.bedrock.data.HudVisibility;
+import org.cloudburstmc.protocol.bedrock.packet.SetHudPacket;
+import org.cloudburstmc.protocol.bedrock.packet.ToastRequestPacket;
+import org.geysermc.geyser.api.bedrock.gui.GuiData;
+import org.geysermc.geyser.api.bedrock.gui.GuiElement;
+import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+public class GeyserGuiData implements GuiData {
+ private static final HudElement[] HUD_ELEMENT_VALUES = HudElement.values();
+ private static final Set ALL_HUD_ELEMENTS = Set.of(HUD_ELEMENT_VALUES);
+
+ /**
+ * An array of elements to hide when the player is in spectator mode.
+ * Helps with tidying up the GUI; Java-style.
+ */
+ private static final GuiElement[] SPECTATOR_HIDDEN_ELEMENTS = {
+ GuiElement.AIR_BUBBLES_BAR,
+ GuiElement.ARMOR,
+ GuiElement.HEALTH,
+ GuiElement.FOOD_BAR,
+ GuiElement.PROGRESS_BAR,
+ GuiElement.TOOL_TIPS
+ };
+
+ private final GeyserSession session;
+
+ public GeyserGuiData(GeyserSession session) {
+ this.session = session;
+ }
+
+ /**
+ * All currently hidden HUD elements
+ */
+ private final Set hiddenHudElements = new HashSet<>();
+
+ @Override
+ public void hideElement(@NotNull @NonNull GuiElement... element) {
+
+ }
+
+ @Override
+ public void resetElement(GuiElement... elements) {
+ SetHudPacket packet = new SetHudPacket();
+ packet.setVisibility(HudVisibility.RESET);
+ Set elementSet = packet.getElements();
+
+ if (elements != null && elements.length != 0) {
+ for (GuiElement element : elements) {
+ this.hiddenHudElements.remove(element);
+ elementSet.add(HUD_ELEMENT_VALUES[element.id()]);
+ }
+ } else {
+ this.hiddenHudElements.clear();
+ elementSet.addAll(ALL_HUD_ELEMENTS);
+ }
+
+ session.sendUpstreamPacket(packet);
+ }
+
+ @Override
+ public boolean isHudElementHidden(@NonNull GuiElement element) {
+ Objects.requireNonNull(element);
+ return this.hiddenHudElements.contains(element);
+ }
+
+ @Override
+ public @NonNull Set hiddenElements() {
+ return Collections.unmodifiableSet(hiddenHudElements);
+ }
+
+ @Override
+ public void sendToast(@NonNull String title, @NonNull String content) {
+ ToastRequestPacket toastRequestPacket = new ToastRequestPacket();
+ toastRequestPacket.setTitle(title);
+ toastRequestPacket.setContent(content);
+ session.sendUpstreamPacket(toastRequestPacket);
+ }
+
+ /**
+ * Deals with hiding hud elements while in spectator.
+ *
+ * @param currentlySpectator whether the player is currently in spectator mode
+ * @param newGameMode the new GameMode to switch to
+ */
+ public void handleGameModeChange(boolean currentlySpectator, GameMode newGameMode) {
+ if (newGameMode == GameMode.SPECTATOR) {
+ if (!currentlySpectator) {
+ hideElement(SPECTATOR_HIDDEN_ELEMENTS);
+ }
+ } else {
+ if (currentlySpectator) {
+ resetElement(SPECTATOR_HIDDEN_ELEMENTS);
+ }
+ }
+ }
+}
diff --git a/core/src/main/java/org/geysermc/geyser/item/components/Rarity.java b/core/src/main/java/org/geysermc/geyser/item/components/Rarity.java
new file mode 100644
index 000000000..6fa74ea35
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/item/components/Rarity.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.item.components;
+
+import lombok.Getter;
+
+@Getter
+public enum Rarity {
+ COMMON("common", 'f'),
+ UNCOMMON("uncommon", 'e'),
+ RARE("rare", 'b'),
+ EPIC("epic", 'd');
+
+ private final String name;
+ private final char color;
+
+ Rarity(final String name, char chatColor) {
+ this.name = name;
+ this.color = chatColor;
+ }
+
+ private static final Rarity[] VALUES = values();
+
+ public static Rarity fromId(int id) {
+ return VALUES.length > id ? VALUES[id] : VALUES[0];
+ }
+
+}
diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BedrockRequiresTagItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BedrockRequiresTagItem.java
new file mode 100644
index 000000000..c41d14396
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/item/type/BedrockRequiresTagItem.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.item.type;
+
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.translator.item.BedrockItemBuilder;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
+
+public interface BedrockRequiresTagItem {
+
+ void addRequiredNbt(GeyserSession session, @Nullable DataComponents components, BedrockItemBuilder builder);
+}
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationPacketTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationPacketTranslator.java
new file mode 100644
index 000000000..8ade4a1f0
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationPacketTranslator.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.translator.protocol.java;
+
+import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket;
+import org.geysermc.geyser.entity.type.player.PlayerEntity;
+import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.translator.protocol.PacketTranslator;
+import org.geysermc.geyser.translator.protocol.Translator;
+import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundFinishConfigurationPacket;
+
+@Translator(packet = ClientboundFinishConfigurationPacket.class)
+public class JavaFinishConfigurationPacketTranslator extends PacketTranslator {
+
+ @Override
+ public void translate(GeyserSession session, ClientboundFinishConfigurationPacket packet) {
+ // Clear the player list, as on Java the player list is cleared after transitioning from config to play phase
+ PlayerListPacket playerListPacket = new PlayerListPacket();
+ playerListPacket.setAction(PlayerListPacket.Action.REMOVE);
+ for (PlayerEntity otherEntity : session.getEntityCache().getAllPlayerEntities()) {
+ playerListPacket.getEntries().add(new PlayerListPacket.Entry(otherEntity.getTabListUuid()));
+ }
+ session.sendUpstreamPacket(playerListPacket);
+ session.getEntityCache().removeAllPlayerEntities();
+ }
+}