From 6a6a601efc3a73281210842e7f9a39fc8ef21db2 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Wed, 15 Feb 2023 00:01:33 -0500
Subject: [PATCH 01/59] Notify on disconnect when a new Geyser update is
 available

---
 .../geyser/network/UpstreamPacketHandler.java        | 12 +++++++++++-
 .../org/geysermc/geyser/util/VersionCheckUtils.java  |  9 +++++++++
 core/src/main/resources/languages                    |  2 +-
 3 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java
index 227f0ed5a..a72d8ab9e 100644
--- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java
+++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java
@@ -31,6 +31,7 @@ import com.nukkitx.protocol.bedrock.data.ExperimentData;
 import com.nukkitx.protocol.bedrock.data.PacketCompressionAlgorithm;
 import com.nukkitx.protocol.bedrock.data.ResourcePackType;
 import com.nukkitx.protocol.bedrock.packet.*;
+import org.geysermc.geyser.Constants;
 import org.geysermc.geyser.GeyserImpl;
 import org.geysermc.geyser.api.network.AuthType;
 import org.geysermc.geyser.configuration.GeyserConfiguration;
@@ -43,11 +44,13 @@ import org.geysermc.geyser.session.PendingMicrosoftAuthentication;
 import org.geysermc.geyser.text.GeyserLocale;
 import org.geysermc.geyser.util.LoginEncryptionUtils;
 import org.geysermc.geyser.util.MathUtils;
+import org.geysermc.geyser.util.VersionCheckUtils;
 
 import java.io.FileInputStream;
 import java.io.InputStream;
 import java.util.ArrayDeque;
 import java.util.Deque;
+import java.util.OptionalInt;
 
 public class UpstreamPacketHandler extends LoggingPacketHandler {
 
@@ -74,7 +77,14 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
             String supportedVersions = GameProtocol.getAllSupportedBedrockVersions();
             if (protocolVersion > GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) {
                 // Too early to determine session locale
-                session.disconnect(GeyserLocale.getLocaleStringLog("geyser.network.outdated.server", supportedVersions));
+                String disconnectMessage = GeyserLocale.getLocaleStringLog("geyser.network.outdated.server", supportedVersions);
+                // If the latest release matches this version, then let the user know.
+                OptionalInt latestRelease = VersionCheckUtils.getLatestBedrockRelease();
+                if (latestRelease.isPresent() && latestRelease.getAsInt() == protocolVersion) {
+                    // Random note: don't make the disconnect message too long or Bedrock will cut it off on smaller screens
+                    disconnectMessage += "\n" + GeyserLocale.getLocaleStringLog("geyser.version.new.on_disconnect", Constants.GEYSER_DOWNLOAD_LOCATION);
+                }
+                session.disconnect(disconnectMessage);
                 return false;
             } else if (protocolVersion < GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) {
                 session.disconnect(GeyserLocale.getLocaleStringLog("geyser.network.outdated.client", supportedVersions));
diff --git a/core/src/main/java/org/geysermc/geyser/util/VersionCheckUtils.java b/core/src/main/java/org/geysermc/geyser/util/VersionCheckUtils.java
index 049d78619..dc0edd37a 100644
--- a/core/src/main/java/org/geysermc/geyser/util/VersionCheckUtils.java
+++ b/core/src/main/java/org/geysermc/geyser/util/VersionCheckUtils.java
@@ -38,10 +38,13 @@ import org.geysermc.geyser.command.GeyserCommandSource;
 import org.geysermc.geyser.network.GameProtocol;
 import org.geysermc.geyser.text.GeyserLocale;
 
+import javax.annotation.Nonnull;
+import java.util.OptionalInt;
 import java.util.concurrent.CompletableFuture;
 import java.util.function.Supplier;
 
 public final class VersionCheckUtils {
+    private static @Nonnull OptionalInt LATEST_BEDROCK_RELEASE = OptionalInt.empty();
 
     public static void checkForOutdatedFloodgate(GeyserLogger logger) {
         try {
@@ -61,10 +64,12 @@ public final class VersionCheckUtils {
                 JsonNode bedrock = json.get("bedrock").get("protocol");
                 int protocolVersion = bedrock.get("id").asInt();
                 if (GameProtocol.getBedrockCodec(protocolVersion) != null) {
+                    LATEST_BEDROCK_RELEASE = OptionalInt.empty();
                     // We support the latest version! No need to print a message.
                     return;
                 }
 
+                LATEST_BEDROCK_RELEASE = OptionalInt.of(protocolVersion);
                 final String newBedrockVersion = bedrock.get("name").asText();
 
                 // Delayed for two reasons: save unnecessary processing, and wait to load locale if this is on join.
@@ -89,6 +94,10 @@ public final class VersionCheckUtils {
         });
     }
 
+    public static @Nonnull OptionalInt getLatestBedrockRelease() {
+        return LATEST_BEDROCK_RELEASE;
+    }
+
     private VersionCheckUtils() {
     }
 }
diff --git a/core/src/main/resources/languages b/core/src/main/resources/languages
index f6685c4cc..24be9ef7f 160000
--- a/core/src/main/resources/languages
+++ b/core/src/main/resources/languages
@@ -1 +1 @@
-Subproject commit f6685c4ccc6e77b07402d45cb41213559004b7d6
+Subproject commit 24be9ef7f850f7d180650a65792c266c709cadf5

From ee754c529ba1072d07cb684336204b5251661ff1 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Wed, 15 Feb 2023 00:17:14 -0500
Subject: [PATCH 02/59] Add implementation for ClientEmoteEvent

Also, a few random changes I've stored since forever.
---
 ...rockEmoteEvent.java => ClientEmoteEvent.java} |  4 ++--
 .../geyser/command/defaults/OffhandCommand.java  |  8 +-------
 .../geyser/item/components/ToolTier.java         |  2 +-
 .../geyser/level/GeyserWorldManager.java         |  8 +-------
 .../geyser/level/physics/PistonBehavior.java     |  2 +-
 .../geyser/registry/type/ParticleMapping.java    |  3 ++-
 .../geysermc/geyser/session/GeyserSession.java   |  8 +++++++-
 .../geyser/session/cache/LodestoneCache.java     |  3 +--
 .../inventory/EnchantingInventoryTranslator.java |  3 ++-
 .../entity/player/BedrockEmoteTranslator.java    | 16 +++++++++-------
 10 files changed, 27 insertions(+), 30 deletions(-)
 rename api/src/main/java/org/geysermc/geyser/api/event/bedrock/{BedrockEmoteEvent.java => ClientEmoteEvent.java} (92%)

diff --git a/api/src/main/java/org/geysermc/geyser/api/event/bedrock/BedrockEmoteEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/ClientEmoteEvent.java
similarity index 92%
rename from api/src/main/java/org/geysermc/geyser/api/event/bedrock/BedrockEmoteEvent.java
rename to api/src/main/java/org/geysermc/geyser/api/event/bedrock/ClientEmoteEvent.java
index efe3f12d6..35b6a9e73 100644
--- a/api/src/main/java/org/geysermc/geyser/api/event/bedrock/BedrockEmoteEvent.java
+++ b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/ClientEmoteEvent.java
@@ -33,11 +33,11 @@ import org.geysermc.geyser.api.event.connection.ConnectionEvent;
 /**
  * Called whenever a Bedrock player performs an emote on their end, before it is broadcasted to the rest of the server.
  */
-public final class BedrockEmoteEvent extends ConnectionEvent implements Cancellable {
+public final class ClientEmoteEvent extends ConnectionEvent implements Cancellable {
     private final String emoteId;
     private boolean cancelled;
 
-    public BedrockEmoteEvent(@NonNull GeyserConnection connection, @NonNull String emoteId) {
+    public ClientEmoteEvent(@NonNull GeyserConnection connection, @NonNull String emoteId) {
         super(connection);
         this.emoteId = emoteId;
     }
diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/OffhandCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/OffhandCommand.java
index 0015149be..6188e6924 100644
--- a/core/src/main/java/org/geysermc/geyser/command/defaults/OffhandCommand.java
+++ b/core/src/main/java/org/geysermc/geyser/command/defaults/OffhandCommand.java
@@ -25,10 +25,6 @@
 
 package org.geysermc.geyser.command.defaults;
 
-import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
-import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
-import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
-import com.nukkitx.math.vector.Vector3i;
 import org.geysermc.geyser.GeyserImpl;
 import org.geysermc.geyser.command.GeyserCommand;
 import org.geysermc.geyser.command.GeyserCommandSource;
@@ -46,9 +42,7 @@ public class OffhandCommand extends GeyserCommand {
             return;
         }
 
-        ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO,
-                Direction.DOWN, 0);
-        session.sendDownstreamPacket(releaseItemPacket);
+        session.requestOffhandSwap();
     }
 
     @Override
diff --git a/core/src/main/java/org/geysermc/geyser/item/components/ToolTier.java b/core/src/main/java/org/geysermc/geyser/item/components/ToolTier.java
index 37e581682..724b197fb 100644
--- a/core/src/main/java/org/geysermc/geyser/item/components/ToolTier.java
+++ b/core/src/main/java/org/geysermc/geyser/item/components/ToolTier.java
@@ -37,7 +37,7 @@ public enum ToolTier {
     DIAMOND(8),
     NETHERITE(9);
 
-    public static final ToolTier[] VALUES = values();
+    private static final ToolTier[] VALUES = values();
 
     private final int speed;
 
diff --git a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java
index f19060c65..5df97e8d7 100644
--- a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java
+++ b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java
@@ -29,9 +29,7 @@ import com.nukkitx.nbt.NbtMap;
 import com.nukkitx.nbt.NbtMapBuilder;
 import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
 import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
-import org.geysermc.geyser.level.block.BlockStateValues;
 import org.geysermc.geyser.session.GeyserSession;
-import org.geysermc.geyser.session.cache.ChunkCache;
 import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator;
 
 public class GeyserWorldManager extends WorldManager {
@@ -39,11 +37,7 @@ public class GeyserWorldManager extends WorldManager {
 
     @Override
     public int getBlockAt(GeyserSession session, int x, int y, int z) {
-        ChunkCache chunkCache = session.getChunkCache();
-        if (chunkCache != null) { // Chunk cache can be null if the session is closed asynchronously
-            return chunkCache.getBlockAt(x, y, z);
-        }
-        return BlockStateValues.JAVA_AIR_ID;
+        return session.getChunkCache().getBlockAt(x, y, z);
     }
 
     @Override
diff --git a/core/src/main/java/org/geysermc/geyser/level/physics/PistonBehavior.java b/core/src/main/java/org/geysermc/geyser/level/physics/PistonBehavior.java
index bf943134b..a6b25d01e 100644
--- a/core/src/main/java/org/geysermc/geyser/level/physics/PistonBehavior.java
+++ b/core/src/main/java/org/geysermc/geyser/level/physics/PistonBehavior.java
@@ -33,7 +33,7 @@ public enum PistonBehavior {
     DESTROY,
     PUSH_ONLY;
 
-    public static final PistonBehavior[] VALUES = values();
+    private static final PistonBehavior[] VALUES = values();
 
     public static PistonBehavior getByName(String name) {
         String upperCase = name.toUpperCase(Locale.ROOT);
diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/ParticleMapping.java b/core/src/main/java/org/geysermc/geyser/registry/type/ParticleMapping.java
index 71feee3de..dcafcd0bf 100644
--- a/core/src/main/java/org/geysermc/geyser/registry/type/ParticleMapping.java
+++ b/core/src/main/java/org/geysermc/geyser/registry/type/ParticleMapping.java
@@ -28,12 +28,13 @@ package org.geysermc.geyser.registry.type;
 import com.nukkitx.protocol.bedrock.data.LevelEventType;
 import org.geysermc.geyser.session.GeyserSession;
 
+import javax.annotation.Nonnull;
 import javax.annotation.ParametersAreNullableByDefault;
 
 @ParametersAreNullableByDefault
 public record ParticleMapping(LevelEventType levelEventType, String identifier) {
 
-    public int getParticleId(GeyserSession session) {
+    public int getParticleId(@Nonnull GeyserSession session) {
         if (this.levelEventType == null) {
             return -1;
         }
diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
index 33655beda..bc49e8945 100644
--- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
+++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
@@ -180,7 +180,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
 
     private final AdvancementsCache advancementsCache;
     private final BookEditCache bookEditCache;
-    private final ChunkCache chunkCache;
+    private @org.checkerframework.checker.nullness.qual.NonNull final ChunkCache chunkCache;
     private final EntityCache entityCache;
     private final EntityEffectCache effectCache;
     private final FormCache formCache;
@@ -1354,6 +1354,12 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
         return false;
     }
 
+    public void requestOffhandSwap() {
+        ServerboundPlayerActionPacket swapHandsPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO,
+                Direction.DOWN, 0);
+        sendDownstreamPacket(swapHandsPacket);
+    }
+
     /**
      * Will be overwritten for GeyserConnect.
      */
diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java
index 05c2628df..41f73863e 100644
--- a/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java
+++ b/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java
@@ -73,8 +73,7 @@ public final class LodestoneCache {
             }
         }
 
-        for (Int2ObjectMap.Entry<LodestonePos> entry : this.lodestones.int2ObjectEntrySet()) {
-            LodestonePos pos = entry.getValue();
+        for (LodestonePos pos : this.lodestones.values()) {
             if (pos.equals(x, y, z, dim)) {
                 // Use this existing position instead
                 this.activeLodestones.put(itemStack, pos);
diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java
index 97946b59c..8ae88c9bb 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java
@@ -43,6 +43,7 @@ import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
 import org.geysermc.geyser.session.GeyserSession;
 
 import java.util.Arrays;
+import java.util.Locale;
 
 public class EnchantingInventoryTranslator extends AbstractBlockInventoryTranslator {
     public EnchantingInventoryTranslator() {
@@ -71,7 +72,7 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla
                 // The Bedrock index might need changed, so let's look it up and see.
                 int bedrockIndex = value;
                 if (bedrockIndex != -1) {
-                    Enchantment enchantment = Enchantment.getByJavaIdentifier("minecraft:" + Enchantment.JavaEnchantment.of(bedrockIndex).name().toLowerCase());
+                    Enchantment enchantment = Enchantment.getByJavaIdentifier("minecraft:" + Enchantment.JavaEnchantment.of(bedrockIndex).name().toLowerCase(Locale.ROOT));
                     if (enchantment != null) {
                         // Convert the Java enchantment index to Bedrock's
                         bedrockIndex = enchantment.ordinal();
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockEmoteTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockEmoteTranslator.java
index 43d2d314c..6be0be20f 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockEmoteTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockEmoteTranslator.java
@@ -25,11 +25,8 @@
 
 package org.geysermc.geyser.translator.protocol.bedrock.entity.player;
 
-import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
-import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
-import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
-import com.nukkitx.math.vector.Vector3i;
 import com.nukkitx.protocol.bedrock.packet.EmotePacket;
+import org.geysermc.geyser.api.event.bedrock.ClientEmoteEvent;
 import org.geysermc.geyser.configuration.EmoteOffhandWorkaroundOption;
 import org.geysermc.geyser.entity.type.Entity;
 import org.geysermc.geyser.session.GeyserSession;
@@ -43,15 +40,20 @@ public class BedrockEmoteTranslator extends PacketTranslator<EmotePacket> {
     public void translate(GeyserSession session, EmotePacket packet) {
         if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() != EmoteOffhandWorkaroundOption.DISABLED) {
             // Activate the workaround - we should trigger the offhand now
-            ServerboundPlayerActionPacket swapHandsPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO,
-                    Direction.DOWN, 0);
-            session.sendDownstreamPacket(swapHandsPacket);
+            session.requestOffhandSwap();
 
             if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() == EmoteOffhandWorkaroundOption.NO_EMOTES) {
                 return;
             }
         }
 
+        // For the future: could have a method that exposes which players will see the emote
+        ClientEmoteEvent event = new ClientEmoteEvent(session, packet.getEmoteId());
+        session.getGeyser().eventBus().fire(event);
+        if (event.isCancelled()) {
+            return;
+        }
+
         int javaId = session.getPlayerEntity().getEntityId();
         for (GeyserSession otherSession : session.getGeyser().getSessionManager().getSessions().values()) {
             if (otherSession != session) {

From 30277d54114de100175b20b4257a55314409723b Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Wed, 15 Feb 2023 16:17:38 -0500
Subject: [PATCH 03/59] Anticipate support for the patch version of 1.19.60

---
 .../java/org/geysermc/geyser/network/GameProtocol.java     | 4 ++++
 .../org/geysermc/geyser/network/UpstreamPacketHandler.java | 7 +++++++
 gradle/libs.versions.toml                                  | 2 +-
 3 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
index 804187075..099a2305a 100644
--- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
+++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
@@ -75,6 +75,10 @@ public final class GameProtocol {
                 .minecraftVersion("1.19.50/1.19.51")
                 .build());
         SUPPORTED_BEDROCK_CODECS.add(Bedrock_v567.V567_CODEC);
+        // So the version checker will work
+        SUPPORTED_BEDROCK_CODECS.add(Bedrock_v567.V567_CODEC.toBuilder()
+                .protocolVersion(568)
+                .build());
     }
 
     /**
diff --git a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java
index a72d8ab9e..26c463bb0 100644
--- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java
+++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java
@@ -31,6 +31,8 @@ import com.nukkitx.protocol.bedrock.data.ExperimentData;
 import com.nukkitx.protocol.bedrock.data.PacketCompressionAlgorithm;
 import com.nukkitx.protocol.bedrock.data.ResourcePackType;
 import com.nukkitx.protocol.bedrock.packet.*;
+import com.nukkitx.protocol.bedrock.v567.Bedrock_v567;
+import com.nukkitx.protocol.bedrock.v567.Bedrock_v567patch;
 import org.geysermc.geyser.Constants;
 import org.geysermc.geyser.GeyserImpl;
 import org.geysermc.geyser.api.network.AuthType;
@@ -141,6 +143,11 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
             return true;
         }
 
+        // Hack for... whatever this is
+        if (loginPacket.getProtocolVersion() == Bedrock_v567.V567_CODEC.getProtocolVersion() && !session.getClientData().getGameVersion().equals("1.19.60")) {
+            session.getUpstream().getSession().setPacketCodec(Bedrock_v567patch.BEDROCK_V567PATCH);
+        }
+
         PlayStatusPacket playStatus = new PlayStatusPacket();
         playStatus.setStatus(PlayStatusPacket.Status.LOGIN_SUCCESS);
         session.sendUpstreamPacket(playStatus);
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 14ca47155..986fae748 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -8,7 +8,7 @@ netty = "4.1.80.Final"
 guava = "29.0-jre"
 gson = "2.3.1" # Provided by Spigot 1.8.8
 websocket = "1.5.1"
-protocol = "2.9.16-20230205.181702-1"
+protocol = "2.9.16-20230215.204900-2"
 raknet = "1.6.28-20220125.214016-6"
 mcauthlib = "d9d773e"
 mcprotocollib = "1.19.3-20230107.194116-10"

From 406dfcb22caf51f1cec3559e11599362e856192e Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Thu, 16 Feb 2023 20:01:51 -0500
Subject: [PATCH 04/59] Fix error on 1.19.62

---
 .../java/org/geysermc/geyser/network/GameProtocol.java     | 7 ++++---
 gradle/libs.versions.toml                                  | 2 +-
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
index 099a2305a..c76fd7b61 100644
--- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
+++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
@@ -48,7 +48,7 @@ public final class GameProtocol {
      * Default Bedrock codec that should act as a fallback. Should represent the latest available
      * release of the game that Geyser supports.
      */
-    public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v560.V560_CODEC;
+    public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v567.V567_CODEC;
     /**
      * A list of all supported Bedrock versions that can join Geyser
      */
@@ -71,13 +71,14 @@ public final class GameProtocol {
         SUPPORTED_BEDROCK_CODECS.add(Bedrock_v557.V557_CODEC.toBuilder()
                 .minecraftVersion("1.19.40/1.19.41")
                 .build());
-        SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder()
+        SUPPORTED_BEDROCK_CODECS.add(Bedrock_v560.V560_CODEC.toBuilder()
                 .minecraftVersion("1.19.50/1.19.51")
                 .build());
-        SUPPORTED_BEDROCK_CODECS.add(Bedrock_v567.V567_CODEC);
+        SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC);
         // So the version checker will work
         SUPPORTED_BEDROCK_CODECS.add(Bedrock_v567.V567_CODEC.toBuilder()
                 .protocolVersion(568)
+                .minecraftVersion("1.19.62")
                 .build());
     }
 
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 986fae748..f62faa54f 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -8,7 +8,7 @@ netty = "4.1.80.Final"
 guava = "29.0-jre"
 gson = "2.3.1" # Provided by Spigot 1.8.8
 websocket = "1.5.1"
-protocol = "2.9.16-20230215.204900-2"
+protocol = "2.9.17-20230217.002312-1"
 raknet = "1.6.28-20220125.214016-6"
 mcauthlib = "d9d773e"
 mcprotocollib = "1.19.3-20230107.194116-10"

From cfd7aeb927d0816a0d7943f370334ec6a876f16c Mon Sep 17 00:00:00 2001
From: Kas-tle <26531652+Kas-tle@users.noreply.github.com>
Date: Fri, 17 Feb 2023 11:37:01 -0800
Subject: [PATCH 05/59] Update PR Build Action for API (#3535)

* Use API from use making PR if exists

* Update CONTRIBUTING.md

* Address @Tim203's review

* Fix path

* Build the api before doing anything with the Geyser repo

---------

Co-authored-by: Tim203 <mctim203@gmail.com>
---
 .github/workflows/pullrequest.yml | 41 ++++++++++++++++++++++++-------
 CONTRIBUTING.md                   |  4 ++-
 2 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml
index 39e9fe188..6781d7483 100644
--- a/.github/workflows/pullrequest.yml
+++ b/.github/workflows/pullrequest.yml
@@ -4,21 +4,44 @@ on: [pull_request]
 
 jobs:
   build:
-
     runs-on: ubuntu-latest
-
     steps:
-      - uses: actions/checkout@v2
       - name: Set up JDK 17
         uses: actions/setup-java@v1
         with:
-          distribution: 'temurin'
           java-version: 17
-          cache: 'gradle'
-      - name: submodules-init
-        uses: snickerbockers/submodules-init@v4
-      - name: Build with Gradle
-        run: ./gradlew build
+          distribution: temurin
+          cache: gradle
+
+      - name: Check if the author has forked the API repo
+        uses: Kas-tle/ForkFinder@v1.0.1
+        id: find_forks
+        with:
+          owner: GeyserMC
+          repo: api
+          token: ${{ secrets.GITHUB_TOKEN }}
+
+      - name: Use author's API repo if it exists
+        if: steps.find_forks.outputs.target_branch_found == 'true'
+        env:
+          API_FORK_URL: ${{ steps.find_forks.outputs.user_fork_url }}
+          API_FORK_BRANCH: ${{ github.event.pull_request.head.ref }}
+        run: |
+          git clone "${API_FORK_URL}" --single-branch --branch "${API_FORK_BRANCH}" api
+          cd api
+          ./gradlew publishToMavenLocal
+
+      - name: Checkout repository and submodules
+        uses: actions/checkout@v3
+        with:
+          submodules: recursive
+          path: geyser
+
+      - name: Build Geyser
+        uses: gradle/gradle-build-action@v2
+        with:
+          arguments: build
+          build-root-directory: geyser
 
       - name: Archive artifacts (Geyser Fabric)
         uses: actions/upload-artifact@v2
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ce6894845..dac8a9a07 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -48,4 +48,6 @@ Make sure to comment your code where possible.
 
 The nature of our software requires a lot of arrays and maps to be stored - where possible, use Fastutil's specialized maps. For example, if you're storing block state translations, use an `Int2IntMap`.
 
-We have a rundown of all the tools you need to develop over on our [wiki](https://github.com/GeyserMC/Geyser/wiki/Developer-Guide). If you have any questions, please feel free to reach out to our [Discord](https://discord.gg/geysermc)!
+We have a rundown of all the tools you need to develop over on our [wiki](https://wiki.geysermc.org/other/developer-guide/). If you have any questions, please feel free to reach out to our [Discord](https://discord.gg/geysermc)!
+
+If you're making a pull request that also depends on changes to [the base API](https://github.com/GeyserMC/api), simply fork the API repo and create a branch with the same name as your Geyser PR. The pull request [action](https://github.com/GeyserMC/Geyser/blob/master/.github/workflows/pullrequest.yml) will automatically use your API changes while building your changes to Geyser.
\ No newline at end of file

From e7b8b4ef29beec7d3696a3bd759df298286083ee Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Fri, 17 Feb 2023 18:55:40 -0500
Subject: [PATCH 06/59] Update supported versions in README

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index b36235e36..6996086b9 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t
 
 Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here!
 
-### Currently supporting Minecraft Bedrock 1.19.20 - 1.19.60 and Minecraft Java 1.19.3.
+### Currently supporting Minecraft Bedrock 1.19.20 - 1.19.62 and Minecraft Java 1.19.3.
 
 ## Setting Up
 Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser.

From e42c2d8ed52751d454d17727ccd6faa19f7f6864 Mon Sep 17 00:00:00 2001
From: Jackson_57 <49173011+jackson-57@users.noreply.github.com>
Date: Wed, 22 Feb 2023 06:11:06 -0800
Subject: [PATCH 07/59] Fix artifact paths (#3570)

---
 .github/workflows/pullrequest.yml | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml
index 6781d7483..8d5f5c03c 100644
--- a/.github/workflows/pullrequest.yml
+++ b/.github/workflows/pullrequest.yml
@@ -48,34 +48,34 @@ jobs:
         if: success()
         with:
           name: Geyser Fabric
-          path: bootstrap/fabric/build/libs/Geyser-Fabric.jar
+          path: geyser/bootstrap/fabric/build/libs/Geyser-Fabric.jar
       - name: Archive artifacts (Geyser Standalone)
         uses: actions/upload-artifact@v2
         if: success()
         with:
           name: Geyser Standalone
-          path: bootstrap/standalone/build/libs/Geyser-Standalone.jar
+          path: geyser/bootstrap/standalone/build/libs/Geyser-Standalone.jar
       - name: Archive artifacts (Geyser Spigot)
         uses: actions/upload-artifact@v2
         if: success()
         with:
           name: Geyser Spigot
-          path: bootstrap/spigot/build/libs/Geyser-Spigot.jar
+          path: geyser/bootstrap/spigot/build/libs/Geyser-Spigot.jar
       - name: Archive artifacts (Geyser BungeeCord)
         uses: actions/upload-artifact@v2
         if: success()
         with:
           name: Geyser BungeeCord
-          path: bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
+          path: geyser/bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
       - name: Archive artifacts (Geyser Sponge)
         uses: actions/upload-artifact@v2
         if: success()
         with:
           name: Geyser Sponge
-          path: bootstrap/sponge/build/libs/Geyser-Sponge.jar
+          path: geyser/bootstrap/sponge/build/libs/Geyser-Sponge.jar
       - name: Archive artifacts (Geyser Velocity)
         uses: actions/upload-artifact@v2
         if: success()
         with:
           name: Geyser Velocity
-          path: bootstrap/velocity/build/libs/Geyser-Velocity.jar
+          path: geyser/bootstrap/velocity/build/libs/Geyser-Velocity.jar

From e50226132febee19831e95c06b1ab99538ecb625 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Thu, 23 Feb 2023 13:11:18 -0500
Subject: [PATCH 08/59] Fix more issues of chunks not appearing

---
 .../java/org/geysermc/geyser/session/GeyserSession.java   | 8 +++-----
 .../main/java/org/geysermc/geyser/util/ChunkUtils.java    | 5 ++++-
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
index bc49e8945..11467253e 100644
--- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
+++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
@@ -180,7 +180,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
 
     private final AdvancementsCache advancementsCache;
     private final BookEditCache bookEditCache;
-    private @org.checkerframework.checker.nullness.qual.NonNull final ChunkCache chunkCache;
+    private final ChunkCache chunkCache;
     private final EntityCache entityCache;
     private final EntityEffectCache effectCache;
     private final FormCache formCache;
@@ -1410,10 +1410,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
     }
 
     public void setServerRenderDistance(int renderDistance) {
-        // +1 is for Fabric and Spigot
-        // Without the client misses loading some chunks per https://github.com/GeyserMC/Geyser/issues/3490
-        // Fog still appears essentially normally
-        renderDistance = renderDistance + 1;
         this.serverRenderDistance = renderDistance;
 
         ChunkRadiusUpdatedPacket chunkRadiusUpdatedPacket = new ChunkRadiusUpdatedPacket();
@@ -1425,11 +1421,13 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
         return this.upstream.getAddress();
     }
 
+    @Override
     public boolean sendForm(@NonNull Form form) {
         formCache.showForm(form);
         return true;
     }
 
+    @Override
     public boolean sendForm(@NonNull FormBuilder<?, ?, ?> formBuilder) {
         formCache.showForm(formBuilder.build());
         return true;
diff --git a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java
index 501087f78..aacf4f4d9 100644
--- a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java
+++ b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java
@@ -25,6 +25,7 @@
 
 package org.geysermc.geyser.util;
 
+import com.nukkitx.math.GenericMath;
 import com.nukkitx.math.vector.Vector2i;
 import com.nukkitx.math.vector.Vector3i;
 import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket;
@@ -91,7 +92,9 @@ public class ChunkUtils {
         if (chunkPos == null || !chunkPos.equals(newChunkPos)) {
             NetworkChunkPublisherUpdatePacket chunkPublisherUpdatePacket = new NetworkChunkPublisherUpdatePacket();
             chunkPublisherUpdatePacket.setPosition(position);
-            chunkPublisherUpdatePacket.setRadius(session.getServerRenderDistance() << 4);
+            // Mitigates chunks not loading on 1.17.1 Paper and 1.19.3 Fabric. As of Bedrock 1.19.60.
+            // https://github.com/GeyserMC/Geyser/issues/3490
+            chunkPublisherUpdatePacket.setRadius(GenericMath.ceil((session.getServerRenderDistance() + 1) * MathUtils.SQRT_OF_TWO) << 4);
             session.sendUpstreamPacket(chunkPublisherUpdatePacket);
 
             session.setLastChunkPosition(newChunkPos);

From 65319c58597e73b8b8f0d8162f60fa48fc6aa8a9 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Fri, 24 Feb 2023 12:40:29 -0500
Subject: [PATCH 09/59] Prepare for an actual 568 release

---
 .../main/java/org/geysermc/geyser/network/GameProtocol.java   | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
index c76fd7b61..8a3d068f9 100644
--- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
+++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
@@ -34,6 +34,7 @@ import com.nukkitx.protocol.bedrock.v554.Bedrock_v554;
 import com.nukkitx.protocol.bedrock.v557.Bedrock_v557;
 import com.nukkitx.protocol.bedrock.v560.Bedrock_v560;
 import com.nukkitx.protocol.bedrock.v567.Bedrock_v567;
+import com.nukkitx.protocol.bedrock.v567.Bedrock_v567patch;
 import org.geysermc.geyser.session.GeyserSession;
 
 import java.util.ArrayList;
@@ -75,8 +76,7 @@ public final class GameProtocol {
                 .minecraftVersion("1.19.50/1.19.51")
                 .build());
         SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC);
-        // So the version checker will work
-        SUPPORTED_BEDROCK_CODECS.add(Bedrock_v567.V567_CODEC.toBuilder()
+        SUPPORTED_BEDROCK_CODECS.add(Bedrock_v567patch.BEDROCK_V567PATCH.toBuilder()
                 .protocolVersion(568)
                 .minecraftVersion("1.19.62")
                 .build());

From 50104c95ec52ddf1032ee6db11cf5acca9a5f15f Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Fri, 24 Feb 2023 13:32:46 -0500
Subject: [PATCH 10/59] Remove deploying Jenkinsfile step

---
 Jenkinsfile | 34 ----------------------------------
 1 file changed, 34 deletions(-)

diff --git a/Jenkinsfile b/Jenkinsfile
index 072f99154..a61ba6b3a 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -24,40 +24,6 @@ pipeline {
                 }
             }
         }
-
-        stage ('Deploy') {
-            when {
-                anyOf {
-                    branch "master"
-                }
-            }
-
-            steps {
-                rtGradleDeployer(
-                        id: "GRADLE_DEPLOYER",
-                        serverId: "opencollab-artifactory",
-                        releaseRepo: "maven-releases",
-                        snapshotRepo: "maven-snapshots"
-                )
-                rtGradleResolver(
-                        id: "GRADLE_RESOLVER",
-                        serverId: "opencollab-artifactory"
-                )
-                rtGradleRun(
-                        usesPlugin: true,
-                        tool: 'Gradle 7',
-                        rootDir: "",
-                        useWrapper: true,
-                        buildFile: 'build.gradle.kts',
-                        tasks: 'artifactoryPublish',
-                        deployerId: "GRADLE_DEPLOYER",
-                        resolverId: "GRADLE_RESOLVER"
-                )
-                rtPublishBuildInfo(
-                        serverId: "opencollab-artifactory"
-                )
-            }
-        }
     }
 
     post {

From a72e49527ddb48885b5bdaf57c766de8070d4c4b Mon Sep 17 00:00:00 2001
From: Redned <redned235@gmail.com>
Date: Fri, 24 Feb 2023 20:05:15 -0600
Subject: [PATCH 11/59] Simplify publish logic and move to GitHub Actions
 (#3579)

Co-authored-by: Tim203 <mctim203@gmail.com>
Co-authored-by: rtm516 <ryantmilner@hotmail.co.uk>
---
 .github/workflows/build.yml                   | 53 +++++++++++++++
 Jenkinsfile                                   | 37 ----------
 build-logic/build.gradle.kts                  | 11 +--
 build-logic/src/main/kotlin/extensions.kt     |  3 -
 .../kotlin/geyser.base-conventions.gradle.kts | 25 ++++---
 .../geyser.publish-conventions.gradle.kts     | 32 ++-------
 .../chat/MessageTranslatorTest.java           | 34 +++++-----
 .../inventory/item/CustomItemsTest.java       | 14 ++--
 .../collection/GeyserCollectionsTest.java     | 68 ++++++++++---------
 gradle/libs.versions.toml                     |  4 +-
 10 files changed, 135 insertions(+), 146 deletions(-)
 create mode 100644 .github/workflows/build.yml

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 000000000..160191d46
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,53 @@
+name: Build
+
+on: [push]
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout repository and submodules
+        uses: actions/checkout@v3
+        with:
+          submodules: recursive
+
+      - uses: actions/setup-java@v3
+        with:
+          java-version: 17
+          distribution: temurin
+          cache: gradle
+
+      - name: Build
+        uses: gradle/gradle-build-action@v2
+        with:
+          arguments: build
+
+      - name: Publish to Maven Repository
+        if: ${{ job.status == 'success' && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
+        uses: gradle/gradle-build-action@v2
+        env:
+          ORG_GRADLE_PROJECT_geysermcUsername: ${{ vars.DEPLOY_USER }}
+          ORG_GRADLE_PROJECT_geysermcPassword: ${{ secrets.DEPLOY_PASS }}
+        with:
+          arguments: publish
+
+      - name: Publish to Downloads API
+        if: ${{ github.ref_name == 'master' && job.status == 'success' && github.repository == 'GeyserMC/Geyser' }}
+        shell: bash
+        run: |
+          # Save the private key to a file
+          echo "$DOWNLOADS_PRIVATE_KEY" > id_ecdsa
+          chmod 600 id_ecdsa
+          # Get the version from gradle.properties
+          version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2)
+          # Copy over artifacts
+          scp -B -o StrictHostKeyChecking=no -i id_ecdsa bootstrap/**/build/libs/Geyser-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/files/
+          # Run the build script
+          ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP ./handleBuild.sh geyser $version $GITHUB_RUN_ID $GITHUB_SHA
+
+      - name: Notify Discord
+        if: ${{ github.repository == 'GeyserMC/Geyser' }}
+        uses: Tim203/actions-git-discord-webhook@main
+        with:
+          webhook_url: ${{ secrets.DISCORD_WEBHOOK }}
+          status: ${{ job.status }}
\ No newline at end of file
diff --git a/Jenkinsfile b/Jenkinsfile
index a61ba6b3a..5c2eada3d 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -27,43 +27,6 @@ pipeline {
     }
 
     post {
-        always {
-            script {
-                def changeLogSets = currentBuild.changeSets
-                def message = "**Changes:**"
-
-                if (changeLogSets.size() == 0) {
-                    message += "\n*No changes.*"
-                } else {
-                    def repositoryUrl = scm.userRemoteConfigs[0].url.replace(".git", "")
-                    def count = 0;
-                    def extra = 0;
-                    for (int i = 0; i < changeLogSets.size(); i++) {
-                        def entries = changeLogSets[i].items
-                        for (int j = 0; j < entries.length; j++) {
-                            if (count <= 10) {
-                                def entry = entries[j]
-                                def commitId = entry.commitId.substring(0, 6)
-                                message += "\n   - [`${commitId}`](${repositoryUrl}/commit/${entry.commitId}) ${entry.msg}"
-                                count++
-                            } else {
-                                extra++;
-                            }
-                        }
-                    }
-                    
-                    if (extra != 0) {
-                        message += "\n   - ${extra} more commits"
-                    }
-                }
-
-                env.changes = message
-            }
-            deleteDir()
-            withCredentials([string(credentialsId: 'geyser-discord-webhook', variable: 'DISCORD_WEBHOOK')]) {
-                discordSend description: "**Build:** [${currentBuild.id}](${env.BUILD_URL})\n**Status:** [${currentBuild.currentResult}](${env.BUILD_URL})\n${changes}\n\n[**Artifacts on Jenkins**](https://ci.opencollab.dev/job/GeyserMC/job/Geyser)", footer: 'Open Collaboration Jenkins', link: env.BUILD_URL, successful: currentBuild.resultIsBetterOrEqualTo('SUCCESS'), title: "${env.JOB_NAME} #${currentBuild.id}", webhookURL: DISCORD_WEBHOOK
-            }
-        }
         success {
             script {
                 if (env.BRANCH_NAME == 'master') {
diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts
index e21806660..3d1fb47f7 100644
--- a/build-logic/build.gradle.kts
+++ b/build-logic/build.gradle.kts
@@ -1,5 +1,3 @@
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
-
 plugins {
     `kotlin-dsl`
 }
@@ -10,17 +8,10 @@ repositories {
 }
 
 dependencies {
-    implementation("net.kyori", "indra-common", "2.0.6")
-    implementation("org.jfrog.buildinfo", "build-info-extractor-gradle", "4.26.1")
+    implementation("net.kyori", "indra-common", "3.0.1")
     implementation("com.github.johnrengelman", "shadow", "7.1.3-SNAPSHOT")
 
     // Within the gradle plugin classpath, there is a version conflict between loom and some other
     // plugin for databind. This fixes it: minimum 2.13.2 is required by loom.
     implementation("com.fasterxml.jackson.core:jackson-databind:2.14.0")
 }
-
-tasks.withType<KotlinCompile> {
-    kotlinOptions {
-        jvmTarget = "16"
-    }
-}
diff --git a/build-logic/src/main/kotlin/extensions.kt b/build-logic/src/main/kotlin/extensions.kt
index 0c01913d2..1e1732852 100644
--- a/build-logic/src/main/kotlin/extensions.kt
+++ b/build-logic/src/main/kotlin/extensions.kt
@@ -30,9 +30,6 @@ import org.gradle.api.artifacts.ProjectDependency
 import org.gradle.api.provider.Provider
 import org.gradle.kotlin.dsl.named
 
-fun Project.isSnapshot(): Boolean =
-    version.toString().endsWith("-SNAPSHOT")
-
 fun Project.relocate(pattern: String) {
     tasks.named<ShadowJar>("shadowJar") {
         relocate(pattern, "org.geysermc.geyser.shaded.$pattern")
diff --git a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts
index 44a74db3d..709867300 100644
--- a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts
+++ b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts
@@ -1,12 +1,25 @@
 plugins {
     `java-library`
-    `maven-publish`
+    id("net.kyori.indra")
 }
 
 dependencies {
     compileOnly("org.checkerframework", "checker-qual", "3.19.0")
 }
 
+indra {
+    github("GeyserMC", "Geyser") {
+        ci(true)
+        issues(true)
+        scm(true)
+    }
+    mitLicense()
+
+    javaVersions {
+        target(16)
+    }
+}
+
 tasks {
     processResources {
         // Spigot, BungeeCord, Velocity, Sponge, Fabric
@@ -21,14 +34,4 @@ tasks {
             )
         }
     }
-    compileJava {
-        options.encoding = Charsets.UTF_8.name()
-    }
-}
-
-java {
-    sourceCompatibility = JavaVersion.VERSION_16
-    targetCompatibility = JavaVersion.VERSION_16
-
-    withSourcesJar()
 }
diff --git a/build-logic/src/main/kotlin/geyser.publish-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.publish-conventions.gradle.kts
index 7525f97fa..036ee803c 100644
--- a/build-logic/src/main/kotlin/geyser.publish-conventions.gradle.kts
+++ b/build-logic/src/main/kotlin/geyser.publish-conventions.gradle.kts
@@ -1,33 +1,9 @@
 plugins {
     id("geyser.shadow-conventions")
-    id("com.jfrog.artifactory")
-    id("maven-publish")
+    id("net.kyori.indra.publishing")
 }
 
-publishing {
-    publications {
-        create<MavenPublication>("mavenJava") {
-            groupId = project.group as String
-            artifactId = project.name
-            version = project.version as String
-
-            from(components["java"])
-        }
-    }
-}
-
-artifactory {
-    setContextUrl("https://repo.opencollab.dev/artifactory")
-    publish {
-        repository {
-            setRepoKey(if (isSnapshot()) "maven-snapshots" else "maven-releases")
-            setMavenCompatible(true)
-        }
-        defaults {
-            publications("mavenJava")
-            setPublishArtifacts(true)
-            setPublishPom(true)
-            setPublishIvy(false)
-        }
-    }
+indra {
+    publishSnapshotsTo("geysermc", "https://repo.opencollab.dev/maven-snapshots")
+    publishReleasesTo("geysermc", "https://repo.opencollab.dev/maven-releases")
 }
diff --git a/core/src/test/java/org/geysermc/geyser/network/translators/chat/MessageTranslatorTest.java b/core/src/test/java/org/geysermc/geyser/network/translators/chat/MessageTranslatorTest.java
index e83c6f73d..a804916fa 100644
--- a/core/src/test/java/org/geysermc/geyser/network/translators/chat/MessageTranslatorTest.java
+++ b/core/src/test/java/org/geysermc/geyser/network/translators/chat/MessageTranslatorTest.java
@@ -27,18 +27,20 @@ package org.geysermc.geyser.network.translators.chat;
 
 import com.github.steveice10.mc.protocol.data.DefaultComponentSerializer;
 import org.geysermc.geyser.translator.text.MessageTranslator;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
 
 import java.util.HashMap;
 import java.util.Map;
 
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
 public class MessageTranslatorTest {
 
     private Map<String, String> messages = new HashMap<>();
 
-    @Before
+    @BeforeAll
     public void setUp() throws Exception {
         messages.put("{\"text\":\"\",\"extra\":[{\"text\":\"DoctorMad9952 joined the game\",\"color\":\"yellow\"}]}",
                 "§r§eDoctorMad9952 joined the game");
@@ -70,27 +72,27 @@ public class MessageTranslatorTest {
     public void convertMessage() {
         for (Map.Entry<String, String> entry : messages.entrySet()) {
             String bedrockMessage = MessageTranslator.convertMessage(entry.getKey(), "en_US");
-            Assert.assertEquals("Translation of messages is incorrect", entry.getValue(), bedrockMessage);
+            Assertions.assertEquals(entry.getValue(), bedrockMessage, "Translation of messages is incorrect");
         }
     }
 
     @Test
     public void convertMessageLenient() {
-        Assert.assertEquals("All newline message is not handled properly", "\n\n\n\n", MessageTranslator.convertMessageLenient("\n\n\n\n"));
-        Assert.assertEquals("Empty message is not handled properly", "", MessageTranslator.convertMessageLenient(""));
-        Assert.assertEquals("Reset before message is not handled properly", "§r§eGame Selector", MessageTranslator.convertMessageLenient("§r§eGame Selector"));
-        Assert.assertEquals("Unimplemented formatting chars not stripped", "Bold Underline", MessageTranslator.convertMessageLenient("§m§nBold Underline"));
+        Assertions.assertEquals("\n\n\n\n", MessageTranslator.convertMessageLenient("\n\n\n\n"), "All newline message is not handled properly");
+        Assertions.assertEquals("", MessageTranslator.convertMessageLenient(""), "Empty message is not handled properly");
+        Assertions.assertEquals("§r§eGame Selector", MessageTranslator.convertMessageLenient("§r§eGame Selector"), "Reset before message is not handled properly");
+        Assertions.assertEquals("Bold Underline", MessageTranslator.convertMessageLenient("§m§nBold Underline"), "Unimplemented formatting chars not stripped");
     }
 
     @Test
     public void convertToPlainText() {
-        Assert.assertEquals("JSON message is not handled properly", "Many colors here", MessageTranslator.convertToPlainText("{\"extra\":[{\"color\":\"red\",\"text\":\"M\"},{\"color\":\"gold\",\"text\":\"a\"},{\"color\":\"yellow\",\"text\":\"n\"},{\"color\":\"green\",\"text\":\"y \"},{\"color\":\"aqua\",\"text\":\"c\"},{\"color\":\"dark_purple\",\"text\":\"o\"},{\"color\":\"red\",\"text\":\"l\"},{\"color\":\"gold\",\"text\":\"o\"},{\"color\":\"yellow\",\"text\":\"r\"},{\"color\":\"green\",\"text\":\"s \"},{\"color\":\"aqua\",\"text\":\"h\"},{\"color\":\"dark_purple\",\"text\":\"e\"},{\"color\":\"red\",\"text\":\"r\"},{\"color\":\"gold\",\"text\":\"e\"}],\"text\":\"\"}", "en_US"));
-        Assert.assertEquals("Legacy formatted message is not handled properly (Colors)", "Many colors here", MessageTranslator.convertToPlainText("§cM§6a§en§ay §bc§5o§cl§6o§er§as §bh§5e§cr§6e"));
-        Assert.assertEquals("Legacy formatted message is not handled properly (Colors)", "Many colors here", MessageTranslator.convertToPlainText("§cM§6a§en§ay §bc§5o§cl§6o§er§as §bh§5e§cr§6e", "en_US"));
-        Assert.assertEquals("Legacy formatted message is not handled properly (Style)", "Obf Bold Strikethrough Underline Italic Reset", MessageTranslator.convertToPlainText("§kObf §lBold §mStrikethrough §nUnderline §oItalic §rReset", "en_US"));
-        Assert.assertEquals("Valid lenient JSON is not handled properly", "Strange", MessageTranslator.convertToPlainText("§rStrange", "en_US"));
-        Assert.assertEquals("Empty message is not handled properly", "", MessageTranslator.convertToPlainText("", "en_US"));
-        Assert.assertEquals("Whitespace is not preserved", "     ", MessageTranslator.convertToPlainText("     ", "en_US"));
+        Assertions.assertEquals("Many colors here", MessageTranslator.convertToPlainText("{\"extra\":[{\"color\":\"red\",\"text\":\"M\"},{\"color\":\"gold\",\"text\":\"a\"},{\"color\":\"yellow\",\"text\":\"n\"},{\"color\":\"green\",\"text\":\"y \"},{\"color\":\"aqua\",\"text\":\"c\"},{\"color\":\"dark_purple\",\"text\":\"o\"},{\"color\":\"red\",\"text\":\"l\"},{\"color\":\"gold\",\"text\":\"o\"},{\"color\":\"yellow\",\"text\":\"r\"},{\"color\":\"green\",\"text\":\"s \"},{\"color\":\"aqua\",\"text\":\"h\"},{\"color\":\"dark_purple\",\"text\":\"e\"},{\"color\":\"red\",\"text\":\"r\"},{\"color\":\"gold\",\"text\":\"e\"}],\"text\":\"\"}", "en_US"), "JSON message is not handled properly");
+        Assertions.assertEquals("Many colors here", MessageTranslator.convertToPlainText("§cM§6a§en§ay §bc§5o§cl§6o§er§as §bh§5e§cr§6e"), "Legacy formatted message is not handled properly (Colors)");
+        Assertions.assertEquals("Many colors here", MessageTranslator.convertToPlainText("§cM§6a§en§ay §bc§5o§cl§6o§er§as §bh§5e§cr§6e", "en_US"), "Legacy formatted message is not handled properly (Colors)");
+        Assertions.assertEquals("Obf Bold Strikethrough Underline Italic Reset", MessageTranslator.convertToPlainText("§kObf §lBold §mStrikethrough §nUnderline §oItalic §rReset", "en_US"), "Legacy formatted message is not handled properly (Style)");
+        Assertions.assertEquals("Strange", MessageTranslator.convertToPlainText("§rStrange", "en_US"), "Valid lenient JSON is not handled properly");
+        Assertions.assertEquals("", MessageTranslator.convertToPlainText("", "en_US"), "Empty message is not handled properly");
+        Assertions.assertEquals("     ", MessageTranslator.convertToPlainText("     ", "en_US"), "Whitespace is not preserved");
     }
 
     @Test
diff --git a/core/src/test/java/org/geysermc/geyser/translator/inventory/item/CustomItemsTest.java b/core/src/test/java/org/geysermc/geyser/translator/inventory/item/CustomItemsTest.java
index 145f46369..806ec4542 100644
--- a/core/src/test/java/org/geysermc/geyser/translator/inventory/item/CustomItemsTest.java
+++ b/core/src/test/java/org/geysermc/geyser/translator/inventory/item/CustomItemsTest.java
@@ -36,20 +36,22 @@ import org.geysermc.geyser.api.item.custom.CustomItemOptions;
 import org.geysermc.geyser.api.util.TriState;
 import org.geysermc.geyser.item.GeyserCustomItemOptions;
 import org.geysermc.geyser.registry.type.ItemMapping;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
 
 import java.util.List;
 import java.util.OptionalInt;
 
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
 public class CustomItemsTest {
     private ItemMapping testMappingWithDamage;
     private Object2IntMap<CompoundTag> tagToCustomItemWithDamage;
     private ItemMapping testMappingWithNoDamage;
     private Object2IntMap<CompoundTag> tagToCustomItemWithNoDamage;
 
-    @Before
+    @BeforeAll
     public void setup() {
         CustomItemOptions a = new GeyserCustomItemOptions(TriState.TRUE, OptionalInt.of(2), OptionalInt.empty());
         CustomItemOptions b = new GeyserCustomItemOptions(TriState.FALSE, OptionalInt.of(5), OptionalInt.empty());
@@ -147,12 +149,12 @@ public class CustomItemsTest {
     public void testCustomItems() {
         for (Object2IntMap.Entry<CompoundTag> entry : this.tagToCustomItemWithDamage.object2IntEntrySet()) {
             int id = CustomItemTranslator.getCustomItem(entry.getKey(), this.testMappingWithDamage);
-            Assert.assertEquals(entry.getKey() + " did not produce the correct custom item", entry.getIntValue(), id);
+            Assertions.assertEquals(entry.getIntValue(), id, entry.getKey() + " did not produce the correct custom item");
         }
 
         for (Object2IntMap.Entry<CompoundTag> entry : this.tagToCustomItemWithNoDamage.object2IntEntrySet()) {
             int id = CustomItemTranslator.getCustomItem(entry.getKey(), this.testMappingWithNoDamage);
-            Assert.assertEquals(entry.getKey() + " did not produce the correct custom item", entry.getIntValue(), id);
+            Assertions.assertEquals(entry.getIntValue(), id, entry.getKey() + " did not produce the correct custom item");
         }
     }
 }
diff --git a/core/src/test/java/org/geysermc/geyser/util/collection/GeyserCollectionsTest.java b/core/src/test/java/org/geysermc/geyser/util/collection/GeyserCollectionsTest.java
index a2a9f98f6..639c79331 100644
--- a/core/src/test/java/org/geysermc/geyser/util/collection/GeyserCollectionsTest.java
+++ b/core/src/test/java/org/geysermc/geyser/util/collection/GeyserCollectionsTest.java
@@ -25,9 +25,11 @@
 
 package org.geysermc.geyser.util.collection;
 
-import org.junit.Assert;
-import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
 
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
 public class GeyserCollectionsTest {
     private final byte[] bytes = new byte[] {(byte) 5, (byte) 4, (byte) 3, (byte) 2, (byte) 2, (byte) 1};
     private final boolean[] booleans = new boolean[] {true, false, false, true};
@@ -51,35 +53,35 @@ public class GeyserCollectionsTest {
         int lastKey = index;
 
         // Easy, understandable out-of-bounds checks
-        Assert.assertFalse("Map contains key bigger by one!", map.containsKey(lastKey));
-        Assert.assertTrue("Map doesn't contain final key!", map.containsKey(lastKey - 1));
+        Assertions.assertFalse(map.containsKey(lastKey), "Map contains key bigger by one!");
+        Assertions.assertTrue(map.containsKey(lastKey - 1), "Map doesn't contain final key!");
 
         // Ensure the first and last values do not throw an exception on get, and test getOrDefault
         map.get(start - 1);
         map.get(lastKey);
-        Assert.assertEquals(map.getOrDefault(start - 1, Byte.MAX_VALUE), Byte.MAX_VALUE);
-        Assert.assertEquals(map.getOrDefault(lastKey, Byte.MAX_VALUE), Byte.MAX_VALUE);
-        Assert.assertEquals(map.getOrDefault(lastKey, Byte.MIN_VALUE), Byte.MIN_VALUE);
+        Assertions.assertEquals(map.getOrDefault(start - 1, Byte.MAX_VALUE), Byte.MAX_VALUE);
+        Assertions.assertEquals(map.getOrDefault(lastKey, Byte.MAX_VALUE), Byte.MAX_VALUE);
+        Assertions.assertEquals(map.getOrDefault(lastKey, Byte.MIN_VALUE), Byte.MIN_VALUE);
 
-        Assert.assertEquals(map.size(), bytes.length);
+        Assertions.assertEquals(map.size(), bytes.length);
 
         for (int i = start; i < bytes.length; i++) {
-            Assert.assertTrue(map.containsKey(i));
-            Assert.assertEquals(map.get(i), bytes[i - start]);
+            Assertions.assertTrue(map.containsKey(i));
+            Assertions.assertEquals(map.get(i), bytes[i - start]);
         }
 
         for (int i = start - 1; i >= (start - 6); i--) {
             // Lower than expected check
-            Assert.assertFalse(i + " is in a map that starts with " + start, map.containsKey(i));
+            Assertions.assertFalse(map.containsKey(i), i + " is in a map that starts with " + start);
         }
 
         for (int i = bytes.length + start; i < bytes.length + 5 + start; i++) {
             // Higher than expected check
-            Assert.assertFalse(i + " is in a map that ends with " + (start + bytes.length), map.containsKey(i));
+            Assertions.assertFalse(map.containsKey(i), i + " is in a map that ends with " + (start + bytes.length));
         }
 
         for (byte b : bytes) {
-            Assert.assertTrue(map.containsValue(b));
+            Assertions.assertTrue(map.containsValue(b));
         }
     }
 
@@ -99,33 +101,33 @@ public class GeyserCollectionsTest {
         int lastKey = index;
 
         // Easy, understandable out-of-bounds checks
-        Assert.assertFalse("Map contains key bigger by one!", map.containsKey(lastKey));
-        Assert.assertTrue("Map doesn't contain final key!", map.containsKey(lastKey - 1));
+        Assertions.assertFalse(map.containsKey(lastKey), "Map contains key bigger by one!");
+        Assertions.assertTrue(map.containsKey(lastKey - 1), "Map doesn't contain final key!");
 
         // Ensure the first and last values do not throw an exception on get
         map.get(start - 1);
         map.get(lastKey);
-        Assert.assertTrue(map.getOrDefault(lastKey, true));
+        Assertions.assertTrue(map.getOrDefault(lastKey, true));
 
-        Assert.assertEquals(map.size(), booleans.length);
+        Assertions.assertEquals(map.size(), booleans.length);
 
         for (int i = start; i < booleans.length; i++) {
-            Assert.assertTrue(map.containsKey(i));
-            Assert.assertEquals(map.get(i), booleans[i - start]);
+            Assertions.assertTrue(map.containsKey(i));
+            Assertions.assertEquals(map.get(i), booleans[i - start]);
         }
 
         for (int i = start - 1; i >= (start - 6); i--) {
             // Lower than expected check
-            Assert.assertFalse(i + " is in a map that starts with " + start, map.containsKey(i));
+            Assertions.assertFalse(map.containsKey(i), i + " is in a map that starts with " + start);
         }
 
         for (int i = booleans.length + start; i < booleans.length + start + 5; i++) {
             // Higher than expected check
-            Assert.assertFalse(i + " is in a map that ends with " + (start + booleans.length), map.containsKey(i));
+            Assertions.assertFalse(map.containsKey(i), i + " is in a map that ends with " + (start + booleans.length));
         }
 
         for (boolean b : booleans) {
-            Assert.assertTrue(map.containsValue(b));
+            Assertions.assertTrue(map.containsValue(b));
         }
     }
 
@@ -145,35 +147,35 @@ public class GeyserCollectionsTest {
         int lastKey = index;
 
         // Easy, understandable out-of-bounds checks
-        Assert.assertFalse("Map contains key bigger by one!", map.containsKey(lastKey));
-        Assert.assertTrue("Map doesn't contain final key!", map.containsKey(lastKey - 1));
+        Assertions.assertFalse(map.containsKey(lastKey), "Map contains key bigger by one!");
+        Assertions.assertTrue(map.containsKey(lastKey - 1), "Map doesn't contain final key!");
 
         // Ensure the first and last values do not throw an exception on get, and test getOrDefault
         map.get(start - 1);
         map.get(lastKey);
-        Assert.assertEquals(map.getOrDefault(start - 1, Integer.MAX_VALUE), Integer.MAX_VALUE);
-        Assert.assertEquals(map.getOrDefault(lastKey, Integer.MAX_VALUE), Integer.MAX_VALUE);
-        Assert.assertEquals(map.getOrDefault(lastKey, Integer.MIN_VALUE), Integer.MIN_VALUE);
+        Assertions.assertEquals(map.getOrDefault(start - 1, Integer.MAX_VALUE), Integer.MAX_VALUE);
+        Assertions.assertEquals(map.getOrDefault(lastKey, Integer.MAX_VALUE), Integer.MAX_VALUE);
+        Assertions.assertEquals(map.getOrDefault(lastKey, Integer.MIN_VALUE), Integer.MIN_VALUE);
 
-        Assert.assertEquals(map.size(), ints.length);
+        Assertions.assertEquals(map.size(), ints.length);
 
         for (int i = start; i < ints.length; i++) {
-            Assert.assertTrue(map.containsKey(i));
-            Assert.assertEquals(map.get(i), ints[i - start]);
+            Assertions.assertTrue(map.containsKey(i));
+            Assertions.assertEquals(map.get(i), ints[i - start]);
         }
 
         for (int i = start - 1; i >= (start - 6); i--) {
             // Lower than expected check
-            Assert.assertFalse(i + " is in a map that starts with " + start, map.containsKey(i));
+            Assertions.assertFalse(map.containsKey(i), i + " is in a map that starts with " + start);
         }
 
         for (int i = ints.length + start; i < ints.length + 5 + start; i++) {
             // Higher than expected check
-            Assert.assertFalse(i + " is in a map that ends with " + (start + ints.length), map.containsKey(i));
+            Assertions.assertFalse(map.containsKey(i), i + " is in a map that ends with " + (start + ints.length));
         }
 
         for (int i : ints) {
-            Assert.assertTrue(map.containsValue(i));
+            Assertions.assertTrue(map.containsValue(i));
         }
     }
 }
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index f62faa54f..8858edc68 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -15,7 +15,7 @@ mcprotocollib = "1.19.3-20230107.194116-10"
 packetlib = "3.0.1"
 adventure = "4.12.0-20220629.025215-9"
 adventure-platform = "4.1.2"
-junit = "4.13.1"
+junit = "5.9.2"
 checkerframework = "3.19.0"
 log4j = "2.17.1"
 jline = "3.21.0"
@@ -81,7 +81,7 @@ checker-qual = { group = "org.checkerframework", name = "checker-qual", version.
 commodore = { group = "me.lucko", name = "commodore", version.ref = "commodore" }
 guava = { group = "com.google.guava", name = "guava", version.ref = "guava" }
 gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }
-junit = { group = "junit", name = "junit", version.ref = "junit" }
+junit = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" }
 mcauthlib = { group = "com.github.GeyserMC", name = "MCAuthLib", version.ref = "mcauthlib" }
 mcprotocollib = { group = "com.github.steveice10", name = "mcprotocollib", version.ref = "mcprotocollib" }
 packetlib = { group = "com.github.steveice10", name = "packetlib", version.ref = "packetlib" }

From c9b58e154fe58a24fd8ef23ba522c81d67d54ba1 Mon Sep 17 00:00:00 2001
From: rtm516 <rtm516@users.noreply.github.com>
Date: Sat, 25 Feb 2023 02:36:51 +0000
Subject: [PATCH 12/59] Allow build notifcation on success or failure

---
 .github/workflows/build.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 160191d46..553e2c5b2 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -46,8 +46,8 @@ jobs:
           ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP ./handleBuild.sh geyser $version $GITHUB_RUN_ID $GITHUB_SHA
 
       - name: Notify Discord
-        if: ${{ github.repository == 'GeyserMC/Geyser' }}
+        if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }}
         uses: Tim203/actions-git-discord-webhook@main
         with:
           webhook_url: ${{ secrets.DISCORD_WEBHOOK }}
-          status: ${{ job.status }}
\ No newline at end of file
+          status: ${{ job.status }}

From 806ce6c9303ae5a2673f4bf2013eb3a9e87afebb Mon Sep 17 00:00:00 2001
From: rtm516 <rtm516@users.noreply.github.com>
Date: Sat, 25 Feb 2023 02:57:43 +0000
Subject: [PATCH 13/59] Import build secrets as env vars

---
 .github/workflows/build.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 553e2c5b2..a8e1ec152 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -34,6 +34,9 @@ jobs:
       - name: Publish to Downloads API
         if: ${{ github.ref_name == 'master' && job.status == 'success' && github.repository == 'GeyserMC/Geyser' }}
         shell: bash
+        env:
+          DOWNLOADS_PRIVATE_KEY: ${{ secrets.DOWNLOADS_PRIVATE_KEY }}
+          DOWNLOADS_SERVER_IP: ${{ secrets.DOWNLOADS_SERVER_IP }}
         run: |
           # Save the private key to a file
           echo "$DOWNLOADS_PRIVATE_KEY" > id_ecdsa

From 9b77d43fa20ea501c4fcce0b69f533be43f070e7 Mon Sep 17 00:00:00 2001
From: rtm516 <rtm516@users.noreply.github.com>
Date: Sat, 25 Feb 2023 03:08:02 +0000
Subject: [PATCH 14/59] Testing in production

---
 .github/workflows/build.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index a8e1ec152..d493ffe94 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -35,6 +35,7 @@ jobs:
         if: ${{ github.ref_name == 'master' && job.status == 'success' && github.repository == 'GeyserMC/Geyser' }}
         shell: bash
         env:
+          DOWNLOADS_USERNAME: ${{ vars.DOWNLOADS_USERNAME }}
           DOWNLOADS_PRIVATE_KEY: ${{ secrets.DOWNLOADS_PRIVATE_KEY }}
           DOWNLOADS_SERVER_IP: ${{ secrets.DOWNLOADS_SERVER_IP }}
         run: |

From b0c42086ad70c0b010bbfd3084a9205bc85d05d4 Mon Sep 17 00:00:00 2001
From: rtm516 <rtm516@users.noreply.github.com>
Date: Sat, 25 Feb 2023 04:03:42 +0000
Subject: [PATCH 15/59] Fix build IDs for publishing

---
 .github/workflows/build.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index d493ffe94..f83b9a901 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -47,7 +47,7 @@ jobs:
           # Copy over artifacts
           scp -B -o StrictHostKeyChecking=no -i id_ecdsa bootstrap/**/build/libs/Geyser-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/files/
           # Run the build script
-          ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP ./handleBuild.sh geyser $version $GITHUB_RUN_ID $GITHUB_SHA
+          ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP ./handleBuild.sh geyser $version $GITHUB_RUN_NUMBER $GITHUB_SHA
 
       - name: Notify Discord
         if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }}

From fca726caa4e408a84707dce0f027ff82aec6be4d Mon Sep 17 00:00:00 2001
From: onebeastchris <reichel32574@gmail.com>
Date: Mon, 27 Feb 2023 20:09:07 +0100
Subject: [PATCH 16/59] version bump (#3585)

seems like aternos depends on this to show the latest version iirc; should be bumped either way
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 6996086b9..2fd09eb8f 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t
 
 Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here!
 
-### Currently supporting Minecraft Bedrock 1.19.20 - 1.19.62 and Minecraft Java 1.19.3.
+### Currently supporting Minecraft Bedrock 1.19.20 - 1.19.63 and Minecraft Java 1.19.3.
 
 ## Setting Up
 Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser.

From 95d10fb7fc499cedc38b05b3b58ba1523109a0ca Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Thu, 2 Mar 2023 18:40:40 -0500
Subject: [PATCH 17/59] Don't throw an AssertionError on failed locale download

Fixes #3589
---
 core/src/main/java/org/geysermc/geyser/util/WebUtils.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java b/core/src/main/java/org/geysermc/geyser/util/WebUtils.java
index c0889f1c5..e4a98b3fc 100644
--- a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java
+++ b/core/src/main/java/org/geysermc/geyser/util/WebUtils.java
@@ -91,7 +91,7 @@ public class WebUtils {
             InputStream in = con.getInputStream();
             Files.copy(in, Paths.get(fileLocation), StandardCopyOption.REPLACE_EXISTING);
         } catch (Exception e) {
-            throw new AssertionError("Unable to download and save file: " + fileLocation + " (" + reqURL + ")", e);
+            throw new RuntimeException("Unable to download and save file: " + fileLocation + " (" + reqURL + ")", e);
         }
     }
 

From 10c2e51da42ea65bf1402ee24c606b58c31e78cf Mon Sep 17 00:00:00 2001
From: apex_ <contact@thatapex.dev>
Date: Fri, 3 Mar 2023 15:09:52 +0100
Subject: [PATCH 18/59] Fix closing inventory confirmation behavior (#3587)

---
 .../main/java/org/geysermc/geyser/inventory/Inventory.java    | 4 ++++
 .../main/java/org/geysermc/geyser/util/InventoryUtils.java    | 4 +++-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java
index f01d242ad..624d0df27 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java
@@ -89,6 +89,10 @@ public abstract class Inventory {
     @Setter
     private boolean pending = false;
 
+    @Getter
+    @Setter
+    private boolean displayed = false;
+
     protected Inventory(int id, int size, ContainerType containerType) {
         this("Inventory", id, size, containerType);
     }
diff --git a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java
index 1f31d917b..1c07a0b1e 100644
--- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java
+++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java
@@ -95,6 +95,7 @@ public class InventoryUtils {
                     if (openInv != null && openInv.getJavaId() == inventory.getJavaId()) {
                         translator.openInventory(session, inventory);
                         translator.updateInventory(session, inventory);
+                        openInv.setDisplayed(true);
                     } else if (openInv != null && openInv.isPending()) {
                         // Presumably, this inventory is no longer relevant, and the client doesn't care about it
                         displayInventory(session, openInv);
@@ -103,6 +104,7 @@ public class InventoryUtils {
             } else {
                 translator.openInventory(session, inventory);
                 translator.updateInventory(session, inventory);
+                inventory.setDisplayed(true);
             }
         } else {
             session.setOpenInventory(null);
@@ -117,7 +119,7 @@ public class InventoryUtils {
         if (inventory != null) {
             InventoryTranslator translator = session.getInventoryTranslator();
             translator.closeInventory(session, inventory);
-            if (confirm && !inventory.isPending() && !(translator instanceof LecternInventoryTranslator)) {
+            if (confirm && inventory.isDisplayed() && !inventory.isPending() && !(translator instanceof LecternInventoryTranslator)) {
                 session.setClosingInventory(true);
             }
         }

From 1be2a1ccac7dd78d42843ac85203757f891ea562 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Mon, 6 Mar 2023 20:53:54 -0500
Subject: [PATCH 19/59] Fix sleeping on vanilla/Fabric

Fixes #3595
---
 .../org/geysermc/geyser/entity/type/player/PlayerEntity.java | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java
index 74a55144e..78456646f 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java
@@ -239,7 +239,10 @@ public class PlayerEntity extends LivingEntity {
 
     @Override
     public Vector3i setBedPosition(EntityMetadata<Optional<Vector3i>, ?> entityMetadata) {
-        return bedPosition = super.setBedPosition(entityMetadata);
+        bedPosition = super.setBedPosition(entityMetadata);
+        // Fixes https://github.com/GeyserMC/Geyser/issues/3595 on vanilla 1.19.3 servers - did not happen on Paper
+        entityMetadata.getValue().ifPresent(pos -> this.setPosition(pos.toFloat()));
+        return bedPosition;
     }
 
     public void setAbsorptionHearts(FloatEntityMetadata entityMetadata) {

From 81f0cbe5eded030ce1a1d745308040c2bf0c114a Mon Sep 17 00:00:00 2001
From: YouHaveTrouble <garrenpolska@gmail.com>
Date: Tue, 7 Mar 2023 18:54:41 +0100
Subject: [PATCH 20/59] Assign permission to the command (#3599)

Assigning permission allows people to possibly deny that permission to hide the command from tab complete list.
Permission is defaulted to true, so command keeps current behavior by default.
---
 bootstrap/spigot/src/main/resources/plugin.yml | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/bootstrap/spigot/src/main/resources/plugin.yml b/bootstrap/spigot/src/main/resources/plugin.yml
index e28b8981d..d8bc264a9 100644
--- a/bootstrap/spigot/src/main/resources/plugin.yml
+++ b/bootstrap/spigot/src/main/resources/plugin.yml
@@ -8,4 +8,8 @@ api-version: 1.13
 commands:
   geyser:
     description: The main command for Geyser.
-    usage: /geyser <subcommand>
\ No newline at end of file
+    usage: /geyser <subcommand>
+    permission: geyser.command
+permissions:
+  geyser.command:
+    default: true

From a5a4f5c3eaa633ac6a1b2b569084602ee2a72958 Mon Sep 17 00:00:00 2001
From: Kas-tle <26531652+Kas-tle@users.noreply.github.com>
Date: Tue, 7 Mar 2023 18:59:21 -0800
Subject: [PATCH 21/59] Properly Cache Build Dependencies, Optimize Build
 Action, and Save Build Action Artifacts (#3593)

* Attempt cache gradle properly

* Save artifacts on standard build

* Dont build on bad path and standardize pr action

* Don't do caching for PR builds

* Correct exclusion paths

* Allow manual trigger of build action
---
 .github/workflows/build.yml       | 70 +++++++++++++++++++++++++++++--
 .github/workflows/pullrequest.yml | 31 ++++++++++----
 2 files changed, 90 insertions(+), 11 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index f83b9a901..2d1c84670 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1,6 +1,18 @@
 name: Build
 
-on: [push]
+on:
+  workflow_dispatch:
+  push:
+    paths-ignore:
+      - '.github/ISSUE_TEMPLATE/*.yml'
+      - '.github/actions/pullrequest.yml'
+      - '.idea/copyright/*.xml' 
+      - '.gitignore'
+      - 'CONTRIBUTING.md'
+      - 'LICENSE'
+      - 'Jenkinsfile '
+      - 'README.md'
+      - 'licenseheader.txt'
 
 jobs:
   build:
@@ -15,12 +27,64 @@ jobs:
         with:
           java-version: 17
           distribution: temurin
-          cache: gradle
+          
+      - name: Cache Gradle Packages
+        uses: actions/cache@v3
+        with:
+          path: | 
+            ~/.m2
+            ~/.gradle/caches
+            ~/.gradle/wrapper
+          key: ${{ github.ref_name }}-gradle-${{ hashFiles('*.gradle.kts', 'gradle.properties', 'gradlew', 'gradle/*', 'gradle/**/*', 'build-logic/*', 'build-logic/**/**/**/*', '**/*.gradle.kts', '**/**/*.gradle.kts') }}
+          restore-keys: ${{ github.ref_name }}-gradle-
 
       - name: Build
         uses: gradle/gradle-build-action@v2
         with:
-          arguments: build
+          arguments: build --no-daemon
+          
+      - name: Archive artifacts (Geyser Fabric)
+        uses: actions/upload-artifact@v3
+        if: success()
+        with:
+          name: Geyser Fabric
+          path: bootstrap/fabric/build/libs/Geyser-Fabric.jar
+          if-no-files-found: error
+      - name: Archive artifacts (Geyser Standalone)
+        uses: actions/upload-artifact@v3
+        if: success()
+        with:
+          name: Geyser Standalone
+          path: bootstrap/standalone/build/libs/Geyser-Standalone.jar
+          if-no-files-found: error
+      - name: Archive artifacts (Geyser Spigot)
+        uses: actions/upload-artifact@v3
+        if: success()
+        with:
+          name: Geyser Spigot
+          path: bootstrap/spigot/build/libs/Geyser-Spigot.jar
+          if-no-files-found: error
+      - name: Archive artifacts (Geyser BungeeCord)
+        uses: actions/upload-artifact@v3
+        if: success()
+        with:
+          name: Geyser BungeeCord
+          path: bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
+          if-no-files-found: error
+      - name: Archive artifacts (Geyser Sponge)
+        uses: actions/upload-artifact@v3
+        if: success()
+        with:
+          name: Geyser Sponge
+          path: bootstrap/sponge/build/libs/Geyser-Sponge.jar
+          if-no-files-found: error
+      - name: Archive artifacts (Geyser Velocity)
+        uses: actions/upload-artifact@v3
+        if: success()
+        with:
+          name: Geyser Velocity
+          path: bootstrap/velocity/build/libs/Geyser-Velocity.jar
+          if-no-files-found: error
 
       - name: Publish to Maven Repository
         if: ${{ job.status == 'success' && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml
index 8d5f5c03c..9567fb414 100644
--- a/.github/workflows/pullrequest.yml
+++ b/.github/workflows/pullrequest.yml
@@ -1,6 +1,16 @@
 name: Build Pull Request
 
-on: [pull_request]
+on: 
+  pull_request:
+    paths-ignore:
+      - '.github/ISSUE_TEMPLATE/*.yml'
+      - '.idea/copyright/*.xml' 
+      - '.gitignore'
+      - 'CONTRIBUTING.md'
+      - 'LICENSE'
+      - 'Jenkinsfile '
+      - 'README.md'
+      - 'licenseheader.txt'
 
 jobs:
   build:
@@ -11,7 +21,6 @@ jobs:
         with:
           java-version: 17
           distribution: temurin
-          cache: gradle
 
       - name: Check if the author has forked the API repo
         uses: Kas-tle/ForkFinder@v1.0.1
@@ -44,38 +53,44 @@ jobs:
           build-root-directory: geyser
 
       - name: Archive artifacts (Geyser Fabric)
-        uses: actions/upload-artifact@v2
+        uses: actions/upload-artifact@v3
         if: success()
         with:
           name: Geyser Fabric
           path: geyser/bootstrap/fabric/build/libs/Geyser-Fabric.jar
+          if-no-files-found: error
       - name: Archive artifacts (Geyser Standalone)
-        uses: actions/upload-artifact@v2
+        uses: actions/upload-artifact@v3
         if: success()
         with:
           name: Geyser Standalone
           path: geyser/bootstrap/standalone/build/libs/Geyser-Standalone.jar
+          if-no-files-found: error
       - name: Archive artifacts (Geyser Spigot)
-        uses: actions/upload-artifact@v2
+        uses: actions/upload-artifact@v3
         if: success()
         with:
           name: Geyser Spigot
           path: geyser/bootstrap/spigot/build/libs/Geyser-Spigot.jar
+          if-no-files-found: error
       - name: Archive artifacts (Geyser BungeeCord)
-        uses: actions/upload-artifact@v2
+        uses: actions/upload-artifact@v3
         if: success()
         with:
           name: Geyser BungeeCord
           path: geyser/bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
+          if-no-files-found: error
       - name: Archive artifacts (Geyser Sponge)
-        uses: actions/upload-artifact@v2
+        uses: actions/upload-artifact@v3
         if: success()
         with:
           name: Geyser Sponge
           path: geyser/bootstrap/sponge/build/libs/Geyser-Sponge.jar
+          if-no-files-found: error
       - name: Archive artifacts (Geyser Velocity)
-        uses: actions/upload-artifact@v2
+        uses: actions/upload-artifact@v3
         if: success()
         with:
           name: Geyser Velocity
           path: geyser/bootstrap/velocity/build/libs/Geyser-Velocity.jar
+          if-no-files-found: error

From 2f23e5cb9c4c1d2f50b0dd341df0dfbac05f8bdf Mon Sep 17 00:00:00 2001
From: nils <github@ni.ls>
Date: Fri, 10 Mar 2023 06:13:20 +0100
Subject: [PATCH 22/59] fix: Fix legacy ping passthough (#3601)

---
 .../geysermc/geyser/ping/GeyserLegacyPingPassthrough.java   | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java b/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java
index a69d9bc3e..bdbe2f760 100644
--- a/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java
+++ b/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java
@@ -79,7 +79,8 @@ public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runn
         try (Socket socket = new Socket()) {
             String address = geyser.getConfig().getRemote().address();
             int port = geyser.getConfig().getRemote().port();
-            socket.connect(new InetSocketAddress(address, port), 5000);
+            InetSocketAddress endpoint = new InetSocketAddress(address, port);
+            socket.connect(endpoint, 5000);
 
             ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream();
             try (DataOutputStream handshake = new DataOutputStream(byteArrayStream)) {
@@ -103,7 +104,8 @@ public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runn
                             HAProxyProxiedProtocol.TCP4.byteValue() : HAProxyProxiedProtocol.TCP6.byteValue());
                     byte[] srcAddrBytes = NetUtil.createByteArrayFromIpAddressString(
                             ((InetSocketAddress) socket.getLocalSocketAddress()).getAddress().getHostAddress());
-                    byte[] dstAddrBytes = NetUtil.createByteArrayFromIpAddressString(address);
+                    byte[] dstAddrBytes = NetUtil.createByteArrayFromIpAddressString(
+                            endpoint.getAddress().getHostAddress());
                     dataOutputStream.writeShort(srcAddrBytes.length + dstAddrBytes.length + 4);
                     dataOutputStream.write(srcAddrBytes);
                     dataOutputStream.write(dstAddrBytes);

From b3f1c64249b576a75643ed05fcba3d9bb52478c3 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Fri, 10 Mar 2023 20:51:51 -0500
Subject: [PATCH 23/59] Base changes for Java 1.19.4 support

---
 core/build.gradle.kts                         |  4 ---
 .../geyser/entity/EntityDefinitions.java      |  2 +-
 .../type/living/monster/EndermanEntity.java   | 10 +++-----
 .../geyser/level/physics/Direction.java       | 20 +++++++--------
 .../java/JavaUpdateRecipesTranslator.java     |  4 +--
 .../entity/JavaSetPassengersTranslator.java   | 10 ++++++++
 .../player/JavaPlayerPositionTranslator.java  | 25 -------------------
 .../java/level/JavaBlockEventTranslator.java  | 10 ++++----
 .../java/level/JavaLevelEventTranslator.java  |  2 +-
 gradle/libs.versions.toml                     |  4 +--
 10 files changed, 32 insertions(+), 59 deletions(-)

diff --git a/core/build.gradle.kts b/core/build.gradle.kts
index 4265a9c35..9ba399674 100644
--- a/core/build.gradle.kts
+++ b/core/build.gradle.kts
@@ -31,10 +31,6 @@ dependencies {
         exclude("com.github.GeyserMC", "mcauthlib")
     }
 
-    api(libs.packetlib) {
-        exclude("io.netty", "netty-all")
-    }
-
     implementation(libs.raknet) {
         exclude("io.netty", "*");
     }
diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java
index b97e23847..3271a962f 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java
@@ -486,7 +486,7 @@ public final class EntityDefinitions {
             ENDERMAN = EntityDefinition.inherited(EndermanEntity::new, mobEntityBase)
                     .type(EntityType.ENDERMAN)
                     .height(2.9f).width(0.6f)
-                    .addTranslator(MetadataType.BLOCK_STATE, EndermanEntity::setCarriedBlock)
+                    .addTranslator(MetadataType.OPTIONAL_BLOCK_STATE, EndermanEntity::setCarriedBlock)
                     .addTranslator(MetadataType.BOOLEAN, EndermanEntity::setScreaming)
                     .addTranslator(MetadataType.BOOLEAN, EndermanEntity::setAngry)
                     .build();
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java
index 04b46997d..1d1f61af1 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java
@@ -28,6 +28,7 @@ package org.geysermc.geyser.entity.type.living.monster;
 import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
 import com.github.steveice10.mc.protocol.data.game.entity.metadata.OptionalIntMetadataType;
 import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
 import com.nukkitx.math.vector.Vector3f;
 import com.nukkitx.protocol.bedrock.data.SoundEvent;
 import com.nukkitx.protocol.bedrock.data.entity.EntityData;
@@ -45,13 +46,8 @@ public class EndermanEntity extends MonsterEntity {
         super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
     }
 
-    public void setCarriedBlock(EntityMetadata<OptionalInt, OptionalIntMetadataType> entityMetadata) {
-        int bedrockBlockId;
-        if (entityMetadata.getValue().isPresent()) {
-            bedrockBlockId = session.getBlockMappings().getBedrockBlockId(entityMetadata.getValue().getAsInt());
-        } else {
-            bedrockBlockId = session.getBlockMappings().getBedrockAirId();
-        }
+    public void setCarriedBlock(IntEntityMetadata entityMetadata) {
+        int bedrockBlockId = session.getBlockMappings().getBedrockBlockId(entityMetadata.getPrimitiveValue());;
 
         dirtyMetadata.put(EntityData.CARRIED_BLOCK, bedrockBlockId);
     }
diff --git a/core/src/main/java/org/geysermc/geyser/level/physics/Direction.java b/core/src/main/java/org/geysermc/geyser/level/physics/Direction.java
index 48c50bc69..95c0cd119 100644
--- a/core/src/main/java/org/geysermc/geyser/level/physics/Direction.java
+++ b/core/src/main/java/org/geysermc/geyser/level/physics/Direction.java
@@ -25,19 +25,18 @@
 
 package org.geysermc.geyser.level.physics;
 
-import com.github.steveice10.mc.protocol.data.game.level.block.value.PistonValue;
 import com.nukkitx.math.vector.Vector3i;
 import lombok.Getter;
 
 import javax.annotation.Nonnull;
 
 public enum Direction {
-    DOWN(1, Vector3i.from(0, -1, 0), Axis.Y, PistonValue.DOWN),
-    UP(0, Vector3i.UNIT_Y, Axis.Y, PistonValue.UP),
-    NORTH(3, Vector3i.from(0, 0, -1), Axis.Z, PistonValue.NORTH),
-    SOUTH(2, Vector3i.UNIT_Z, Axis.Z, PistonValue.SOUTH),
-    WEST(5, Vector3i.from(-1, 0, 0), Axis.X, PistonValue.WEST),
-    EAST(4, Vector3i.UNIT_X, Axis.X, PistonValue.EAST);
+    DOWN(1, Vector3i.from(0, -1, 0), Axis.Y, com.github.steveice10.mc.protocol.data.game.entity.object.Direction.DOWN),
+    UP(0, Vector3i.UNIT_Y, Axis.Y, com.github.steveice10.mc.protocol.data.game.entity.object.Direction.UP),
+    NORTH(3, Vector3i.from(0, 0, -1), Axis.Z, com.github.steveice10.mc.protocol.data.game.entity.object.Direction.NORTH),
+    SOUTH(2, Vector3i.UNIT_Z, Axis.Z, com.github.steveice10.mc.protocol.data.game.entity.object.Direction.SOUTH),
+    WEST(5, Vector3i.from(-1, 0, 0), Axis.X, com.github.steveice10.mc.protocol.data.game.entity.object.Direction.WEST),
+    EAST(4, Vector3i.UNIT_X, Axis.X, com.github.steveice10.mc.protocol.data.game.entity.object.Direction.EAST);
 
     public static final Direction[] VALUES = values();
 
@@ -46,10 +45,9 @@ public enum Direction {
     private final Vector3i unitVector;
     @Getter
     private final Axis axis;
-    @Getter
-    private final PistonValue pistonValue;
+    private final com.github.steveice10.mc.protocol.data.game.entity.object.Direction pistonValue;
 
-    Direction(int reversedId, Vector3i unitVector, Axis axis, PistonValue pistonValue) {
+    Direction(int reversedId, Vector3i unitVector, Axis axis, com.github.steveice10.mc.protocol.data.game.entity.object.Direction pistonValue) {
         this.reversedId = reversedId;
         this.unitVector = unitVector;
         this.axis = axis;
@@ -69,7 +67,7 @@ public enum Direction {
     }
 
     @Nonnull
-    public static Direction fromPistonValue(PistonValue pistonValue) {
+    public static Direction fromPistonValue(com.github.steveice10.mc.protocol.data.game.entity.object.Direction pistonValue) {
         for (Direction direction : VALUES) {
             if (direction.pistonValue == pistonValue) {
                 return direction;
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java
index 6159e9dd5..9923c0a16 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java
@@ -29,9 +29,9 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
 import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient;
 import com.github.steveice10.mc.protocol.data.game.recipe.Recipe;
 import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType;
+import com.github.steveice10.mc.protocol.data.game.recipe.data.LegacyUpgradeRecipeData;
 import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData;
 import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData;
-import com.github.steveice10.mc.protocol.data.game.recipe.data.SmithingRecipeData;
 import com.github.steveice10.mc.protocol.data.game.recipe.data.StoneCuttingRecipeData;
 import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket;
 import com.nukkitx.protocol.bedrock.data.inventory.CraftingData;
@@ -137,7 +137,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
                 }
                 case SMITHING -> {
                     // Required to translate these as of 1.18.10, or else they cannot be crafted
-                    SmithingRecipeData recipeData = (SmithingRecipeData) recipe.getData();
+                    LegacyUpgradeRecipeData recipeData = (LegacyUpgradeRecipeData) recipe.getData();
                     ItemData output = ItemTranslator.translateToBedrock(session, recipeData.getResult());
                     for (ItemStack base : recipeData.getBase().getOptions()) {
                         ItemDescriptorWithCount bedrockBase = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, base));
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetPassengersTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetPassengersTranslator.java
index 63985d9ae..8fa528cb7 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetPassengersTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetPassengersTranslator.java
@@ -91,6 +91,16 @@ public class JavaSetPassengersTranslator extends PacketTranslator<ClientboundSet
                 EntityUtils.updateMountOffset(passenger, entity, false, false, (packet.getPassengerIds().length > 1));
                 // Force an update to the passenger metadata
                 passenger.updateBedrockMetadata();
+
+                if (passenger == session.getPlayerEntity()) {
+                    //TODO test
+                    if (session.getMountVehicleScheduledFuture() != null) {
+                        // Cancel this task as it is now unnecessary.
+                        // Note that this isn't present in JavaSetPassengersTranslator as that code is not called for players
+                        // as of Java 1.19.3, but the scheduled future checks for the vehicle being null anyway.
+                        session.getMountVehicleScheduledFuture().cancel(false);
+                    }
+                }
             }
         }
 
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java
index 5f182805e..ff745a546 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java
@@ -30,20 +30,16 @@ import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player
 import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundAcceptTeleportationPacket;
 import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket;
 import com.nukkitx.math.vector.Vector3f;
-import com.nukkitx.protocol.bedrock.data.entity.EntityLinkData;
 import com.nukkitx.protocol.bedrock.packet.ChunkRadiusUpdatedPacket;
 import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
 import com.nukkitx.protocol.bedrock.packet.RespawnPacket;
-import com.nukkitx.protocol.bedrock.packet.SetEntityLinkPacket;
 import org.geysermc.geyser.entity.EntityDefinitions;
-import org.geysermc.geyser.entity.type.Entity;
 import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
 import org.geysermc.geyser.session.GeyserSession;
 import org.geysermc.geyser.session.cache.TeleportCache;
 import org.geysermc.geyser.translator.protocol.PacketTranslator;
 import org.geysermc.geyser.translator.protocol.Translator;
 import org.geysermc.geyser.util.ChunkUtils;
-import org.geysermc.geyser.util.EntityUtils;
 
 @Translator(packet = ClientboundPlayerPositionPacket.class)
 public class JavaPlayerPositionTranslator extends PacketTranslator<ClientboundPlayerPositionPacket> {
@@ -101,27 +97,6 @@ public class JavaPlayerPositionTranslator extends PacketTranslator<ClientboundPl
             return;
         }
 
-        Entity vehicle;
-        if (packet.isDismountVehicle() && (vehicle = session.getPlayerEntity().getVehicle()) != null) {
-            SetEntityLinkPacket linkPacket = new SetEntityLinkPacket();
-            linkPacket.setEntityLink(new EntityLinkData(vehicle.getGeyserId(), entity.getGeyserId(), EntityLinkData.Type.REMOVE, false, false));
-            session.sendUpstreamPacket(linkPacket);
-
-            vehicle.getPassengers().remove(entity);
-            session.getPlayerEntity().setVehicle(null);
-
-            EntityUtils.updateRiderRotationLock(entity, null, false);
-            EntityUtils.updateMountOffset(entity, null, false, false, entity.getPassengers().size() > 1);
-            entity.updateBedrockMetadata();
-
-            if (session.getMountVehicleScheduledFuture() != null) {
-                // Cancel this task as it is now unnecessary.
-                // Note that this isn't present in JavaSetPassengersTranslator as that code is not called for players
-                // as of Java 1.19.3, but the scheduled future checks for the vehicle being null anyway.
-                session.getMountVehicleScheduledFuture().cancel(false);
-            }
-        }
-
         // If coordinates are relative, then add to the existing coordinate
         double newX = packet.getX() +
                 (packet.getRelative().contains(PositionElement.X) ? entity.getPosition().getX() : 0);
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java
index 8824f88c4..4d35db562 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java
@@ -57,13 +57,13 @@ public class JavaBlockEventTranslator extends PacketTranslator<ClientboundBlockE
         } else if (packet.getValue() instanceof EndGatewayValue) {
             blockEventPacket.setEventType(1);
             session.sendUpstreamPacket(blockEventPacket);
-        } else if (packet.getValue() instanceof NoteBlockValue) {
-            int blockState = session.getGeyser().getWorldManager().getBlockAt(session, position);
-            blockEventPacket.setEventData(BlockStateValues.getNoteblockPitch(blockState));
-            session.sendUpstreamPacket(blockEventPacket);
+//        } else if (packet.getValue() instanceof NoteBlockValue) {
+//            int blockState = session.getGeyser().getWorldManager().getBlockAt(session, position);
+//            blockEventPacket.setEventData(BlockStateValues.getNoteblockPitch(blockState));
+//            session.sendUpstreamPacket(blockEventPacket);
         } else if (packet.getValue() instanceof PistonValue pistonValue) {
             PistonValueType action = (PistonValueType) packet.getType();
-            Direction direction = Direction.fromPistonValue(pistonValue);
+            Direction direction = Direction.fromPistonValue(pistonValue.getDirection());
             PistonCache pistonCache = session.getPistonCache();
 
             if (session.getGeyser().getPlatformType() == PlatformType.SPIGOT) {
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java
index 797699e2b..019865311 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java
@@ -157,7 +157,7 @@ public class JavaLevelEventTranslator extends PacketTranslator<ClientboundLevelE
 
                 SmokeEventData smokeEventData = (SmokeEventData) packet.getData();
                 int data = 0;
-                switch (smokeEventData) {
+                switch (smokeEventData.getDirection()) {
                     case DOWN -> {
                         data = 4;
                         pos = pos.add(0, -0.9f, 0);
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 8858edc68..d83aaa8f4 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -11,8 +11,7 @@ websocket = "1.5.1"
 protocol = "2.9.17-20230217.002312-1"
 raknet = "1.6.28-20220125.214016-6"
 mcauthlib = "d9d773e"
-mcprotocollib = "1.19.3-20230107.194116-10"
-packetlib = "3.0.1"
+mcprotocollib = "1.19.4-SNAPSHOT"
 adventure = "4.12.0-20220629.025215-9"
 adventure-platform = "4.1.2"
 junit = "5.9.2"
@@ -84,7 +83,6 @@ gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }
 junit = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" }
 mcauthlib = { group = "com.github.GeyserMC", name = "MCAuthLib", version.ref = "mcauthlib" }
 mcprotocollib = { group = "com.github.steveice10", name = "mcprotocollib", version.ref = "mcprotocollib" }
-packetlib = { group = "com.github.steveice10", name = "packetlib", version.ref = "packetlib" }
 protocol = { group = "com.nukkitx.protocol", name = "bedrock-v567", version.ref = "protocol" }
 raknet = { group = "com.nukkitx.network", name = "raknet", version.ref = "raknet" }
 sponge-api = { group = "org.spongepowered", name = "spongeapi", version.ref = "sponge" }

From 777c69a21e629822a6317b91a9d39bfc992346bc Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Sun, 12 Mar 2023 13:06:13 -0400
Subject: [PATCH 24/59] Remove armor quick change config

This is now in vanilla 1.19.4.
---
 .../configuration/GeyserConfiguration.java    |  2 -
 .../GeyserJacksonConfiguration.java           |  3 --
 ...BedrockInventoryTransactionTranslator.java | 37 -------------------
 core/src/main/resources/config.yml            |  4 --
 core/src/main/resources/languages             |  2 +-
 core/src/main/resources/mappings              |  2 +-
 6 files changed, 2 insertions(+), 48 deletions(-)

diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java
index 4843df72b..ea4c31876 100644
--- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java
+++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java
@@ -83,8 +83,6 @@ public interface GeyserConfiguration {
 
     boolean isDisableBedrockScaffolding();
 
-    boolean isAlwaysQuickChangeArmor();
-
     EmoteOffhandWorkaroundOption getEmoteOffhandWorkaround();
 
     String getDefaultLocale();
diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java
index dc675319b..bbfa37ec2 100644
--- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java
+++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java
@@ -111,9 +111,6 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
     @JsonProperty("disable-bedrock-scaffolding")
     private boolean disableBedrockScaffolding = false;
 
-    @JsonProperty("always-quick-change-armor")
-    private boolean alwaysQuickChangeArmor = false;
-
     @JsonDeserialize(using = EmoteOffhandWorkaroundOption.Deserializer.class)
     @JsonProperty("emote-offhand-workaround")
     private EmoteOffhandWorkaroundOption emoteOffhandWorkaround = EmoteOffhandWorkaroundOption.DISABLED;
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java
index 6992dada4..c770b070f 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java
@@ -356,43 +356,6 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
 
                         ServerboundUseItemPacket useItemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getWorldCache().nextPredictionSequence());
                         session.sendDownstreamPacket(useItemPacket);
-
-                        List<LegacySetItemSlotData> legacySlots = packet.getLegacySlots();
-                        if (packet.getActions().size() == 1 && legacySlots.size() > 0) {
-                            InventoryActionData actionData = packet.getActions().get(0);
-                            LegacySetItemSlotData slotData = legacySlots.get(0);
-                            if (slotData.getContainerId() == 6 && actionData.getToItem().getId() != 0) {
-                                // The player is trying to swap out an armor piece that already has an item in it
-                                if (session.getGeyser().getConfig().isAlwaysQuickChangeArmor()) {
-                                    // Java doesn't know when a player is in its own inventory and not, so we
-                                    // can abuse this feature to send a swap inventory packet
-                                    int bedrockHotbarSlot = packet.getHotbarSlot();
-                                    Click click = InventoryUtils.getClickForHotbarSwap(bedrockHotbarSlot);
-                                    if (click != null && slotData.getSlots().length != 0) {
-                                        Inventory playerInventory = session.getPlayerInventory();
-                                        // Bedrock sends us the index of the slot in the armor container; armor in Java
-                                        // Edition is offset by 5 in the player inventory
-                                        int armorSlot = slotData.getSlots()[0] + 5;
-                                        GeyserItemStack armorSlotItem = playerInventory.getItem(armorSlot);
-                                        GeyserItemStack hotbarItem = playerInventory.getItem(playerInventory.getOffsetForHotbar(bedrockHotbarSlot));
-                                        playerInventory.setItem(armorSlot, hotbarItem, session);
-                                        playerInventory.setItem(bedrockHotbarSlot, armorSlotItem, session);
-
-                                        Int2ObjectMap<ItemStack> changedSlots = new Int2ObjectOpenHashMap<>(2);
-                                        changedSlots.put(armorSlot, hotbarItem.getItemStack());
-                                        changedSlots.put(bedrockHotbarSlot, armorSlotItem.getItemStack());
-
-                                        ServerboundContainerClickPacket clickPacket = new ServerboundContainerClickPacket(
-                                                playerInventory.getJavaId(), playerInventory.getStateId(), armorSlot,
-                                                click.actionType, click.action, null, changedSlots);
-                                        session.sendDownstreamPacket(clickPacket);
-                                    }
-                                } else {
-                                    // Disallowed; let's revert
-                                    session.getInventoryTranslator().updateInventory(session, session.getPlayerInventory());
-                                }
-                            }
-                        }
                     }
                     case 2 -> {
                         int blockState = session.getGameMode() == GameMode.CREATIVE ?
diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml
index eb5b7e73c..421ad4c1c 100644
--- a/core/src/main/resources/config.yml
+++ b/core/src/main/resources/config.yml
@@ -130,10 +130,6 @@ show-coordinates: true
 # Whether Bedrock players are blocked from performing their scaffolding-style bridging.
 disable-bedrock-scaffolding: false
 
-# Whether Bedrock players can right-click outside of their inventory to replace armor in their inventory, even if the
-# armor slot is already occupied (which Java Edition doesn't allow)
-always-quick-change-armor: false
-
 # If set, when a Bedrock player performs any emote, it will swap the offhand and mainhand items, just like the Java Edition keybind
 # There are three options this can be set to:
 # disabled - the default/fallback, which doesn't apply this workaround
diff --git a/core/src/main/resources/languages b/core/src/main/resources/languages
index 24be9ef7f..f6685c4cc 160000
--- a/core/src/main/resources/languages
+++ b/core/src/main/resources/languages
@@ -1 +1 @@
-Subproject commit 24be9ef7f850f7d180650a65792c266c709cadf5
+Subproject commit f6685c4ccc6e77b07402d45cb41213559004b7d6
diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings
index 677c5b087..eab643ddb 160000
--- a/core/src/main/resources/mappings
+++ b/core/src/main/resources/mappings
@@ -1 +1 @@
-Subproject commit 677c5b0872d2f0c99ad834c0ca49a0ae3b45fde3
+Subproject commit eab643ddbaf31c4d76531376838f8fd30633bb8e

From 2436b2b1bebfec1823f87e79b0725b02f042765b Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Sun, 12 Mar 2023 23:51:51 -0400
Subject: [PATCH 25/59] Damage will now show again.

---
 .../org/geysermc/geyser/level/DamageType.java | 29 ++++++++++
 .../geyser/session/GeyserSession.java         |  5 +-
 .../protocol/java/JavaLoginTranslator.java    | 16 ++++++
 .../entity/JavaEntityEventTranslator.java     |  9 ----
 .../spawn/JavaDamageEventTranslator.java      | 54 +++++++++++++++++++
 .../java/level/JavaBlockEventTranslator.java  |  8 +--
 6 files changed, 107 insertions(+), 14 deletions(-)
 create mode 100644 core/src/main/java/org/geysermc/geyser/level/DamageType.java
 create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaDamageEventTranslator.java

diff --git a/core/src/main/java/org/geysermc/geyser/level/DamageType.java b/core/src/main/java/org/geysermc/geyser/level/DamageType.java
new file mode 100644
index 000000000..50848da90
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/level/DamageType.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019-2023 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.level;
+
+public class DamageType {
+}
diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
index 11467253e..80e2be5cd 100644
--- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
+++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
@@ -116,6 +116,7 @@ import org.geysermc.geyser.inventory.Inventory;
 import org.geysermc.geyser.inventory.PlayerInventory;
 import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
 import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData;
+import org.geysermc.geyser.level.DamageType;
 import org.geysermc.geyser.level.JavaDimension;
 import org.geysermc.geyser.level.WorldManager;
 import org.geysermc.geyser.level.physics.CollisionManager;
@@ -345,6 +346,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
 
     private final Int2ObjectMap<TextDecoration> chatTypes = new Int2ObjectOpenHashMap<>(7);
 
+    private final Int2ObjectMap<DamageType> damageTypes = new Int2ObjectOpenHashMap<>();
+
     @Setter
     private int breakingBlock;
 
@@ -1012,7 +1015,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
                     // Server is offline, probably
                     disconnectMessage = GeyserLocale.getPlayerLocaleString("geyser.network.remote.server_offline", locale());
                 } else {
-                    disconnectMessage = MessageTranslator.convertMessageLenient(event.getReason());
+                    disconnectMessage = MessageTranslator.convertMessage(event.getReason());
                 }
 
                 if (downstream instanceof LocalSession) {
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java
index 09d117087..c88c9aae2 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java
@@ -27,6 +27,7 @@ package org.geysermc.geyser.translator.protocol.java;
 
 import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundLoginPacket;
 import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCustomPayloadPacket;
+import com.github.steveice10.opennbt.SNBTIO;
 import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
 import com.github.steveice10.opennbt.tag.builtin.IntTag;
 import com.nukkitx.protocol.bedrock.data.GameRuleData;
@@ -38,6 +39,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
 import org.geysermc.floodgate.pluginmessage.PluginMessageChannels;
 import org.geysermc.geyser.api.network.AuthType;
 import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
+import org.geysermc.geyser.level.DamageType;
 import org.geysermc.geyser.level.JavaDimension;
 import org.geysermc.geyser.session.GeyserSession;
 import org.geysermc.geyser.text.TextDecoration;
@@ -49,6 +51,7 @@ import org.geysermc.geyser.util.DimensionUtils;
 import org.geysermc.geyser.util.JavaCodecUtil;
 import org.geysermc.geyser.util.PluginMessageUtils;
 
+import java.io.IOException;
 import java.util.Map;
 
 @Translator(packet = ClientboundLoginPacket.class)
@@ -64,6 +67,12 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
 
         JavaDimension.load(packet.getRegistry(), dimensions);
 
+        try {
+            SNBTIO.writeTag(System.out, packet.getRegistry().get("minecraft:damage_type"), true);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
         Int2ObjectMap<TextDecoration> chatTypes = session.getChatTypes();
         chatTypes.clear();
         for (CompoundTag tag : JavaCodecUtil.iterateAsTag(packet.getRegistry().get("minecraft:chat_type"))) {
@@ -78,6 +87,13 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
             chatTypes.put(id, textDecoration);
         }
 
+        Int2ObjectMap<DamageType> damageTypes = session.getDamageTypes();
+        damageTypes.clear();
+        for (CompoundTag tag : JavaCodecUtil.iterateAsTag(packet.getRegistry().get("minecraft:damage_type"))) {
+            int id = ((IntTag) tag.get("id")).getValue();
+            CompoundTag element = tag.get("element");
+        }
+
         // If the player is already initialized and a join game packet is sent, they
         // are swapping servers
         if (session.isSpawned()) {
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java
index 3d44ce2fd..8b492027b 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java
@@ -83,15 +83,6 @@ public class JavaEntityEventTranslator extends PacketTranslator<ClientboundEntit
                 session.sendAdventureSettings();
                 return;
 
-            // EntityEventType.HURT sends extra data depending on the type of damage. However this appears to have no visual changes
-            case LIVING_BURN:
-            case LIVING_DROWN:
-            case LIVING_HURT:
-            case LIVING_HURT_SWEET_BERRY_BUSH:
-            case LIVING_HURT_THORNS:
-            case LIVING_FREEZE:
-                entityEventPacket.setType(EntityEventType.HURT);
-                break;
             case LIVING_DEATH:
                 entityEventPacket.setType(EntityEventType.DEATH);
                 if (entity.getDefinition() == EntityDefinitions.EGG) {
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaDamageEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaDamageEventTranslator.java
new file mode 100644
index 000000000..52cda8517
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaDamageEventTranslator.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2019-2023 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.entity.spawn;
+
+import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundDamageEventPacket;
+import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
+import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
+import org.geysermc.geyser.entity.type.Entity;
+import org.geysermc.geyser.level.DamageType;
+import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.translator.protocol.PacketTranslator;
+import org.geysermc.geyser.translator.protocol.Translator;
+
+@Translator(packet = ClientboundDamageEventPacket.class)
+public class JavaDamageEventTranslator extends PacketTranslator<ClientboundDamageEventPacket> {
+
+    @Override
+    public void translate(GeyserSession session, ClientboundDamageEventPacket packet) {
+        Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
+        if (entity == null) {
+            return;
+        }
+
+        EntityEventPacket entityEventPacket = new EntityEventPacket();
+        entityEventPacket.setRuntimeEntityId(entity.getGeyserId());
+        entityEventPacket.setType(EntityEventType.HURT);
+        DamageType damageType = session.getDamageTypes().get(packet.getSourceTypeId());
+
+        session.sendUpstreamPacket(entityEventPacket);
+    }
+}
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java
index 4d35db562..149e8356e 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java
@@ -57,10 +57,10 @@ public class JavaBlockEventTranslator extends PacketTranslator<ClientboundBlockE
         } else if (packet.getValue() instanceof EndGatewayValue) {
             blockEventPacket.setEventType(1);
             session.sendUpstreamPacket(blockEventPacket);
-//        } else if (packet.getValue() instanceof NoteBlockValue) {
-//            int blockState = session.getGeyser().getWorldManager().getBlockAt(session, position);
-//            blockEventPacket.setEventData(BlockStateValues.getNoteblockPitch(blockState));
-//            session.sendUpstreamPacket(blockEventPacket);
+        } else if (packet.getValue() instanceof NoteBlockValue) {
+            int blockState = session.getGeyser().getWorldManager().getBlockAt(session, position);
+            blockEventPacket.setEventData(BlockStateValues.getNoteblockPitch(blockState));
+            session.sendUpstreamPacket(blockEventPacket);
         } else if (packet.getValue() instanceof PistonValue pistonValue) {
             PistonValueType action = (PistonValueType) packet.getType();
             Direction direction = Direction.fromPistonValue(pistonValue.getDirection());

From 720c90153585cb90020232c4007f4ac95677ed44 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Tue, 14 Mar 2023 07:44:52 -0400
Subject: [PATCH 26/59] Fix nameTagVisibility nullability

---
 .../geysermc/geyser/entity/EntityDefinitions.java   |  1 -
 .../java/org/geysermc/geyser/scoreboard/Team.java   | 13 ++++++++++++-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java
index 3271a962f..41a88f64f 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java
@@ -858,7 +858,6 @@ public final class EntityDefinitions {
         {
             EntityDefinition<AbstractHorseEntity> abstractHorseEntityBase = EntityDefinition.inherited(AbstractHorseEntity::new, ageableEntityBase)
                     .addTranslator(MetadataType.BYTE, AbstractHorseEntity::setHorseFlags)
-                    .addTranslator(null) // UUID of owner
                     .build();
             CAMEL = EntityDefinition.inherited(CamelEntity::new, abstractHorseEntityBase)
                     .type(EntityType.CAMEL)
diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java
index 7738f5f42..b2e9043b5 100644
--- a/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java
+++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java
@@ -33,7 +33,9 @@ import lombok.Getter;
 import lombok.Setter;
 import lombok.experimental.Accessors;
 
+import javax.annotation.Nullable;
 import java.util.HashSet;
+import java.util.Objects;
 import java.util.Set;
 
 @Getter
@@ -44,7 +46,7 @@ public final class Team {
 
     @Getter(AccessLevel.PACKAGE)
     private final Set<String> entities;
-    @Setter private NameTagVisibility nameTagVisibility;
+    @Setter @Nullable private NameTagVisibility nameTagVisibility;
     @Setter private TeamColor color;
 
     private final TeamData currentData;
@@ -187,6 +189,11 @@ public final class Team {
     }
 
     public boolean isVisibleFor(String entity) {
+        if (nameTagVisibility == null) {
+            // Null - normal behavior
+            return true;
+        }
+
         return switch (nameTagVisibility) {
             case HIDE_FOR_OTHER_TEAMS -> {
                 // Player must be in a team in order for HIDE_FOR_OTHER_TEAMS to be triggered
@@ -199,6 +206,10 @@ public final class Team {
         };
     }
 
+    public NameTagVisibility getNameTagVisibility() {
+        return Objects.requireNonNullElse(this.nameTagVisibility, NameTagVisibility.ALWAYS);
+    }
+
     @Override
     public int hashCode() {
         return id.hashCode();

From 03c076796594c32b9567a482c6aa7c4c40a00ebb Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Tue, 14 Mar 2023 15:37:57 -0400
Subject: [PATCH 27/59] Finish 1.19.4 support and add Bedrock 1.19.70 support

---
 README.md                                     |    2 +-
 .../org/geysermc/geyser/level/DamageType.java |   29 -
 .../geysermc/geyser/network/GameProtocol.java |   14 +-
 .../populator/BlockRegistryPopulator.java     |   10 +
 .../populator/ItemRegistryPopulator.java      |    6 +
 .../geyser/session/GeyserSession.java         |    3 -
 ...BedrockInventoryTransactionTranslator.java |   13 +-
 .../protocol/java/JavaLoginTranslator.java    |   16 -
 .../JavaDamageEventTranslator.java            |    6 +-
 .../bedrock/block_palette.1_19_70.nbt         |  Bin 0 -> 75552 bytes
 .../bedrock/creative_items.1_19_70.json       | 5452 +++++++++++++++++
 .../bedrock/runtime_item_states.1_19_70.json  | 4786 +++++++++++++++
 gradle/libs.versions.toml                     |    2 +-
 13 files changed, 10267 insertions(+), 72 deletions(-)
 delete mode 100644 core/src/main/java/org/geysermc/geyser/level/DamageType.java
 rename core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/{spawn => }/JavaDamageEventTranslator.java (92%)
 create mode 100644 core/src/main/resources/bedrock/block_palette.1_19_70.nbt
 create mode 100644 core/src/main/resources/bedrock/creative_items.1_19_70.json
 create mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_19_70.json

diff --git a/README.md b/README.md
index 2fd09eb8f..cfc99a8ba 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t
 
 Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here!
 
-### Currently supporting Minecraft Bedrock 1.19.20 - 1.19.63 and Minecraft Java 1.19.3.
+### Currently supporting Minecraft Bedrock 1.19.30 - 1.19.70 and Minecraft Java 1.19.4.
 
 ## Setting Up
 Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser.
diff --git a/core/src/main/java/org/geysermc/geyser/level/DamageType.java b/core/src/main/java/org/geysermc/geyser/level/DamageType.java
deleted file mode 100644
index 50848da90..000000000
--- a/core/src/main/java/org/geysermc/geyser/level/DamageType.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2019-2023 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.level;
-
-public class DamageType {
-}
diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
index 8a3d068f9..16f4abd04 100644
--- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
+++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
@@ -28,8 +28,6 @@ package org.geysermc.geyser.network;
 import com.github.steveice10.mc.protocol.codec.MinecraftCodec;
 import com.github.steveice10.mc.protocol.codec.PacketCodec;
 import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
-import com.nukkitx.protocol.bedrock.v544.Bedrock_v544;
-import com.nukkitx.protocol.bedrock.v545.Bedrock_v545;
 import com.nukkitx.protocol.bedrock.v554.Bedrock_v554;
 import com.nukkitx.protocol.bedrock.v557.Bedrock_v557;
 import com.nukkitx.protocol.bedrock.v560.Bedrock_v560;
@@ -49,7 +47,10 @@ public final class GameProtocol {
      * Default Bedrock codec that should act as a fallback. Should represent the latest available
      * release of the game that Geyser supports.
      */
-    public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v567.V567_CODEC;
+    public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v567patch.BEDROCK_V567PATCH.toBuilder()
+            .protocolVersion(575)
+            .minecraftVersion("1.19.70")
+            .build();
     /**
      * A list of all supported Bedrock versions that can join Geyser
      */
@@ -62,10 +63,6 @@ public final class GameProtocol {
     private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC;
 
     static {
-        SUPPORTED_BEDROCK_CODECS.add(Bedrock_v544.V544_CODEC);
-        SUPPORTED_BEDROCK_CODECS.add(Bedrock_v545.V545_CODEC.toBuilder()
-                .minecraftVersion("1.19.21/1.19.22")
-                .build());
         SUPPORTED_BEDROCK_CODECS.add(Bedrock_v554.V554_CODEC.toBuilder()
                 .minecraftVersion("1.19.30/1.19.31")
                 .build());
@@ -75,11 +72,12 @@ public final class GameProtocol {
         SUPPORTED_BEDROCK_CODECS.add(Bedrock_v560.V560_CODEC.toBuilder()
                 .minecraftVersion("1.19.50/1.19.51")
                 .build());
-        SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC);
+        SUPPORTED_BEDROCK_CODECS.add(Bedrock_v567.V567_CODEC);
         SUPPORTED_BEDROCK_CODECS.add(Bedrock_v567patch.BEDROCK_V567PATCH.toBuilder()
                 .protocolVersion(568)
                 .minecraftVersion("1.19.62")
                 .build());
+        SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC);
     }
 
     /**
diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java
index bac15377d..b931750e1 100644
--- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java
+++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java
@@ -77,6 +77,16 @@ public final class BlockRegistryPopulator {
                 .put(ObjectIntPair.of("1_19_20", Bedrock_v544.V544_CODEC.getProtocolVersion()), emptyMapper)
                 .put(ObjectIntPair.of("1_19_50", Bedrock_v560.V560_CODEC.getProtocolVersion()), emptyMapper)
                 .put(ObjectIntPair.of("1_19_60", Bedrock_v567.V567_CODEC.getProtocolVersion()), emptyMapper)
+                .put(ObjectIntPair.of("1_19_70", 575), (bedrockIdentifier, statesBuilder) -> {
+                    if (bedrockIdentifier.equals("minecraft:wool")) {
+                        String color = (String) statesBuilder.remove("color");
+                        if ("silver".equals(color)) {
+                            color = "light_gray";
+                        }
+                        return "minecraft:" + color + "_wool";
+                    }
+                    return null;
+                })
                 .build();
 
         for (Map.Entry<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>> palette : blockMappers.entrySet()) {
diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java
index 2d35c0f1d..9b4ae99a2 100644
--- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java
+++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java
@@ -76,6 +76,7 @@ public class ItemRegistryPopulator {
         paletteVersions.put("1_19_20", new PaletteVersion(Bedrock_v544.V544_CODEC.getProtocolVersion(), Collections.emptyMap()));
         paletteVersions.put("1_19_50", new PaletteVersion(Bedrock_v560.V560_CODEC.getProtocolVersion(), Collections.emptyMap()));
         paletteVersions.put("1_19_60", new PaletteVersion(Bedrock_v567.V567_CODEC.getProtocolVersion(), Collections.emptyMap()));
+        paletteVersions.put("1_19_70", new PaletteVersion(575, Collections.emptyMap()));
 
         GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap();
 
@@ -305,6 +306,11 @@ public class ItemRegistryPopulator {
                     mappingItem = entry.getValue();
                 }
 
+                // 1.19.70+
+                if (palette.getValue().protocolVersion() >= 575 && mappingItem.getBedrockIdentifier().equals("minecraft:wool")) {
+                    mappingItem.setBedrockIdentifier(javaIdentifier);
+                }
+
                 if (customItemsAllowed && javaIdentifier.equals("minecraft:furnace_minecart")) {
                     javaFurnaceMinecartId = itemIndex;
                     itemIndex++;
diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
index 80e2be5cd..9b7d334fc 100644
--- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
+++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
@@ -116,7 +116,6 @@ import org.geysermc.geyser.inventory.Inventory;
 import org.geysermc.geyser.inventory.PlayerInventory;
 import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
 import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData;
-import org.geysermc.geyser.level.DamageType;
 import org.geysermc.geyser.level.JavaDimension;
 import org.geysermc.geyser.level.WorldManager;
 import org.geysermc.geyser.level.physics.CollisionManager;
@@ -346,8 +345,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
 
     private final Int2ObjectMap<TextDecoration> chatTypes = new Int2ObjectOpenHashMap<>(7);
 
-    private final Int2ObjectMap<DamageType> damageTypes = new Int2ObjectOpenHashMap<>();
-
     @Setter
     private int breakingBlock;
 
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java
index c770b070f..9e348e704 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java
@@ -32,12 +32,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
 import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction;
 import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
 import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket;
-import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket;
-import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket;
-import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
-import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket;
-import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemOnPacket;
-import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket;
+import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.*;
 import com.nukkitx.math.vector.Vector3d;
 import com.nukkitx.math.vector.Vector3f;
 import com.nukkitx.math.vector.Vector3i;
@@ -46,14 +41,12 @@ import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
 import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData;
 import com.nukkitx.protocol.bedrock.data.inventory.InventorySource;
 import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
-import com.nukkitx.protocol.bedrock.data.inventory.LegacySetItemSlotData;
 import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
 import com.nukkitx.protocol.bedrock.packet.InventoryTransactionPacket;
 import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
 import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
 import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
 import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
-import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
 import org.geysermc.geyser.entity.EntityDefinitions;
 import org.geysermc.geyser.entity.type.Entity;
 import org.geysermc.geyser.entity.type.ItemFrameEntity;
@@ -75,9 +68,7 @@ import org.geysermc.geyser.util.BlockUtils;
 import org.geysermc.geyser.util.CooldownUtils;
 import org.geysermc.geyser.util.EntityUtils;
 import org.geysermc.geyser.util.InteractionResult;
-import org.geysermc.geyser.util.InventoryUtils;
 
-import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -494,6 +485,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
      * @param blockPos the block position to restore
      */
     private void restoreCorrectBlock(GeyserSession session, Vector3i blockPos, InventoryTransactionPacket packet) {
+        Thread.dumpStack();
         int javaBlockState = session.getGeyser().getWorldManager().getBlockAt(session, blockPos);
         UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
         updateBlockPacket.setDataLayer(0);
@@ -517,6 +509,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
         int javaSlot = session.getPlayerInventory().getOffsetForHotbar(packet.getHotbarSlot());
         int expectedItemId = ItemTranslator.getBedrockItemId(session, session.getPlayerInventory().getItem(javaSlot));
         int heldItemId = packet.getItemInHand() == null ? ItemData.AIR.getId() : packet.getItemInHand().getId();
+        System.out.println(expectedItemId + " " + heldItemId);
 
         if (expectedItemId != heldItemId) {
             session.getGeyser().getLogger().debug(session.bedrockUsername() + "'s held item has desynced! Expected: " + expectedItemId + " Received: " + heldItemId);
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java
index c88c9aae2..09d117087 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java
@@ -27,7 +27,6 @@ package org.geysermc.geyser.translator.protocol.java;
 
 import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundLoginPacket;
 import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCustomPayloadPacket;
-import com.github.steveice10.opennbt.SNBTIO;
 import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
 import com.github.steveice10.opennbt.tag.builtin.IntTag;
 import com.nukkitx.protocol.bedrock.data.GameRuleData;
@@ -39,7 +38,6 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
 import org.geysermc.floodgate.pluginmessage.PluginMessageChannels;
 import org.geysermc.geyser.api.network.AuthType;
 import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
-import org.geysermc.geyser.level.DamageType;
 import org.geysermc.geyser.level.JavaDimension;
 import org.geysermc.geyser.session.GeyserSession;
 import org.geysermc.geyser.text.TextDecoration;
@@ -51,7 +49,6 @@ import org.geysermc.geyser.util.DimensionUtils;
 import org.geysermc.geyser.util.JavaCodecUtil;
 import org.geysermc.geyser.util.PluginMessageUtils;
 
-import java.io.IOException;
 import java.util.Map;
 
 @Translator(packet = ClientboundLoginPacket.class)
@@ -67,12 +64,6 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
 
         JavaDimension.load(packet.getRegistry(), dimensions);
 
-        try {
-            SNBTIO.writeTag(System.out, packet.getRegistry().get("minecraft:damage_type"), true);
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-
         Int2ObjectMap<TextDecoration> chatTypes = session.getChatTypes();
         chatTypes.clear();
         for (CompoundTag tag : JavaCodecUtil.iterateAsTag(packet.getRegistry().get("minecraft:chat_type"))) {
@@ -87,13 +78,6 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
             chatTypes.put(id, textDecoration);
         }
 
-        Int2ObjectMap<DamageType> damageTypes = session.getDamageTypes();
-        damageTypes.clear();
-        for (CompoundTag tag : JavaCodecUtil.iterateAsTag(packet.getRegistry().get("minecraft:damage_type"))) {
-            int id = ((IntTag) tag.get("id")).getValue();
-            CompoundTag element = tag.get("element");
-        }
-
         // If the player is already initialized and a join game packet is sent, they
         // are swapping servers
         if (session.isSpawned()) {
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaDamageEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaDamageEventTranslator.java
similarity index 92%
rename from core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaDamageEventTranslator.java
rename to core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaDamageEventTranslator.java
index 52cda8517..4553ed97c 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaDamageEventTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaDamageEventTranslator.java
@@ -23,13 +23,12 @@
  * @link https://github.com/GeyserMC/Geyser
  */
 
-package org.geysermc.geyser.translator.protocol.java.entity.spawn;
+package org.geysermc.geyser.translator.protocol.java.entity;
 
 import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundDamageEventPacket;
 import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
 import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
 import org.geysermc.geyser.entity.type.Entity;
-import org.geysermc.geyser.level.DamageType;
 import org.geysermc.geyser.session.GeyserSession;
 import org.geysermc.geyser.translator.protocol.PacketTranslator;
 import org.geysermc.geyser.translator.protocol.Translator;
@@ -44,11 +43,10 @@ public class JavaDamageEventTranslator extends PacketTranslator<ClientboundDamag
             return;
         }
 
+        // We can probably actually map damage types.
         EntityEventPacket entityEventPacket = new EntityEventPacket();
         entityEventPacket.setRuntimeEntityId(entity.getGeyserId());
         entityEventPacket.setType(EntityEventType.HURT);
-        DamageType damageType = session.getDamageTypes().get(packet.getSourceTypeId());
-
         session.sendUpstreamPacket(entityEventPacket);
     }
 }
diff --git a/core/src/main/resources/bedrock/block_palette.1_19_70.nbt b/core/src/main/resources/bedrock/block_palette.1_19_70.nbt
new file mode 100644
index 0000000000000000000000000000000000000000..3e78f3929c70aaf2db29ee1eb226262c249efed5
GIT binary patch
literal 75552
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

literal 0
HcmV?d00001

diff --git a/core/src/main/resources/bedrock/creative_items.1_19_70.json b/core/src/main/resources/bedrock/creative_items.1_19_70.json
new file mode 100644
index 000000000..e47467f23
--- /dev/null
+++ b/core/src/main/resources/bedrock/creative_items.1_19_70.json
@@ -0,0 +1,5452 @@
+{
+    "items" : [
+        {
+            "id" : "minecraft:planks",
+            "blockRuntimeId" : 9885
+        },
+        {
+            "id" : "minecraft:planks",
+            "blockRuntimeId" : 9886
+        },
+        {
+            "id" : "minecraft:planks",
+            "blockRuntimeId" : 9887
+        },
+        {
+            "id" : "minecraft:planks",
+            "blockRuntimeId" : 9888
+        },
+        {
+            "id" : "minecraft:planks",
+            "blockRuntimeId" : 9889
+        },
+        {
+            "id" : "minecraft:planks",
+            "blockRuntimeId" : 9890
+        },
+        {
+            "id" : "minecraft:mangrove_planks",
+            "blockRuntimeId" : 1639
+        },
+        {
+            "id" : "minecraft:crimson_planks",
+            "blockRuntimeId" : 7466
+        },
+        {
+            "id" : "minecraft:warped_planks",
+            "blockRuntimeId" : 1612
+        },
+        {
+            "id" : "minecraft:cobblestone_wall",
+            "blockRuntimeId" : 1883
+        },
+        {
+            "id" : "minecraft:cobblestone_wall",
+            "blockRuntimeId" : 1884
+        },
+        {
+            "id" : "minecraft:cobblestone_wall",
+            "blockRuntimeId" : 1885
+        },
+        {
+            "id" : "minecraft:cobblestone_wall",
+            "blockRuntimeId" : 1886
+        },
+        {
+            "id" : "minecraft:cobblestone_wall",
+            "blockRuntimeId" : 1887
+        },
+        {
+            "id" : "minecraft:cobblestone_wall",
+            "blockRuntimeId" : 1888
+        },
+        {
+            "id" : "minecraft:cobblestone_wall",
+            "blockRuntimeId" : 1895
+        },
+        {
+            "id" : "minecraft:cobblestone_wall",
+            "blockRuntimeId" : 1890
+        },
+        {
+            "id" : "minecraft:cobblestone_wall",
+            "blockRuntimeId" : 1891
+        },
+        {
+            "id" : "minecraft:cobblestone_wall",
+            "blockRuntimeId" : 1889
+        },
+        {
+            "id" : "minecraft:cobblestone_wall",
+            "blockRuntimeId" : 1892
+        },
+        {
+            "id" : "minecraft:cobblestone_wall",
+            "blockRuntimeId" : 1896
+        },
+        {
+            "id" : "minecraft:cobblestone_wall",
+            "blockRuntimeId" : 1893
+        },
+        {
+            "id" : "minecraft:cobblestone_wall",
+            "blockRuntimeId" : 1894
+        },
+        {
+            "id" : "minecraft:blackstone_wall",
+            "blockRuntimeId" : 5774
+        },
+        {
+            "id" : "minecraft:polished_blackstone_wall",
+            "blockRuntimeId" : 10580
+        },
+        {
+            "id" : "minecraft:polished_blackstone_brick_wall",
+            "blockRuntimeId" : 1664
+        },
+        {
+            "id" : "minecraft:cobbled_deepslate_wall",
+            "blockRuntimeId" : 12346
+        },
+        {
+            "id" : "minecraft:deepslate_tile_wall",
+            "blockRuntimeId" : 7703
+        },
+        {
+            "id" : "minecraft:polished_deepslate_wall",
+            "blockRuntimeId" : 12080
+        },
+        {
+            "id" : "minecraft:deepslate_brick_wall",
+            "blockRuntimeId" : 727
+        },
+        {
+            "id" : "minecraft:mud_brick_wall",
+            "blockRuntimeId" : 1422
+        },
+        {
+            "id" : "minecraft:fence",
+            "blockRuntimeId" : 11627
+        },
+        {
+            "id" : "minecraft:fence",
+            "blockRuntimeId" : 11628
+        },
+        {
+            "id" : "minecraft:fence",
+            "blockRuntimeId" : 11629
+        },
+        {
+            "id" : "minecraft:fence",
+            "blockRuntimeId" : 11630
+        },
+        {
+            "id" : "minecraft:fence",
+            "blockRuntimeId" : 11631
+        },
+        {
+            "id" : "minecraft:fence",
+            "blockRuntimeId" : 11632
+        },
+        {
+            "id" : "minecraft:mangrove_fence",
+            "blockRuntimeId" : 10485
+        },
+        {
+            "id" : "minecraft:nether_brick_fence",
+            "blockRuntimeId" : 6138
+        },
+        {
+            "id" : "minecraft:crimson_fence",
+            "blockRuntimeId" : 12259
+        },
+        {
+            "id" : "minecraft:warped_fence",
+            "blockRuntimeId" : 8889
+        },
+        {
+            "id" : "minecraft:fence_gate",
+            "blockRuntimeId" : 79
+        },
+        {
+            "id" : "minecraft:spruce_fence_gate",
+            "blockRuntimeId" : 10436
+        },
+        {
+            "id" : "minecraft:birch_fence_gate",
+            "blockRuntimeId" : 5237
+        },
+        {
+            "id" : "minecraft:jungle_fence_gate",
+            "blockRuntimeId" : 8014
+        },
+        {
+            "id" : "minecraft:acacia_fence_gate",
+            "blockRuntimeId" : 11849
+        },
+        {
+            "id" : "minecraft:dark_oak_fence_gate",
+            "blockRuntimeId" : 6017
+        },
+        {
+            "id" : "minecraft:mangrove_fence_gate",
+            "blockRuntimeId" : 6473
+        },
+        {
+            "id" : "minecraft:crimson_fence_gate",
+            "blockRuntimeId" : 6893
+        },
+        {
+            "id" : "minecraft:warped_fence_gate",
+            "blockRuntimeId" : 8049
+        },
+        {
+            "id" : "minecraft:normal_stone_stairs",
+            "blockRuntimeId" : 932
+        },
+        {
+            "id" : "minecraft:stone_stairs",
+            "blockRuntimeId" : 5166
+        },
+        {
+            "id" : "minecraft:mossy_cobblestone_stairs",
+            "blockRuntimeId" : 5936
+        },
+        {
+            "id" : "minecraft:oak_stairs",
+            "blockRuntimeId" : 280
+        },
+        {
+            "id" : "minecraft:spruce_stairs",
+            "blockRuntimeId" : 132
+        },
+        {
+            "id" : "minecraft:birch_stairs",
+            "blockRuntimeId" : 10865
+        },
+        {
+            "id" : "minecraft:jungle_stairs",
+            "blockRuntimeId" : 10829
+        },
+        {
+            "id" : "minecraft:acacia_stairs",
+            "blockRuntimeId" : 10030
+        },
+        {
+            "id" : "minecraft:dark_oak_stairs",
+            "blockRuntimeId" : 7695
+        },
+        {
+            "id" : "minecraft:mangrove_stairs",
+            "blockRuntimeId" : 6443
+        },
+        {
+            "id" : "minecraft:stone_brick_stairs",
+            "blockRuntimeId" : 1623
+        },
+        {
+            "id" : "minecraft:mossy_stone_brick_stairs",
+            "blockRuntimeId" : 9303
+        },
+        {
+            "id" : "minecraft:sandstone_stairs",
+            "blockRuntimeId" : 5042
+        },
+        {
+            "id" : "minecraft:smooth_sandstone_stairs",
+            "blockRuntimeId" : 5085
+        },
+        {
+            "id" : "minecraft:red_sandstone_stairs",
+            "blockRuntimeId" : 7999
+        },
+        {
+            "id" : "minecraft:smooth_red_sandstone_stairs",
+            "blockRuntimeId" : 8197
+        },
+        {
+            "id" : "minecraft:granite_stairs",
+            "blockRuntimeId" : 4608
+        },
+        {
+            "id" : "minecraft:polished_granite_stairs",
+            "blockRuntimeId" : 5994
+        },
+        {
+            "id" : "minecraft:diorite_stairs",
+            "blockRuntimeId" : 6239
+        },
+        {
+            "id" : "minecraft:polished_diorite_stairs",
+            "blockRuntimeId" : 10566
+        },
+        {
+            "id" : "minecraft:andesite_stairs",
+            "blockRuntimeId" : 7956
+        },
+        {
+            "id" : "minecraft:polished_andesite_stairs",
+            "blockRuntimeId" : 10890
+        },
+        {
+            "id" : "minecraft:brick_stairs",
+            "blockRuntimeId" : 10382
+        },
+        {
+            "id" : "minecraft:nether_brick_stairs",
+            "blockRuntimeId" : 109
+        },
+        {
+            "id" : "minecraft:red_nether_brick_stairs",
+            "blockRuntimeId" : 10454
+        },
+        {
+            "id" : "minecraft:end_brick_stairs",
+            "blockRuntimeId" : 10220
+        },
+        {
+            "id" : "minecraft:quartz_stairs",
+            "blockRuntimeId" : 6999
+        },
+        {
+            "id" : "minecraft:smooth_quartz_stairs",
+            "blockRuntimeId" : 11963
+        },
+        {
+            "id" : "minecraft:purpur_stairs",
+            "blockRuntimeId" : 12018
+        },
+        {
+            "id" : "minecraft:prismarine_stairs",
+            "blockRuntimeId" : 11526
+        },
+        {
+            "id" : "minecraft:dark_prismarine_stairs",
+            "blockRuntimeId" : 11693
+        },
+        {
+            "id" : "minecraft:prismarine_bricks_stairs",
+            "blockRuntimeId" : 211
+        },
+        {
+            "id" : "minecraft:crimson_stairs",
+            "blockRuntimeId" : 10118
+        },
+        {
+            "id" : "minecraft:warped_stairs",
+            "blockRuntimeId" : 5176
+        },
+        {
+            "id" : "minecraft:blackstone_stairs",
+            "blockRuntimeId" : 10881
+        },
+        {
+            "id" : "minecraft:polished_blackstone_stairs",
+            "blockRuntimeId" : 6145
+        },
+        {
+            "id" : "minecraft:polished_blackstone_brick_stairs",
+            "blockRuntimeId" : 6325
+        },
+        {
+            "id" : "minecraft:cut_copper_stairs",
+            "blockRuntimeId" : 6452
+        },
+        {
+            "id" : "minecraft:exposed_cut_copper_stairs",
+            "blockRuntimeId" : 6435
+        },
+        {
+            "id" : "minecraft:weathered_cut_copper_stairs",
+            "blockRuntimeId" : 6153
+        },
+        {
+            "id" : "minecraft:oxidized_cut_copper_stairs",
+            "blockRuntimeId" : 648
+        },
+        {
+            "id" : "minecraft:waxed_cut_copper_stairs",
+            "blockRuntimeId" : 691
+        },
+        {
+            "id" : "minecraft:waxed_exposed_cut_copper_stairs",
+            "blockRuntimeId" : 5746
+        },
+        {
+            "id" : "minecraft:waxed_weathered_cut_copper_stairs",
+            "blockRuntimeId" : 9997
+        },
+        {
+            "id" : "minecraft:waxed_oxidized_cut_copper_stairs",
+            "blockRuntimeId" : 8876
+        },
+        {
+            "id" : "minecraft:cobbled_deepslate_stairs",
+            "blockRuntimeId" : 152
+        },
+        {
+            "id" : "minecraft:deepslate_tile_stairs",
+            "blockRuntimeId" : 6885
+        },
+        {
+            "id" : "minecraft:polished_deepslate_stairs",
+            "blockRuntimeId" : 589
+        },
+        {
+            "id" : "minecraft:deepslate_brick_stairs",
+            "blockRuntimeId" : 11685
+        },
+        {
+            "id" : "minecraft:mud_brick_stairs",
+            "blockRuntimeId" : 8173
+        },
+        {
+            "id" : "minecraft:wooden_door"
+        },
+        {
+            "id" : "minecraft:spruce_door"
+        },
+        {
+            "id" : "minecraft:birch_door"
+        },
+        {
+            "id" : "minecraft:jungle_door"
+        },
+        {
+            "id" : "minecraft:acacia_door"
+        },
+        {
+            "id" : "minecraft:dark_oak_door"
+        },
+        {
+            "id" : "minecraft:mangrove_door"
+        },
+        {
+            "id" : "minecraft:iron_door"
+        },
+        {
+            "id" : "minecraft:crimson_door"
+        },
+        {
+            "id" : "minecraft:warped_door"
+        },
+        {
+            "id" : "minecraft:trapdoor",
+            "blockRuntimeId" : 235
+        },
+        {
+            "id" : "minecraft:spruce_trapdoor",
+            "blockRuntimeId" : 10404
+        },
+        {
+            "id" : "minecraft:birch_trapdoor",
+            "blockRuntimeId" : 10502
+        },
+        {
+            "id" : "minecraft:jungle_trapdoor",
+            "blockRuntimeId" : 8030
+        },
+        {
+            "id" : "minecraft:acacia_trapdoor",
+            "blockRuntimeId" : 8240
+        },
+        {
+            "id" : "minecraft:dark_oak_trapdoor",
+            "blockRuntimeId" : 11765
+        },
+        {
+            "id" : "minecraft:mangrove_trapdoor",
+            "blockRuntimeId" : 6333
+        },
+        {
+            "id" : "minecraft:iron_trapdoor",
+            "blockRuntimeId" : 616
+        },
+        {
+            "id" : "minecraft:crimson_trapdoor",
+            "blockRuntimeId" : 6181
+        },
+        {
+            "id" : "minecraft:warped_trapdoor",
+            "blockRuntimeId" : 6965
+        },
+        {
+            "id" : "minecraft:iron_bars",
+            "blockRuntimeId" : 7033
+        },
+        {
+            "id" : "minecraft:glass",
+            "blockRuntimeId" : 9994
+        },
+        {
+            "id" : "minecraft:stained_glass",
+            "blockRuntimeId" : 1826
+        },
+        {
+            "id" : "minecraft:stained_glass",
+            "blockRuntimeId" : 1834
+        },
+        {
+            "id" : "minecraft:stained_glass",
+            "blockRuntimeId" : 1833
+        },
+        {
+            "id" : "minecraft:stained_glass",
+            "blockRuntimeId" : 1841
+        },
+        {
+            "id" : "minecraft:stained_glass",
+            "blockRuntimeId" : 1838
+        },
+        {
+            "id" : "minecraft:stained_glass",
+            "blockRuntimeId" : 1840
+        },
+        {
+            "id" : "minecraft:stained_glass",
+            "blockRuntimeId" : 1827
+        },
+        {
+            "id" : "minecraft:stained_glass",
+            "blockRuntimeId" : 1830
+        },
+        {
+            "id" : "minecraft:stained_glass",
+            "blockRuntimeId" : 1831
+        },
+        {
+            "id" : "minecraft:stained_glass",
+            "blockRuntimeId" : 1839
+        },
+        {
+            "id" : "minecraft:stained_glass",
+            "blockRuntimeId" : 1835
+        },
+        {
+            "id" : "minecraft:stained_glass",
+            "blockRuntimeId" : 1829
+        },
+        {
+            "id" : "minecraft:stained_glass",
+            "blockRuntimeId" : 1837
+        },
+        {
+            "id" : "minecraft:stained_glass",
+            "blockRuntimeId" : 1836
+        },
+        {
+            "id" : "minecraft:stained_glass",
+            "blockRuntimeId" : 1828
+        },
+        {
+            "id" : "minecraft:stained_glass",
+            "blockRuntimeId" : 1832
+        },
+        {
+            "id" : "minecraft:tinted_glass",
+            "blockRuntimeId" : 9395
+        },
+        {
+            "id" : "minecraft:glass_pane",
+            "blockRuntimeId" : 7865
+        },
+        {
+            "id" : "minecraft:stained_glass_pane",
+            "blockRuntimeId" : 7468
+        },
+        {
+            "id" : "minecraft:stained_glass_pane",
+            "blockRuntimeId" : 7476
+        },
+        {
+            "id" : "minecraft:stained_glass_pane",
+            "blockRuntimeId" : 7475
+        },
+        {
+            "id" : "minecraft:stained_glass_pane",
+            "blockRuntimeId" : 7483
+        },
+        {
+            "id" : "minecraft:stained_glass_pane",
+            "blockRuntimeId" : 7480
+        },
+        {
+            "id" : "minecraft:stained_glass_pane",
+            "blockRuntimeId" : 7482
+        },
+        {
+            "id" : "minecraft:stained_glass_pane",
+            "blockRuntimeId" : 7469
+        },
+        {
+            "id" : "minecraft:stained_glass_pane",
+            "blockRuntimeId" : 7472
+        },
+        {
+            "id" : "minecraft:stained_glass_pane",
+            "blockRuntimeId" : 7473
+        },
+        {
+            "id" : "minecraft:stained_glass_pane",
+            "blockRuntimeId" : 7481
+        },
+        {
+            "id" : "minecraft:stained_glass_pane",
+            "blockRuntimeId" : 7477
+        },
+        {
+            "id" : "minecraft:stained_glass_pane",
+            "blockRuntimeId" : 7471
+        },
+        {
+            "id" : "minecraft:stained_glass_pane",
+            "blockRuntimeId" : 7479
+        },
+        {
+            "id" : "minecraft:stained_glass_pane",
+            "blockRuntimeId" : 7478
+        },
+        {
+            "id" : "minecraft:stained_glass_pane",
+            "blockRuntimeId" : 7470
+        },
+        {
+            "id" : "minecraft:stained_glass_pane",
+            "blockRuntimeId" : 7474
+        },
+        {
+            "id" : "minecraft:ladder",
+            "blockRuntimeId" : 12528
+        },
+        {
+            "id" : "minecraft:scaffolding",
+            "blockRuntimeId" : 5026
+        },
+        {
+            "id" : "minecraft:stone_block_slab",
+            "blockRuntimeId" : 6116
+        },
+        {
+            "id" : "minecraft:stone_block_slab4",
+            "blockRuntimeId" : 8474
+        },
+        {
+            "id" : "minecraft:stone_block_slab",
+            "blockRuntimeId" : 6119
+        },
+        {
+            "id" : "minecraft:stone_block_slab2",
+            "blockRuntimeId" : 8445
+        },
+        {
+            "id" : "minecraft:wooden_slab",
+            "blockRuntimeId" : 7918
+        },
+        {
+            "id" : "minecraft:wooden_slab",
+            "blockRuntimeId" : 7919
+        },
+        {
+            "id" : "minecraft:wooden_slab",
+            "blockRuntimeId" : 7920
+        },
+        {
+            "id" : "minecraft:wooden_slab",
+            "blockRuntimeId" : 7921
+        },
+        {
+            "id" : "minecraft:wooden_slab",
+            "blockRuntimeId" : 7922
+        },
+        {
+            "id" : "minecraft:wooden_slab",
+            "blockRuntimeId" : 7923
+        },
+        {
+            "id" : "minecraft:mangrove_slab",
+            "blockRuntimeId" : 1842
+        },
+        {
+            "id" : "minecraft:stone_block_slab",
+            "blockRuntimeId" : 6121
+        },
+        {
+            "id" : "minecraft:stone_block_slab4",
+            "blockRuntimeId" : 8472
+        },
+        {
+            "id" : "minecraft:stone_block_slab",
+            "blockRuntimeId" : 6117
+        },
+        {
+            "id" : "minecraft:stone_block_slab4",
+            "blockRuntimeId" : 8475
+        },
+        {
+            "id" : "minecraft:stone_block_slab2",
+            "blockRuntimeId" : 8446
+        },
+        {
+            "id" : "minecraft:stone_block_slab2",
+            "blockRuntimeId" : 8440
+        },
+        {
+            "id" : "minecraft:stone_block_slab4",
+            "blockRuntimeId" : 8476
+        },
+        {
+            "id" : "minecraft:stone_block_slab3",
+            "blockRuntimeId" : 8457
+        },
+        {
+            "id" : "minecraft:stone_block_slab3",
+            "blockRuntimeId" : 8462
+        },
+        {
+            "id" : "minecraft:stone_block_slab3",
+            "blockRuntimeId" : 8463
+        },
+        {
+            "id" : "minecraft:stone_block_slab3",
+            "blockRuntimeId" : 8460
+        },
+        {
+            "id" : "minecraft:stone_block_slab3",
+            "blockRuntimeId" : 8461
+        },
+        {
+            "id" : "minecraft:stone_block_slab3",
+            "blockRuntimeId" : 8459
+        },
+        {
+            "id" : "minecraft:stone_block_slab3",
+            "blockRuntimeId" : 8458
+        },
+        {
+            "id" : "minecraft:stone_block_slab",
+            "blockRuntimeId" : 6120
+        },
+        {
+            "id" : "minecraft:stone_block_slab",
+            "blockRuntimeId" : 6123
+        },
+        {
+            "id" : "minecraft:stone_block_slab2",
+            "blockRuntimeId" : 8447
+        },
+        {
+            "id" : "minecraft:stone_block_slab3",
+            "blockRuntimeId" : 8456
+        },
+        {
+            "id" : "minecraft:stone_block_slab",
+            "blockRuntimeId" : 6122
+        },
+        {
+            "id" : "minecraft:stone_block_slab4",
+            "blockRuntimeId" : 8473
+        },
+        {
+            "id" : "minecraft:stone_block_slab2",
+            "blockRuntimeId" : 8441
+        },
+        {
+            "id" : "minecraft:stone_block_slab2",
+            "blockRuntimeId" : 8442
+        },
+        {
+            "id" : "minecraft:stone_block_slab2",
+            "blockRuntimeId" : 8443
+        },
+        {
+            "id" : "minecraft:stone_block_slab2",
+            "blockRuntimeId" : 8444
+        },
+        {
+            "id" : "minecraft:crimson_slab",
+            "blockRuntimeId" : 9320
+        },
+        {
+            "id" : "minecraft:warped_slab",
+            "blockRuntimeId" : 10334
+        },
+        {
+            "id" : "minecraft:blackstone_slab",
+            "blockRuntimeId" : 1602
+        },
+        {
+            "id" : "minecraft:polished_blackstone_slab",
+            "blockRuntimeId" : 9823
+        },
+        {
+            "id" : "minecraft:polished_blackstone_brick_slab",
+            "blockRuntimeId" : 6038
+        },
+        {
+            "id" : "minecraft:cut_copper_slab",
+            "blockRuntimeId" : 7867
+        },
+        {
+            "id" : "minecraft:exposed_cut_copper_slab",
+            "blockRuntimeId" : 10452
+        },
+        {
+            "id" : "minecraft:weathered_cut_copper_slab",
+            "blockRuntimeId" : 9866
+        },
+        {
+            "id" : "minecraft:oxidized_cut_copper_slab",
+            "blockRuntimeId" : 7930
+        },
+        {
+            "id" : "minecraft:waxed_cut_copper_slab",
+            "blockRuntimeId" : 12078
+        },
+        {
+            "id" : "minecraft:waxed_exposed_cut_copper_slab",
+            "blockRuntimeId" : 255
+        },
+        {
+            "id" : "minecraft:waxed_weathered_cut_copper_slab",
+            "blockRuntimeId" : 10397
+        },
+        {
+            "id" : "minecraft:waxed_oxidized_cut_copper_slab",
+            "blockRuntimeId" : 1392
+        },
+        {
+            "id" : "minecraft:cobbled_deepslate_slab",
+            "blockRuntimeId" : 11573
+        },
+        {
+            "id" : "minecraft:polished_deepslate_slab",
+            "blockRuntimeId" : 295
+        },
+        {
+            "id" : "minecraft:deepslate_tile_slab",
+            "blockRuntimeId" : 6139
+        },
+        {
+            "id" : "minecraft:deepslate_brick_slab",
+            "blockRuntimeId" : 5174
+        },
+        {
+            "id" : "minecraft:mud_brick_slab",
+            "blockRuntimeId" : 5754
+        },
+        {
+            "id" : "minecraft:brick_block",
+            "blockRuntimeId" : 6997
+        },
+        {
+            "id" : "minecraft:chiseled_nether_bricks",
+            "blockRuntimeId" : 11512
+        },
+        {
+            "id" : "minecraft:cracked_nether_bricks",
+            "blockRuntimeId" : 6400
+        },
+        {
+            "id" : "minecraft:quartz_bricks",
+            "blockRuntimeId" : 10189
+        },
+        {
+            "id" : "minecraft:stonebrick",
+            "blockRuntimeId" : 10399
+        },
+        {
+            "id" : "minecraft:stonebrick",
+            "blockRuntimeId" : 10400
+        },
+        {
+            "id" : "minecraft:stonebrick",
+            "blockRuntimeId" : 10401
+        },
+        {
+            "id" : "minecraft:stonebrick",
+            "blockRuntimeId" : 10402
+        },
+        {
+            "id" : "minecraft:end_bricks",
+            "blockRuntimeId" : 288
+        },
+        {
+            "id" : "minecraft:prismarine",
+            "blockRuntimeId" : 9917
+        },
+        {
+            "id" : "minecraft:polished_blackstone_bricks",
+            "blockRuntimeId" : 6912
+        },
+        {
+            "id" : "minecraft:cracked_polished_blackstone_bricks",
+            "blockRuntimeId" : 11461
+        },
+        {
+            "id" : "minecraft:gilded_blackstone",
+            "blockRuntimeId" : 6434
+        },
+        {
+            "id" : "minecraft:chiseled_polished_blackstone",
+            "blockRuntimeId" : 7694
+        },
+        {
+            "id" : "minecraft:deepslate_tiles",
+            "blockRuntimeId" : 6429
+        },
+        {
+            "id" : "minecraft:cracked_deepslate_tiles",
+            "blockRuntimeId" : 6004
+        },
+        {
+            "id" : "minecraft:deepslate_bricks",
+            "blockRuntimeId" : 8114
+        },
+        {
+            "id" : "minecraft:cracked_deepslate_bricks",
+            "blockRuntimeId" : 8013
+        },
+        {
+            "id" : "minecraft:chiseled_deepslate",
+            "blockRuntimeId" : 7866
+        },
+        {
+            "id" : "minecraft:cobblestone",
+            "blockRuntimeId" : 5073
+        },
+        {
+            "id" : "minecraft:mossy_cobblestone",
+            "blockRuntimeId" : 258
+        },
+        {
+            "id" : "minecraft:cobbled_deepslate",
+            "blockRuntimeId" : 10522
+        },
+        {
+            "id" : "minecraft:smooth_stone",
+            "blockRuntimeId" : 6430
+        },
+        {
+            "id" : "minecraft:sandstone",
+            "blockRuntimeId" : 5111
+        },
+        {
+            "id" : "minecraft:sandstone",
+            "blockRuntimeId" : 5112
+        },
+        {
+            "id" : "minecraft:sandstone",
+            "blockRuntimeId" : 5113
+        },
+        {
+            "id" : "minecraft:sandstone",
+            "blockRuntimeId" : 5114
+        },
+        {
+            "id" : "minecraft:red_sandstone",
+            "blockRuntimeId" : 10432
+        },
+        {
+            "id" : "minecraft:red_sandstone",
+            "blockRuntimeId" : 10433
+        },
+        {
+            "id" : "minecraft:red_sandstone",
+            "blockRuntimeId" : 10434
+        },
+        {
+            "id" : "minecraft:red_sandstone",
+            "blockRuntimeId" : 10435
+        },
+        {
+            "id" : "minecraft:coal_block",
+            "blockRuntimeId" : 8047
+        },
+        {
+            "id" : "minecraft:dried_kelp_block",
+            "blockRuntimeId" : 12242
+        },
+        {
+            "id" : "minecraft:gold_block",
+            "blockRuntimeId" : 330
+        },
+        {
+            "id" : "minecraft:iron_block",
+            "blockRuntimeId" : 12527
+        },
+        {
+            "id" : "minecraft:copper_block",
+            "blockRuntimeId" : 6883
+        },
+        {
+            "id" : "minecraft:exposed_copper",
+            "blockRuntimeId" : 891
+        },
+        {
+            "id" : "minecraft:weathered_copper",
+            "blockRuntimeId" : 12510
+        },
+        {
+            "id" : "minecraft:oxidized_copper",
+            "blockRuntimeId" : 5008
+        },
+        {
+            "id" : "minecraft:waxed_copper",
+            "blockRuntimeId" : 11997
+        },
+        {
+            "id" : "minecraft:waxed_exposed_copper",
+            "blockRuntimeId" : 1378
+        },
+        {
+            "id" : "minecraft:waxed_weathered_copper",
+            "blockRuntimeId" : 1391
+        },
+        {
+            "id" : "minecraft:waxed_oxidized_copper",
+            "blockRuntimeId" : 11805
+        },
+        {
+            "id" : "minecraft:cut_copper",
+            "blockRuntimeId" : 6921
+        },
+        {
+            "id" : "minecraft:exposed_cut_copper",
+            "blockRuntimeId" : 9996
+        },
+        {
+            "id" : "minecraft:weathered_cut_copper",
+            "blockRuntimeId" : 11444
+        },
+        {
+            "id" : "minecraft:oxidized_cut_copper",
+            "blockRuntimeId" : 8128
+        },
+        {
+            "id" : "minecraft:waxed_cut_copper",
+            "blockRuntimeId" : 11556
+        },
+        {
+            "id" : "minecraft:waxed_exposed_cut_copper",
+            "blockRuntimeId" : 5269
+        },
+        {
+            "id" : "minecraft:waxed_weathered_cut_copper",
+            "blockRuntimeId" : 7467
+        },
+        {
+            "id" : "minecraft:waxed_oxidized_cut_copper",
+            "blockRuntimeId" : 219
+        },
+        {
+            "id" : "minecraft:emerald_block",
+            "blockRuntimeId" : 1852
+        },
+        {
+            "id" : "minecraft:diamond_block",
+            "blockRuntimeId" : 279
+        },
+        {
+            "id" : "minecraft:lapis_block",
+            "blockRuntimeId" : 6132
+        },
+        {
+            "id" : "minecraft:raw_iron_block",
+            "blockRuntimeId" : 12525
+        },
+        {
+            "id" : "minecraft:raw_copper_block",
+            "blockRuntimeId" : 7917
+        },
+        {
+            "id" : "minecraft:raw_gold_block",
+            "blockRuntimeId" : 658
+        },
+        {
+            "id" : "minecraft:quartz_block",
+            "blockRuntimeId" : 5154
+        },
+        {
+            "id" : "minecraft:quartz_block",
+            "blockRuntimeId" : 5156
+        },
+        {
+            "id" : "minecraft:quartz_block",
+            "blockRuntimeId" : 5155
+        },
+        {
+            "id" : "minecraft:quartz_block",
+            "blockRuntimeId" : 5157
+        },
+        {
+            "id" : "minecraft:prismarine",
+            "blockRuntimeId" : 9915
+        },
+        {
+            "id" : "minecraft:prismarine",
+            "blockRuntimeId" : 9916
+        },
+        {
+            "id" : "minecraft:slime",
+            "blockRuntimeId" : 6079
+        },
+        {
+            "id" : "minecraft:honey_block",
+            "blockRuntimeId" : 1584
+        },
+        {
+            "id" : "minecraft:honeycomb_block",
+            "blockRuntimeId" : 6324
+        },
+        {
+            "id" : "minecraft:hay_block",
+            "blockRuntimeId" : 1379
+        },
+        {
+            "id" : "minecraft:bone_block",
+            "blockRuntimeId" : 6080
+        },
+        {
+            "id" : "minecraft:nether_brick",
+            "blockRuntimeId" : 11535
+        },
+        {
+            "id" : "minecraft:red_nether_brick",
+            "blockRuntimeId" : 151
+        },
+        {
+            "id" : "minecraft:netherite_block",
+            "blockRuntimeId" : 5234
+        },
+        {
+            "id" : "minecraft:lodestone",
+            "blockRuntimeId" : 12523
+        },
+        {
+            "id" : "minecraft:white_wool",
+            "blockRuntimeId" : 8048
+        },
+        {
+            "id" : "minecraft:light_gray_wool",
+            "blockRuntimeId" : 12318
+        },
+        {
+            "id" : "minecraft:gray_wool",
+            "blockRuntimeId" : 228
+        },
+        {
+            "id" : "minecraft:black_wool",
+            "blockRuntimeId" : 659
+        },
+        {
+            "id" : "minecraft:brown_wool",
+            "blockRuntimeId" : 262
+        },
+        {
+            "id" : "minecraft:red_wool",
+            "blockRuntimeId" : 119
+        },
+        {
+            "id" : "minecraft:orange_wool",
+            "blockRuntimeId" : 1360
+        },
+        {
+            "id" : "minecraft:yellow_wool",
+            "blockRuntimeId" : 142
+        },
+        {
+            "id" : "minecraft:lime_wool",
+            "blockRuntimeId" : 9812
+        },
+        {
+            "id" : "minecraft:green_wool",
+            "blockRuntimeId" : 5185
+        },
+        {
+            "id" : "minecraft:cyan_wool",
+            "blockRuntimeId" : 7992
+        },
+        {
+            "id" : "minecraft:light_blue_wool",
+            "blockRuntimeId" : 10944
+        },
+        {
+            "id" : "minecraft:blue_wool",
+            "blockRuntimeId" : 8129
+        },
+        {
+            "id" : "minecraft:purple_wool",
+            "blockRuntimeId" : 12526
+        },
+        {
+            "id" : "minecraft:magenta_wool",
+            "blockRuntimeId" : 1657
+        },
+        {
+            "id" : "minecraft:pink_wool",
+            "blockRuntimeId" : 5235
+        },
+        {
+            "id" : "minecraft:carpet",
+            "blockRuntimeId" : 1641
+        },
+        {
+            "id" : "minecraft:carpet",
+            "blockRuntimeId" : 1649
+        },
+        {
+            "id" : "minecraft:carpet",
+            "blockRuntimeId" : 1648
+        },
+        {
+            "id" : "minecraft:carpet",
+            "blockRuntimeId" : 1656
+        },
+        {
+            "id" : "minecraft:carpet",
+            "blockRuntimeId" : 1653
+        },
+        {
+            "id" : "minecraft:carpet",
+            "blockRuntimeId" : 1655
+        },
+        {
+            "id" : "minecraft:carpet",
+            "blockRuntimeId" : 1642
+        },
+        {
+            "id" : "minecraft:carpet",
+            "blockRuntimeId" : 1645
+        },
+        {
+            "id" : "minecraft:carpet",
+            "blockRuntimeId" : 1646
+        },
+        {
+            "id" : "minecraft:carpet",
+            "blockRuntimeId" : 1654
+        },
+        {
+            "id" : "minecraft:carpet",
+            "blockRuntimeId" : 1650
+        },
+        {
+            "id" : "minecraft:carpet",
+            "blockRuntimeId" : 1644
+        },
+        {
+            "id" : "minecraft:carpet",
+            "blockRuntimeId" : 1652
+        },
+        {
+            "id" : "minecraft:carpet",
+            "blockRuntimeId" : 1651
+        },
+        {
+            "id" : "minecraft:carpet",
+            "blockRuntimeId" : 1643
+        },
+        {
+            "id" : "minecraft:carpet",
+            "blockRuntimeId" : 1647
+        },
+        {
+            "id" : "minecraft:concrete_powder",
+            "blockRuntimeId" : 10102
+        },
+        {
+            "id" : "minecraft:concrete_powder",
+            "blockRuntimeId" : 10110
+        },
+        {
+            "id" : "minecraft:concrete_powder",
+            "blockRuntimeId" : 10109
+        },
+        {
+            "id" : "minecraft:concrete_powder",
+            "blockRuntimeId" : 10117
+        },
+        {
+            "id" : "minecraft:concrete_powder",
+            "blockRuntimeId" : 10114
+        },
+        {
+            "id" : "minecraft:concrete_powder",
+            "blockRuntimeId" : 10116
+        },
+        {
+            "id" : "minecraft:concrete_powder",
+            "blockRuntimeId" : 10103
+        },
+        {
+            "id" : "minecraft:concrete_powder",
+            "blockRuntimeId" : 10106
+        },
+        {
+            "id" : "minecraft:concrete_powder",
+            "blockRuntimeId" : 10107
+        },
+        {
+            "id" : "minecraft:concrete_powder",
+            "blockRuntimeId" : 10115
+        },
+        {
+            "id" : "minecraft:concrete_powder",
+            "blockRuntimeId" : 10111
+        },
+        {
+            "id" : "minecraft:concrete_powder",
+            "blockRuntimeId" : 10105
+        },
+        {
+            "id" : "minecraft:concrete_powder",
+            "blockRuntimeId" : 10113
+        },
+        {
+            "id" : "minecraft:concrete_powder",
+            "blockRuntimeId" : 10112
+        },
+        {
+            "id" : "minecraft:concrete_powder",
+            "blockRuntimeId" : 10104
+        },
+        {
+            "id" : "minecraft:concrete_powder",
+            "blockRuntimeId" : 10108
+        },
+        {
+            "id" : "minecraft:concrete",
+            "blockRuntimeId" : 1343
+        },
+        {
+            "id" : "minecraft:concrete",
+            "blockRuntimeId" : 1351
+        },
+        {
+            "id" : "minecraft:concrete",
+            "blockRuntimeId" : 1350
+        },
+        {
+            "id" : "minecraft:concrete",
+            "blockRuntimeId" : 1358
+        },
+        {
+            "id" : "minecraft:concrete",
+            "blockRuntimeId" : 1355
+        },
+        {
+            "id" : "minecraft:concrete",
+            "blockRuntimeId" : 1357
+        },
+        {
+            "id" : "minecraft:concrete",
+            "blockRuntimeId" : 1344
+        },
+        {
+            "id" : "minecraft:concrete",
+            "blockRuntimeId" : 1347
+        },
+        {
+            "id" : "minecraft:concrete",
+            "blockRuntimeId" : 1348
+        },
+        {
+            "id" : "minecraft:concrete",
+            "blockRuntimeId" : 1356
+        },
+        {
+            "id" : "minecraft:concrete",
+            "blockRuntimeId" : 1352
+        },
+        {
+            "id" : "minecraft:concrete",
+            "blockRuntimeId" : 1346
+        },
+        {
+            "id" : "minecraft:concrete",
+            "blockRuntimeId" : 1354
+        },
+        {
+            "id" : "minecraft:concrete",
+            "blockRuntimeId" : 1353
+        },
+        {
+            "id" : "minecraft:concrete",
+            "blockRuntimeId" : 1345
+        },
+        {
+            "id" : "minecraft:concrete",
+            "blockRuntimeId" : 1349
+        },
+        {
+            "id" : "minecraft:clay",
+            "blockRuntimeId" : 10987
+        },
+        {
+            "id" : "minecraft:hardened_clay",
+            "blockRuntimeId" : 940
+        },
+        {
+            "id" : "minecraft:stained_hardened_clay",
+            "blockRuntimeId" : 10006
+        },
+        {
+            "id" : "minecraft:stained_hardened_clay",
+            "blockRuntimeId" : 10014
+        },
+        {
+            "id" : "minecraft:stained_hardened_clay",
+            "blockRuntimeId" : 10013
+        },
+        {
+            "id" : "minecraft:stained_hardened_clay",
+            "blockRuntimeId" : 10021
+        },
+        {
+            "id" : "minecraft:stained_hardened_clay",
+            "blockRuntimeId" : 10018
+        },
+        {
+            "id" : "minecraft:stained_hardened_clay",
+            "blockRuntimeId" : 10020
+        },
+        {
+            "id" : "minecraft:stained_hardened_clay",
+            "blockRuntimeId" : 10007
+        },
+        {
+            "id" : "minecraft:stained_hardened_clay",
+            "blockRuntimeId" : 10010
+        },
+        {
+            "id" : "minecraft:stained_hardened_clay",
+            "blockRuntimeId" : 10011
+        },
+        {
+            "id" : "minecraft:stained_hardened_clay",
+            "blockRuntimeId" : 10019
+        },
+        {
+            "id" : "minecraft:stained_hardened_clay",
+            "blockRuntimeId" : 10015
+        },
+        {
+            "id" : "minecraft:stained_hardened_clay",
+            "blockRuntimeId" : 10009
+        },
+        {
+            "id" : "minecraft:stained_hardened_clay",
+            "blockRuntimeId" : 10017
+        },
+        {
+            "id" : "minecraft:stained_hardened_clay",
+            "blockRuntimeId" : 10016
+        },
+        {
+            "id" : "minecraft:stained_hardened_clay",
+            "blockRuntimeId" : 10008
+        },
+        {
+            "id" : "minecraft:stained_hardened_clay",
+            "blockRuntimeId" : 10012
+        },
+        {
+            "id" : "minecraft:white_glazed_terracotta",
+            "blockRuntimeId" : 8224
+        },
+        {
+            "id" : "minecraft:silver_glazed_terracotta",
+            "blockRuntimeId" : 4602
+        },
+        {
+            "id" : "minecraft:gray_glazed_terracotta",
+            "blockRuntimeId" : 12517
+        },
+        {
+            "id" : "minecraft:black_glazed_terracotta",
+            "blockRuntimeId" : 8870
+        },
+        {
+            "id" : "minecraft:brown_glazed_terracotta",
+            "blockRuntimeId" : 5002
+        },
+        {
+            "id" : "minecraft:red_glazed_terracotta",
+            "blockRuntimeId" : 6011
+        },
+        {
+            "id" : "minecraft:orange_glazed_terracotta",
+            "blockRuntimeId" : 1844
+        },
+        {
+            "id" : "minecraft:yellow_glazed_terracotta",
+            "blockRuntimeId" : 1605
+        },
+        {
+            "id" : "minecraft:lime_glazed_terracotta",
+            "blockRuntimeId" : 229
+        },
+        {
+            "id" : "minecraft:green_glazed_terracotta",
+            "blockRuntimeId" : 10462
+        },
+        {
+            "id" : "minecraft:cyan_glazed_terracotta",
+            "blockRuntimeId" : 8007
+        },
+        {
+            "id" : "minecraft:light_blue_glazed_terracotta",
+            "blockRuntimeId" : 8121
+        },
+        {
+            "id" : "minecraft:blue_glazed_terracotta",
+            "blockRuntimeId" : 8115
+        },
+        {
+            "id" : "minecraft:purple_glazed_terracotta",
+            "blockRuntimeId" : 10873
+        },
+        {
+            "id" : "minecraft:magenta_glazed_terracotta",
+            "blockRuntimeId" : 1658
+        },
+        {
+            "id" : "minecraft:pink_glazed_terracotta",
+            "blockRuntimeId" : 10391
+        },
+        {
+            "id" : "minecraft:purpur_block",
+            "blockRuntimeId" : 11977
+        },
+        {
+            "id" : "minecraft:purpur_block",
+            "blockRuntimeId" : 11979
+        },
+        {
+            "id" : "minecraft:packed_mud",
+            "blockRuntimeId" : 290
+        },
+        {
+            "id" : "minecraft:mud_bricks",
+            "blockRuntimeId" : 10745
+        },
+        {
+            "id" : "minecraft:nether_wart_block",
+            "blockRuntimeId" : 6141
+        },
+        {
+            "id" : "minecraft:warped_wart_block",
+            "blockRuntimeId" : 9325
+        },
+        {
+            "id" : "minecraft:shroomlight",
+            "blockRuntimeId" : 7677
+        },
+        {
+            "id" : "minecraft:crimson_nylium",
+            "blockRuntimeId" : 6035
+        },
+        {
+            "id" : "minecraft:warped_nylium",
+            "blockRuntimeId" : 10187
+        },
+        {
+            "id" : "minecraft:basalt",
+            "blockRuntimeId" : 6197
+        },
+        {
+            "id" : "minecraft:polished_basalt",
+            "blockRuntimeId" : 24
+        },
+        {
+            "id" : "minecraft:smooth_basalt",
+            "blockRuntimeId" : 1850
+        },
+        {
+            "id" : "minecraft:soul_soil",
+            "blockRuntimeId" : 8482
+        },
+        {
+            "id" : "minecraft:dirt",
+            "blockRuntimeId" : 8403
+        },
+        {
+            "id" : "minecraft:dirt",
+            "blockRuntimeId" : 8404
+        },
+        {
+            "id" : "minecraft:farmland",
+            "blockRuntimeId" : 5756
+        },
+        {
+            "id" : "minecraft:grass",
+            "blockRuntimeId" : 10837
+        },
+        {
+            "id" : "minecraft:grass_path",
+            "blockRuntimeId" : 12345
+        },
+        {
+            "id" : "minecraft:podzol",
+            "blockRuntimeId" : 6882
+        },
+        {
+            "id" : "minecraft:mycelium",
+            "blockRuntimeId" : 5141
+        },
+        {
+            "id" : "minecraft:mud",
+            "blockRuntimeId" : 10536
+        },
+        {
+            "id" : "minecraft:stone",
+            "blockRuntimeId" : 1336
+        },
+        {
+            "id" : "minecraft:iron_ore",
+            "blockRuntimeId" : 6922
+        },
+        {
+            "id" : "minecraft:gold_ore",
+            "blockRuntimeId" : 1604
+        },
+        {
+            "id" : "minecraft:diamond_ore",
+            "blockRuntimeId" : 6209
+        },
+        {
+            "id" : "minecraft:lapis_ore",
+            "blockRuntimeId" : 11962
+        },
+        {
+            "id" : "minecraft:redstone_ore",
+            "blockRuntimeId" : 6135
+        },
+        {
+            "id" : "minecraft:coal_ore",
+            "blockRuntimeId" : 6133
+        },
+        {
+            "id" : "minecraft:copper_ore",
+            "blockRuntimeId" : 5009
+        },
+        {
+            "id" : "minecraft:emerald_ore",
+            "blockRuntimeId" : 11610
+        },
+        {
+            "id" : "minecraft:quartz_ore",
+            "blockRuntimeId" : 6349
+        },
+        {
+            "id" : "minecraft:nether_gold_ore",
+            "blockRuntimeId" : 27
+        },
+        {
+            "id" : "minecraft:ancient_debris",
+            "blockRuntimeId" : 9937
+        },
+        {
+            "id" : "minecraft:deepslate_iron_ore",
+            "blockRuntimeId" : 11536
+        },
+        {
+            "id" : "minecraft:deepslate_gold_ore",
+            "blockRuntimeId" : 9936
+        },
+        {
+            "id" : "minecraft:deepslate_diamond_ore",
+            "blockRuntimeId" : 12301
+        },
+        {
+            "id" : "minecraft:deepslate_lapis_ore",
+            "blockRuntimeId" : 11525
+        },
+        {
+            "id" : "minecraft:deepslate_redstone_ore",
+            "blockRuntimeId" : 10468
+        },
+        {
+            "id" : "minecraft:deepslate_emerald_ore",
+            "blockRuntimeId" : 10188
+        },
+        {
+            "id" : "minecraft:deepslate_coal_ore",
+            "blockRuntimeId" : 11443
+        },
+        {
+            "id" : "minecraft:deepslate_copper_ore",
+            "blockRuntimeId" : 108
+        },
+        {
+            "id" : "minecraft:gravel",
+            "blockRuntimeId" : 12553
+        },
+        {
+            "id" : "minecraft:stone",
+            "blockRuntimeId" : 1337
+        },
+        {
+            "id" : "minecraft:stone",
+            "blockRuntimeId" : 1339
+        },
+        {
+            "id" : "minecraft:stone",
+            "blockRuntimeId" : 1341
+        },
+        {
+            "id" : "minecraft:blackstone",
+            "blockRuntimeId" : 11848
+        },
+        {
+            "id" : "minecraft:deepslate",
+            "blockRuntimeId" : 259
+        },
+        {
+            "id" : "minecraft:stone",
+            "blockRuntimeId" : 1338
+        },
+        {
+            "id" : "minecraft:stone",
+            "blockRuntimeId" : 1340
+        },
+        {
+            "id" : "minecraft:stone",
+            "blockRuntimeId" : 1342
+        },
+        {
+            "id" : "minecraft:polished_blackstone",
+            "blockRuntimeId" : 5140
+        },
+        {
+            "id" : "minecraft:polished_deepslate",
+            "blockRuntimeId" : 12017
+        },
+        {
+            "id" : "minecraft:sand",
+            "blockRuntimeId" : 6041
+        },
+        {
+            "id" : "minecraft:sand",
+            "blockRuntimeId" : 6042
+        },
+        {
+            "id" : "minecraft:cactus",
+            "blockRuntimeId" : 10848
+        },
+        {
+            "id" : "minecraft:log",
+            "blockRuntimeId" : 10524
+        },
+        {
+            "id" : "minecraft:stripped_oak_log",
+            "blockRuntimeId" : 11806
+        },
+        {
+            "id" : "minecraft:log",
+            "blockRuntimeId" : 10525
+        },
+        {
+            "id" : "minecraft:stripped_spruce_log",
+            "blockRuntimeId" : 10126
+        },
+        {
+            "id" : "minecraft:log",
+            "blockRuntimeId" : 10526
+        },
+        {
+            "id" : "minecraft:stripped_birch_log",
+            "blockRuntimeId" : 9392
+        },
+        {
+            "id" : "minecraft:log",
+            "blockRuntimeId" : 10527
+        },
+        {
+            "id" : "minecraft:stripped_jungle_log",
+            "blockRuntimeId" : 1325
+        },
+        {
+            "id" : "minecraft:log2",
+            "blockRuntimeId" : 5674
+        },
+        {
+            "id" : "minecraft:stripped_acacia_log",
+            "blockRuntimeId" : 8884
+        },
+        {
+            "id" : "minecraft:log2",
+            "blockRuntimeId" : 5675
+        },
+        {
+            "id" : "minecraft:stripped_dark_oak_log",
+            "blockRuntimeId" : 221
+        },
+        {
+            "id" : "minecraft:mangrove_log",
+            "blockRuntimeId" : 645
+        },
+        {
+            "id" : "minecraft:stripped_mangrove_log",
+            "blockRuntimeId" : 12550
+        },
+        {
+            "id" : "minecraft:crimson_stem",
+            "blockRuntimeId" : 9317
+        },
+        {
+            "id" : "minecraft:stripped_crimson_stem",
+            "blockRuntimeId" : 10810
+        },
+        {
+            "id" : "minecraft:warped_stem",
+            "blockRuntimeId" : 10336
+        },
+        {
+            "id" : "minecraft:stripped_warped_stem",
+            "blockRuntimeId" : 11663
+        },
+        {
+            "id" : "minecraft:wood",
+            "blockRuntimeId" : 4161
+        },
+        {
+            "id" : "minecraft:wood",
+            "blockRuntimeId" : 4167
+        },
+        {
+            "id" : "minecraft:wood",
+            "blockRuntimeId" : 4162
+        },
+        {
+            "id" : "minecraft:wood",
+            "blockRuntimeId" : 4168
+        },
+        {
+            "id" : "minecraft:wood",
+            "blockRuntimeId" : 4163
+        },
+        {
+            "id" : "minecraft:wood",
+            "blockRuntimeId" : 4169
+        },
+        {
+            "id" : "minecraft:wood",
+            "blockRuntimeId" : 4164
+        },
+        {
+            "id" : "minecraft:wood",
+            "blockRuntimeId" : 4170
+        },
+        {
+            "id" : "minecraft:wood",
+            "blockRuntimeId" : 4165
+        },
+        {
+            "id" : "minecraft:wood",
+            "blockRuntimeId" : 4171
+        },
+        {
+            "id" : "minecraft:wood",
+            "blockRuntimeId" : 4166
+        },
+        {
+            "id" : "minecraft:wood",
+            "blockRuntimeId" : 4172
+        },
+        {
+            "id" : "minecraft:mangrove_wood",
+            "blockRuntimeId" : 6005
+        },
+        {
+            "id" : "minecraft:stripped_mangrove_wood",
+            "blockRuntimeId" : 6075
+        },
+        {
+            "id" : "minecraft:crimson_hyphae",
+            "blockRuntimeId" : 6142
+        },
+        {
+            "id" : "minecraft:stripped_crimson_hyphae",
+            "blockRuntimeId" : 10349
+        },
+        {
+            "id" : "minecraft:warped_hyphae",
+            "blockRuntimeId" : 9322
+        },
+        {
+            "id" : "minecraft:stripped_warped_hyphae",
+            "blockRuntimeId" : 8230
+        },
+        {
+            "id" : "minecraft:leaves",
+            "blockRuntimeId" : 9920
+        },
+        {
+            "id" : "minecraft:leaves",
+            "blockRuntimeId" : 9921
+        },
+        {
+            "id" : "minecraft:leaves",
+            "blockRuntimeId" : 9922
+        },
+        {
+            "id" : "minecraft:leaves",
+            "blockRuntimeId" : 9923
+        },
+        {
+            "id" : "minecraft:leaves2",
+            "blockRuntimeId" : 6201
+        },
+        {
+            "id" : "minecraft:leaves2",
+            "blockRuntimeId" : 6202
+        },
+        {
+            "id" : "minecraft:mangrove_leaves",
+            "blockRuntimeId" : 10518
+        },
+        {
+            "id" : "minecraft:azalea_leaves",
+            "blockRuntimeId" : 11973
+        },
+        {
+            "id" : "minecraft:azalea_leaves_flowered",
+            "blockRuntimeId" : 10177
+        },
+        {
+            "id" : "minecraft:sapling",
+            "blockRuntimeId" : 1396
+        },
+        {
+            "id" : "minecraft:sapling",
+            "blockRuntimeId" : 1397
+        },
+        {
+            "id" : "minecraft:sapling",
+            "blockRuntimeId" : 1398
+        },
+        {
+            "id" : "minecraft:sapling",
+            "blockRuntimeId" : 1399
+        },
+        {
+            "id" : "minecraft:sapling",
+            "blockRuntimeId" : 1400
+        },
+        {
+            "id" : "minecraft:sapling",
+            "blockRuntimeId" : 1401
+        },
+        {
+            "id" : "minecraft:mangrove_propagule",
+            "blockRuntimeId" : 10838
+        },
+        {
+            "id" : "minecraft:bee_nest",
+            "blockRuntimeId" : 8406
+        },
+        {
+            "id" : "minecraft:wheat_seeds"
+        },
+        {
+            "id" : "minecraft:pumpkin_seeds"
+        },
+        {
+            "id" : "minecraft:melon_seeds"
+        },
+        {
+            "id" : "minecraft:beetroot_seeds"
+        },
+        {
+            "id" : "minecraft:wheat"
+        },
+        {
+            "id" : "minecraft:beetroot"
+        },
+        {
+            "id" : "minecraft:potato"
+        },
+        {
+            "id" : "minecraft:poisonous_potato"
+        },
+        {
+            "id" : "minecraft:carrot"
+        },
+        {
+            "id" : "minecraft:golden_carrot"
+        },
+        {
+            "id" : "minecraft:apple"
+        },
+        {
+            "id" : "minecraft:golden_apple"
+        },
+        {
+            "id" : "minecraft:enchanted_golden_apple"
+        },
+        {
+            "id" : "minecraft:melon_block",
+            "blockRuntimeId" : 690
+        },
+        {
+            "id" : "minecraft:melon_slice"
+        },
+        {
+            "id" : "minecraft:glistering_melon_slice"
+        },
+        {
+            "id" : "minecraft:sweet_berries"
+        },
+        {
+            "id" : "minecraft:glow_berries"
+        },
+        {
+            "id" : "minecraft:pumpkin",
+            "blockRuntimeId" : 6425
+        },
+        {
+            "id" : "minecraft:carved_pumpkin",
+            "blockRuntimeId" : 11641
+        },
+        {
+            "id" : "minecraft:lit_pumpkin",
+            "blockRuntimeId" : 10537
+        },
+        {
+            "id" : "minecraft:honeycomb"
+        },
+        {
+            "id" : "minecraft:tallgrass",
+            "blockRuntimeId" : 1621
+        },
+        {
+            "id" : "minecraft:double_plant",
+            "blockRuntimeId" : 8105
+        },
+        {
+            "id" : "minecraft:tallgrass",
+            "blockRuntimeId" : 1620
+        },
+        {
+            "id" : "minecraft:double_plant",
+            "blockRuntimeId" : 8104
+        },
+        {
+            "id" : "minecraft:nether_sprouts"
+        },
+        {
+            "id" : "minecraft:coral",
+            "blockRuntimeId" : 10342
+        },
+        {
+            "id" : "minecraft:coral",
+            "blockRuntimeId" : 10340
+        },
+        {
+            "id" : "minecraft:coral",
+            "blockRuntimeId" : 10341
+        },
+        {
+            "id" : "minecraft:coral",
+            "blockRuntimeId" : 10339
+        },
+        {
+            "id" : "minecraft:coral",
+            "blockRuntimeId" : 10343
+        },
+        {
+            "id" : "minecraft:coral",
+            "blockRuntimeId" : 10347
+        },
+        {
+            "id" : "minecraft:coral",
+            "blockRuntimeId" : 10345
+        },
+        {
+            "id" : "minecraft:coral",
+            "blockRuntimeId" : 10346
+        },
+        {
+            "id" : "minecraft:coral",
+            "blockRuntimeId" : 10344
+        },
+        {
+            "id" : "minecraft:coral",
+            "blockRuntimeId" : 10348
+        },
+        {
+            "id" : "minecraft:coral_fan",
+            "blockRuntimeId" : 6464
+        },
+        {
+            "id" : "minecraft:coral_fan",
+            "blockRuntimeId" : 6462
+        },
+        {
+            "id" : "minecraft:coral_fan",
+            "blockRuntimeId" : 6463
+        },
+        {
+            "id" : "minecraft:coral_fan",
+            "blockRuntimeId" : 6461
+        },
+        {
+            "id" : "minecraft:coral_fan",
+            "blockRuntimeId" : 6465
+        },
+        {
+            "id" : "minecraft:coral_fan_dead",
+            "blockRuntimeId" : 72
+        },
+        {
+            "id" : "minecraft:coral_fan_dead",
+            "blockRuntimeId" : 70
+        },
+        {
+            "id" : "minecraft:coral_fan_dead",
+            "blockRuntimeId" : 71
+        },
+        {
+            "id" : "minecraft:coral_fan_dead",
+            "blockRuntimeId" : 69
+        },
+        {
+            "id" : "minecraft:coral_fan_dead",
+            "blockRuntimeId" : 73
+        },
+        {
+            "id" : "minecraft:crimson_roots",
+            "blockRuntimeId" : 11836
+        },
+        {
+            "id" : "minecraft:warped_roots",
+            "blockRuntimeId" : 6210
+        },
+        {
+            "id" : "minecraft:yellow_flower",
+            "blockRuntimeId" : 597
+        },
+        {
+            "id" : "minecraft:red_flower",
+            "blockRuntimeId" : 5074
+        },
+        {
+            "id" : "minecraft:red_flower",
+            "blockRuntimeId" : 5075
+        },
+        {
+            "id" : "minecraft:red_flower",
+            "blockRuntimeId" : 5076
+        },
+        {
+            "id" : "minecraft:red_flower",
+            "blockRuntimeId" : 5077
+        },
+        {
+            "id" : "minecraft:red_flower",
+            "blockRuntimeId" : 5078
+        },
+        {
+            "id" : "minecraft:red_flower",
+            "blockRuntimeId" : 5079
+        },
+        {
+            "id" : "minecraft:red_flower",
+            "blockRuntimeId" : 5080
+        },
+        {
+            "id" : "minecraft:red_flower",
+            "blockRuntimeId" : 5081
+        },
+        {
+            "id" : "minecraft:red_flower",
+            "blockRuntimeId" : 5082
+        },
+        {
+            "id" : "minecraft:red_flower",
+            "blockRuntimeId" : 5083
+        },
+        {
+            "id" : "minecraft:red_flower",
+            "blockRuntimeId" : 5084
+        },
+        {
+            "id" : "minecraft:double_plant",
+            "blockRuntimeId" : 8102
+        },
+        {
+            "id" : "minecraft:double_plant",
+            "blockRuntimeId" : 8103
+        },
+        {
+            "id" : "minecraft:double_plant",
+            "blockRuntimeId" : 8106
+        },
+        {
+            "id" : "minecraft:double_plant",
+            "blockRuntimeId" : 8107
+        },
+        {
+            "id" : "minecraft:wither_rose",
+            "blockRuntimeId" : 9995
+        },
+        {
+            "id" : "minecraft:white_dye"
+        },
+        {
+            "id" : "minecraft:light_gray_dye"
+        },
+        {
+            "id" : "minecraft:gray_dye"
+        },
+        {
+            "id" : "minecraft:black_dye"
+        },
+        {
+            "id" : "minecraft:brown_dye"
+        },
+        {
+            "id" : "minecraft:red_dye"
+        },
+        {
+            "id" : "minecraft:orange_dye"
+        },
+        {
+            "id" : "minecraft:yellow_dye"
+        },
+        {
+            "id" : "minecraft:lime_dye"
+        },
+        {
+            "id" : "minecraft:green_dye"
+        },
+        {
+            "id" : "minecraft:cyan_dye"
+        },
+        {
+            "id" : "minecraft:light_blue_dye"
+        },
+        {
+            "id" : "minecraft:blue_dye"
+        },
+        {
+            "id" : "minecraft:purple_dye"
+        },
+        {
+            "id" : "minecraft:magenta_dye"
+        },
+        {
+            "id" : "minecraft:pink_dye"
+        },
+        {
+            "id" : "minecraft:ink_sac"
+        },
+        {
+            "id" : "minecraft:glow_ink_sac"
+        },
+        {
+            "id" : "minecraft:cocoa_beans"
+        },
+        {
+            "id" : "minecraft:lapis_lazuli"
+        },
+        {
+            "id" : "minecraft:bone_meal"
+        },
+        {
+            "id" : "minecraft:vine",
+            "blockRuntimeId" : 1586
+        },
+        {
+            "id" : "minecraft:weeping_vines",
+            "blockRuntimeId" : 8130
+        },
+        {
+            "id" : "minecraft:twisting_vines",
+            "blockRuntimeId" : 8343
+        },
+        {
+            "id" : "minecraft:waterlily",
+            "blockRuntimeId" : 1851
+        },
+        {
+            "id" : "minecraft:seagrass",
+            "blockRuntimeId" : 252
+        },
+        {
+            "id" : "minecraft:kelp"
+        },
+        {
+            "id" : "minecraft:deadbush",
+            "blockRuntimeId" : 6909
+        },
+        {
+            "id" : "minecraft:bamboo",
+            "blockRuntimeId" : 5142
+        },
+        {
+            "id" : "minecraft:snow",
+            "blockRuntimeId" : 6040
+        },
+        {
+            "id" : "minecraft:ice",
+            "blockRuntimeId" : 10541
+        },
+        {
+            "id" : "minecraft:packed_ice",
+            "blockRuntimeId" : 289
+        },
+        {
+            "id" : "minecraft:blue_ice",
+            "blockRuntimeId" : 10889
+        },
+        {
+            "id" : "minecraft:snow_layer",
+            "blockRuntimeId" : 160
+        },
+        {
+            "id" : "minecraft:pointed_dripstone",
+            "blockRuntimeId" : 11679
+        },
+        {
+            "id" : "minecraft:dripstone_block",
+            "blockRuntimeId" : 1585
+        },
+        {
+            "id" : "minecraft:moss_carpet",
+            "blockRuntimeId" : 293
+        },
+        {
+            "id" : "minecraft:moss_block",
+            "blockRuntimeId" : 10390
+        },
+        {
+            "id" : "minecraft:dirt_with_roots",
+            "blockRuntimeId" : 8046
+        },
+        {
+            "id" : "minecraft:hanging_roots",
+            "blockRuntimeId" : 210
+        },
+        {
+            "id" : "minecraft:mangrove_roots",
+            "blockRuntimeId" : 10005
+        },
+        {
+            "id" : "minecraft:muddy_mangrove_roots",
+            "blockRuntimeId" : 640
+        },
+        {
+            "id" : "minecraft:big_dripleaf",
+            "blockRuntimeId" : 9400
+        },
+        {
+            "id" : "minecraft:small_dripleaf_block",
+            "blockRuntimeId" : 6168
+        },
+        {
+            "id" : "minecraft:spore_blossom",
+            "blockRuntimeId" : 11575
+        },
+        {
+            "id" : "minecraft:azalea",
+            "blockRuntimeId" : 10744
+        },
+        {
+            "id" : "minecraft:flowering_azalea",
+            "blockRuntimeId" : 8127
+        },
+        {
+            "id" : "minecraft:glow_lichen",
+            "blockRuntimeId" : 8336
+        },
+        {
+            "id" : "minecraft:amethyst_block",
+            "blockRuntimeId" : 329
+        },
+        {
+            "id" : "minecraft:budding_amethyst",
+            "blockRuntimeId" : 10864
+        },
+        {
+            "id" : "minecraft:amethyst_cluster",
+            "blockRuntimeId" : 12073
+        },
+        {
+            "id" : "minecraft:large_amethyst_bud",
+            "blockRuntimeId" : 6960
+        },
+        {
+            "id" : "minecraft:medium_amethyst_bud",
+            "blockRuntimeId" : 6224
+        },
+        {
+            "id" : "minecraft:small_amethyst_bud",
+            "blockRuntimeId" : 599
+        },
+        {
+            "id" : "minecraft:tuff",
+            "blockRuntimeId" : 644
+        },
+        {
+            "id" : "minecraft:calcite",
+            "blockRuntimeId" : 220
+        },
+        {
+            "id" : "minecraft:chicken"
+        },
+        {
+            "id" : "minecraft:porkchop"
+        },
+        {
+            "id" : "minecraft:beef"
+        },
+        {
+            "id" : "minecraft:mutton"
+        },
+        {
+            "id" : "minecraft:rabbit"
+        },
+        {
+            "id" : "minecraft:cod"
+        },
+        {
+            "id" : "minecraft:salmon"
+        },
+        {
+            "id" : "minecraft:tropical_fish"
+        },
+        {
+            "id" : "minecraft:pufferfish"
+        },
+        {
+            "id" : "minecraft:brown_mushroom",
+            "blockRuntimeId" : 5001
+        },
+        {
+            "id" : "minecraft:red_mushroom",
+            "blockRuntimeId" : 6433
+        },
+        {
+            "id" : "minecraft:crimson_fungus",
+            "blockRuntimeId" : 12016
+        },
+        {
+            "id" : "minecraft:warped_fungus",
+            "blockRuntimeId" : 294
+        },
+        {
+            "id" : "minecraft:brown_mushroom_block",
+            "blockRuntimeId" : 11625
+        },
+        {
+            "id" : "minecraft:red_mushroom_block",
+            "blockRuntimeId" : 5069
+        },
+        {
+            "id" : "minecraft:brown_mushroom_block",
+            "blockRuntimeId" : 11626
+        },
+        {
+            "id" : "minecraft:brown_mushroom_block",
+            "blockRuntimeId" : 11611
+        },
+        {
+            "id" : "minecraft:egg"
+        },
+        {
+            "id" : "minecraft:sugar_cane"
+        },
+        {
+            "id" : "minecraft:sugar"
+        },
+        {
+            "id" : "minecraft:rotten_flesh"
+        },
+        {
+            "id" : "minecraft:bone"
+        },
+        {
+            "id" : "minecraft:web",
+            "blockRuntimeId" : 10565
+        },
+        {
+            "id" : "minecraft:spider_eye"
+        },
+        {
+            "id" : "minecraft:mob_spawner",
+            "blockRuntimeId" : 699
+        },
+        {
+            "id" : "minecraft:monster_egg",
+            "blockRuntimeId" : 5988
+        },
+        {
+            "id" : "minecraft:monster_egg",
+            "blockRuntimeId" : 5989
+        },
+        {
+            "id" : "minecraft:monster_egg",
+            "blockRuntimeId" : 5990
+        },
+        {
+            "id" : "minecraft:monster_egg",
+            "blockRuntimeId" : 5991
+        },
+        {
+            "id" : "minecraft:monster_egg",
+            "blockRuntimeId" : 5992
+        },
+        {
+            "id" : "minecraft:monster_egg",
+            "blockRuntimeId" : 5993
+        },
+        {
+            "id" : "minecraft:infested_deepslate",
+            "blockRuntimeId" : 6873
+        },
+        {
+            "id" : "minecraft:dragon_egg",
+            "blockRuntimeId" : 11534
+        },
+        {
+            "id" : "minecraft:turtle_egg",
+            "blockRuntimeId" : 12260
+        },
+        {
+            "id" : "minecraft:frog_spawn",
+            "blockRuntimeId" : 6247
+        },
+        {
+            "id" : "minecraft:pearlescent_froglight",
+            "blockRuntimeId" : 10273
+        },
+        {
+            "id" : "minecraft:verdant_froglight",
+            "blockRuntimeId" : 10331
+        },
+        {
+            "id" : "minecraft:ochre_froglight",
+            "blockRuntimeId" : 4581
+        },
+        {
+            "id" : "minecraft:chicken_spawn_egg"
+        },
+        {
+            "id" : "minecraft:bee_spawn_egg"
+        },
+        {
+            "id" : "minecraft:cow_spawn_egg"
+        },
+        {
+            "id" : "minecraft:pig_spawn_egg"
+        },
+        {
+            "id" : "minecraft:sheep_spawn_egg"
+        },
+        {
+            "id" : "minecraft:wolf_spawn_egg"
+        },
+        {
+            "id" : "minecraft:polar_bear_spawn_egg"
+        },
+        {
+            "id" : "minecraft:ocelot_spawn_egg"
+        },
+        {
+            "id" : "minecraft:cat_spawn_egg"
+        },
+        {
+            "id" : "minecraft:mooshroom_spawn_egg"
+        },
+        {
+            "id" : "minecraft:bat_spawn_egg"
+        },
+        {
+            "id" : "minecraft:parrot_spawn_egg"
+        },
+        {
+            "id" : "minecraft:rabbit_spawn_egg"
+        },
+        {
+            "id" : "minecraft:llama_spawn_egg"
+        },
+        {
+            "id" : "minecraft:horse_spawn_egg"
+        },
+        {
+            "id" : "minecraft:donkey_spawn_egg"
+        },
+        {
+            "id" : "minecraft:mule_spawn_egg"
+        },
+        {
+            "id" : "minecraft:skeleton_horse_spawn_egg"
+        },
+        {
+            "id" : "minecraft:zombie_horse_spawn_egg"
+        },
+        {
+            "id" : "minecraft:tropical_fish_spawn_egg"
+        },
+        {
+            "id" : "minecraft:cod_spawn_egg"
+        },
+        {
+            "id" : "minecraft:pufferfish_spawn_egg"
+        },
+        {
+            "id" : "minecraft:salmon_spawn_egg"
+        },
+        {
+            "id" : "minecraft:dolphin_spawn_egg"
+        },
+        {
+            "id" : "minecraft:turtle_spawn_egg"
+        },
+        {
+            "id" : "minecraft:panda_spawn_egg"
+        },
+        {
+            "id" : "minecraft:fox_spawn_egg"
+        },
+        {
+            "id" : "minecraft:creeper_spawn_egg"
+        },
+        {
+            "id" : "minecraft:enderman_spawn_egg"
+        },
+        {
+            "id" : "minecraft:silverfish_spawn_egg"
+        },
+        {
+            "id" : "minecraft:skeleton_spawn_egg"
+        },
+        {
+            "id" : "minecraft:wither_skeleton_spawn_egg"
+        },
+        {
+            "id" : "minecraft:stray_spawn_egg"
+        },
+        {
+            "id" : "minecraft:slime_spawn_egg"
+        },
+        {
+            "id" : "minecraft:spider_spawn_egg"
+        },
+        {
+            "id" : "minecraft:zombie_spawn_egg"
+        },
+        {
+            "id" : "minecraft:zombie_pigman_spawn_egg"
+        },
+        {
+            "id" : "minecraft:husk_spawn_egg"
+        },
+        {
+            "id" : "minecraft:drowned_spawn_egg"
+        },
+        {
+            "id" : "minecraft:squid_spawn_egg"
+        },
+        {
+            "id" : "minecraft:glow_squid_spawn_egg"
+        },
+        {
+            "id" : "minecraft:cave_spider_spawn_egg"
+        },
+        {
+            "id" : "minecraft:witch_spawn_egg"
+        },
+        {
+            "id" : "minecraft:guardian_spawn_egg"
+        },
+        {
+            "id" : "minecraft:elder_guardian_spawn_egg"
+        },
+        {
+            "id" : "minecraft:endermite_spawn_egg"
+        },
+        {
+            "id" : "minecraft:magma_cube_spawn_egg"
+        },
+        {
+            "id" : "minecraft:strider_spawn_egg"
+        },
+        {
+            "id" : "minecraft:hoglin_spawn_egg"
+        },
+        {
+            "id" : "minecraft:piglin_spawn_egg"
+        },
+        {
+            "id" : "minecraft:zoglin_spawn_egg"
+        },
+        {
+            "id" : "minecraft:piglin_brute_spawn_egg"
+        },
+        {
+            "id" : "minecraft:goat_spawn_egg"
+        },
+        {
+            "id" : "minecraft:axolotl_spawn_egg"
+        },
+        {
+            "id" : "minecraft:warden_spawn_egg"
+        },
+        {
+            "id" : "minecraft:allay_spawn_egg"
+        },
+        {
+            "id" : "minecraft:frog_spawn_egg"
+        },
+        {
+            "id" : "minecraft:tadpole_spawn_egg"
+        },
+        {
+            "id" : "minecraft:trader_llama_spawn_egg"
+        },
+        {
+            "id" : "minecraft:ghast_spawn_egg"
+        },
+        {
+            "id" : "minecraft:blaze_spawn_egg"
+        },
+        {
+            "id" : "minecraft:shulker_spawn_egg"
+        },
+        {
+            "id" : "minecraft:vindicator_spawn_egg"
+        },
+        {
+            "id" : "minecraft:evoker_spawn_egg"
+        },
+        {
+            "id" : "minecraft:vex_spawn_egg"
+        },
+        {
+            "id" : "minecraft:villager_spawn_egg"
+        },
+        {
+            "id" : "minecraft:wandering_trader_spawn_egg"
+        },
+        {
+            "id" : "minecraft:zombie_villager_spawn_egg"
+        },
+        {
+            "id" : "minecraft:phantom_spawn_egg"
+        },
+        {
+            "id" : "minecraft:pillager_spawn_egg"
+        },
+        {
+            "id" : "minecraft:ravager_spawn_egg"
+        },
+        {
+            "id" : "minecraft:iron_golem_spawn_egg"
+        },
+        {
+            "id" : "minecraft:snow_golem_spawn_egg"
+        },
+        {
+            "id" : "minecraft:obsidian",
+            "blockRuntimeId" : 726
+        },
+        {
+            "id" : "minecraft:crying_obsidian",
+            "blockRuntimeId" : 10574
+        },
+        {
+            "id" : "minecraft:bedrock",
+            "blockRuntimeId" : 10879
+        },
+        {
+            "id" : "minecraft:soul_sand",
+            "blockRuntimeId" : 8483
+        },
+        {
+            "id" : "minecraft:netherrack",
+            "blockRuntimeId" : 10899
+        },
+        {
+            "id" : "minecraft:magma",
+            "blockRuntimeId" : 12272
+        },
+        {
+            "id" : "minecraft:nether_wart"
+        },
+        {
+            "id" : "minecraft:end_stone",
+            "blockRuntimeId" : 5680
+        },
+        {
+            "id" : "minecraft:chorus_flower",
+            "blockRuntimeId" : 6378
+        },
+        {
+            "id" : "minecraft:chorus_plant",
+            "blockRuntimeId" : 8156
+        },
+        {
+            "id" : "minecraft:chorus_fruit"
+        },
+        {
+            "id" : "minecraft:popped_chorus_fruit"
+        },
+        {
+            "id" : "minecraft:sponge",
+            "blockRuntimeId" : 927
+        },
+        {
+            "id" : "minecraft:sponge",
+            "blockRuntimeId" : 928
+        },
+        {
+            "id" : "minecraft:coral_block",
+            "blockRuntimeId" : 7869
+        },
+        {
+            "id" : "minecraft:coral_block",
+            "blockRuntimeId" : 7870
+        },
+        {
+            "id" : "minecraft:coral_block",
+            "blockRuntimeId" : 7871
+        },
+        {
+            "id" : "minecraft:coral_block",
+            "blockRuntimeId" : 7872
+        },
+        {
+            "id" : "minecraft:coral_block",
+            "blockRuntimeId" : 7873
+        },
+        {
+            "id" : "minecraft:coral_block",
+            "blockRuntimeId" : 7874
+        },
+        {
+            "id" : "minecraft:coral_block",
+            "blockRuntimeId" : 7875
+        },
+        {
+            "id" : "minecraft:coral_block",
+            "blockRuntimeId" : 7876
+        },
+        {
+            "id" : "minecraft:coral_block",
+            "blockRuntimeId" : 7877
+        },
+        {
+            "id" : "minecraft:coral_block",
+            "blockRuntimeId" : 7878
+        },
+        {
+            "id" : "minecraft:sculk",
+            "blockRuntimeId" : 10898
+        },
+        {
+            "id" : "minecraft:sculk_vein",
+            "blockRuntimeId" : 11379
+        },
+        {
+            "id" : "minecraft:sculk_catalyst",
+            "blockRuntimeId" : 5071
+        },
+        {
+            "id" : "minecraft:sculk_shrieker",
+            "blockRuntimeId" : 224
+        },
+        {
+            "id" : "minecraft:sculk_sensor",
+            "blockRuntimeId" : 6237
+        },
+        {
+            "id" : "minecraft:reinforced_deepslate",
+            "blockRuntimeId" : 8868
+        },
+        {
+            "id" : "minecraft:leather_helmet"
+        },
+        {
+            "id" : "minecraft:chainmail_helmet"
+        },
+        {
+            "id" : "minecraft:iron_helmet"
+        },
+        {
+            "id" : "minecraft:golden_helmet"
+        },
+        {
+            "id" : "minecraft:diamond_helmet"
+        },
+        {
+            "id" : "minecraft:netherite_helmet"
+        },
+        {
+            "id" : "minecraft:leather_chestplate"
+        },
+        {
+            "id" : "minecraft:chainmail_chestplate"
+        },
+        {
+            "id" : "minecraft:iron_chestplate"
+        },
+        {
+            "id" : "minecraft:golden_chestplate"
+        },
+        {
+            "id" : "minecraft:diamond_chestplate"
+        },
+        {
+            "id" : "minecraft:netherite_chestplate"
+        },
+        {
+            "id" : "minecraft:leather_leggings"
+        },
+        {
+            "id" : "minecraft:chainmail_leggings"
+        },
+        {
+            "id" : "minecraft:iron_leggings"
+        },
+        {
+            "id" : "minecraft:golden_leggings"
+        },
+        {
+            "id" : "minecraft:diamond_leggings"
+        },
+        {
+            "id" : "minecraft:netherite_leggings"
+        },
+        {
+            "id" : "minecraft:leather_boots"
+        },
+        {
+            "id" : "minecraft:chainmail_boots"
+        },
+        {
+            "id" : "minecraft:iron_boots"
+        },
+        {
+            "id" : "minecraft:golden_boots"
+        },
+        {
+            "id" : "minecraft:diamond_boots"
+        },
+        {
+            "id" : "minecraft:netherite_boots"
+        },
+        {
+            "id" : "minecraft:wooden_sword"
+        },
+        {
+            "id" : "minecraft:stone_sword"
+        },
+        {
+            "id" : "minecraft:iron_sword"
+        },
+        {
+            "id" : "minecraft:golden_sword"
+        },
+        {
+            "id" : "minecraft:diamond_sword"
+        },
+        {
+            "id" : "minecraft:netherite_sword"
+        },
+        {
+            "id" : "minecraft:wooden_axe"
+        },
+        {
+            "id" : "minecraft:stone_axe"
+        },
+        {
+            "id" : "minecraft:iron_axe"
+        },
+        {
+            "id" : "minecraft:golden_axe"
+        },
+        {
+            "id" : "minecraft:diamond_axe"
+        },
+        {
+            "id" : "minecraft:netherite_axe"
+        },
+        {
+            "id" : "minecraft:wooden_pickaxe"
+        },
+        {
+            "id" : "minecraft:stone_pickaxe"
+        },
+        {
+            "id" : "minecraft:iron_pickaxe"
+        },
+        {
+            "id" : "minecraft:golden_pickaxe"
+        },
+        {
+            "id" : "minecraft:diamond_pickaxe"
+        },
+        {
+            "id" : "minecraft:netherite_pickaxe"
+        },
+        {
+            "id" : "minecraft:wooden_shovel"
+        },
+        {
+            "id" : "minecraft:stone_shovel"
+        },
+        {
+            "id" : "minecraft:iron_shovel"
+        },
+        {
+            "id" : "minecraft:golden_shovel"
+        },
+        {
+            "id" : "minecraft:diamond_shovel"
+        },
+        {
+            "id" : "minecraft:netherite_shovel"
+        },
+        {
+            "id" : "minecraft:wooden_hoe"
+        },
+        {
+            "id" : "minecraft:stone_hoe"
+        },
+        {
+            "id" : "minecraft:iron_hoe"
+        },
+        {
+            "id" : "minecraft:golden_hoe"
+        },
+        {
+            "id" : "minecraft:diamond_hoe"
+        },
+        {
+            "id" : "minecraft:netherite_hoe"
+        },
+        {
+            "id" : "minecraft:bow"
+        },
+        {
+            "id" : "minecraft:crossbow"
+        },
+        {
+            "id" : "minecraft:arrow"
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 6
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 7
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 8
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 9
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 10
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 11
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 12
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 13
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 14
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 15
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 16
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 17
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 18
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 19
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 20
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 21
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 22
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 23
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 24
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 25
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 26
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 27
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 28
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 29
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 30
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 31
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 32
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 33
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 34
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 35
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 36
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 37
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 38
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 39
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 40
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 41
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 42
+        },
+        {
+            "id" : "minecraft:arrow",
+            "damage" : 43
+        },
+        {
+            "id" : "minecraft:shield"
+        },
+        {
+            "id" : "minecraft:cooked_chicken"
+        },
+        {
+            "id" : "minecraft:cooked_porkchop"
+        },
+        {
+            "id" : "minecraft:cooked_beef"
+        },
+        {
+            "id" : "minecraft:cooked_mutton"
+        },
+        {
+            "id" : "minecraft:cooked_rabbit"
+        },
+        {
+            "id" : "minecraft:cooked_cod"
+        },
+        {
+            "id" : "minecraft:cooked_salmon"
+        },
+        {
+            "id" : "minecraft:bread"
+        },
+        {
+            "id" : "minecraft:mushroom_stew"
+        },
+        {
+            "id" : "minecraft:beetroot_soup"
+        },
+        {
+            "id" : "minecraft:rabbit_stew"
+        },
+        {
+            "id" : "minecraft:baked_potato"
+        },
+        {
+            "id" : "minecraft:cookie"
+        },
+        {
+            "id" : "minecraft:pumpkin_pie"
+        },
+        {
+            "id" : "minecraft:cake"
+        },
+        {
+            "id" : "minecraft:dried_kelp"
+        },
+        {
+            "id" : "minecraft:fishing_rod"
+        },
+        {
+            "id" : "minecraft:carrot_on_a_stick"
+        },
+        {
+            "id" : "minecraft:warped_fungus_on_a_stick"
+        },
+        {
+            "id" : "minecraft:snowball"
+        },
+        {
+            "id" : "minecraft:shears"
+        },
+        {
+            "id" : "minecraft:flint_and_steel"
+        },
+        {
+            "id" : "minecraft:lead"
+        },
+        {
+            "id" : "minecraft:clock"
+        },
+        {
+            "id" : "minecraft:compass"
+        },
+        {
+            "id" : "minecraft:recovery_compass"
+        },
+        {
+            "id" : "minecraft:goat_horn"
+        },
+        {
+            "id" : "minecraft:goat_horn",
+            "damage" : 1
+        },
+        {
+            "id" : "minecraft:goat_horn",
+            "damage" : 2
+        },
+        {
+            "id" : "minecraft:goat_horn",
+            "damage" : 3
+        },
+        {
+            "id" : "minecraft:goat_horn",
+            "damage" : 4
+        },
+        {
+            "id" : "minecraft:goat_horn",
+            "damage" : 5
+        },
+        {
+            "id" : "minecraft:goat_horn",
+            "damage" : 6
+        },
+        {
+            "id" : "minecraft:goat_horn",
+            "damage" : 7
+        },
+        {
+            "id" : "minecraft:empty_map"
+        },
+        {
+            "id" : "minecraft:empty_map",
+            "damage" : 2
+        },
+        {
+            "id" : "minecraft:saddle"
+        },
+        {
+            "id" : "minecraft:leather_horse_armor"
+        },
+        {
+            "id" : "minecraft:iron_horse_armor"
+        },
+        {
+            "id" : "minecraft:golden_horse_armor"
+        },
+        {
+            "id" : "minecraft:diamond_horse_armor"
+        },
+        {
+            "id" : "minecraft:trident"
+        },
+        {
+            "id" : "minecraft:turtle_helmet"
+        },
+        {
+            "id" : "minecraft:elytra"
+        },
+        {
+            "id" : "minecraft:totem_of_undying"
+        },
+        {
+            "id" : "minecraft:glass_bottle"
+        },
+        {
+            "id" : "minecraft:experience_bottle"
+        },
+        {
+            "id" : "minecraft:potion"
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 1
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 2
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 3
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 4
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 5
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 6
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 7
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 8
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 9
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 10
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 11
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 12
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 13
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 14
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 15
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 16
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 17
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 18
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 19
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 20
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 21
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 22
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 23
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 24
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 25
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 26
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 27
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 28
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 29
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 30
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 31
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 32
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 33
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 34
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 35
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 36
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 37
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 38
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 39
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 40
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 41
+        },
+        {
+            "id" : "minecraft:potion",
+            "damage" : 42
+        },
+        {
+            "id" : "minecraft:splash_potion"
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 1
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 2
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 3
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 4
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 5
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 6
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 7
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 8
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 9
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 10
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 11
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 12
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 13
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 14
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 15
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 16
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 17
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 18
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 19
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 20
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 21
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 22
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 23
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 24
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 25
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 26
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 27
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 28
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 29
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 30
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 31
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 32
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 33
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 34
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 35
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 36
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 37
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 38
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 39
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 40
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 41
+        },
+        {
+            "id" : "minecraft:splash_potion",
+            "damage" : 42
+        },
+        {
+            "id" : "minecraft:lingering_potion"
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 1
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 2
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 3
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 4
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 5
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 6
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 7
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 8
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 9
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 10
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 11
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 12
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 13
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 14
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 15
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 16
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 17
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 18
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 19
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 20
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 21
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 22
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 23
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 24
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 25
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 26
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 27
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 28
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 29
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 30
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 31
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 32
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 33
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 34
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 35
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 36
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 37
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 38
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 39
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 40
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 41
+        },
+        {
+            "id" : "minecraft:lingering_potion",
+            "damage" : 42
+        },
+        {
+            "id" : "minecraft:spyglass"
+        },
+        {
+            "id" : "minecraft:stick"
+        },
+        {
+            "id" : "minecraft:bed"
+        },
+        {
+            "id" : "minecraft:bed",
+            "damage" : 8
+        },
+        {
+            "id" : "minecraft:bed",
+            "damage" : 7
+        },
+        {
+            "id" : "minecraft:bed",
+            "damage" : 15
+        },
+        {
+            "id" : "minecraft:bed",
+            "damage" : 12
+        },
+        {
+            "id" : "minecraft:bed",
+            "damage" : 14
+        },
+        {
+            "id" : "minecraft:bed",
+            "damage" : 1
+        },
+        {
+            "id" : "minecraft:bed",
+            "damage" : 4
+        },
+        {
+            "id" : "minecraft:bed",
+            "damage" : 5
+        },
+        {
+            "id" : "minecraft:bed",
+            "damage" : 13
+        },
+        {
+            "id" : "minecraft:bed",
+            "damage" : 9
+        },
+        {
+            "id" : "minecraft:bed",
+            "damage" : 3
+        },
+        {
+            "id" : "minecraft:bed",
+            "damage" : 11
+        },
+        {
+            "id" : "minecraft:bed",
+            "damage" : 10
+        },
+        {
+            "id" : "minecraft:bed",
+            "damage" : 2
+        },
+        {
+            "id" : "minecraft:bed",
+            "damage" : 6
+        },
+        {
+            "id" : "minecraft:torch",
+            "blockRuntimeId" : 1416
+        },
+        {
+            "id" : "minecraft:soul_torch",
+            "blockRuntimeId" : 6876
+        },
+        {
+            "id" : "minecraft:sea_pickle",
+            "blockRuntimeId" : 8891
+        },
+        {
+            "id" : "minecraft:lantern",
+            "blockRuntimeId" : 10936
+        },
+        {
+            "id" : "minecraft:soul_lantern",
+            "blockRuntimeId" : 8401
+        },
+        {
+            "id" : "minecraft:candle",
+            "blockRuntimeId" : 11666
+        },
+        {
+            "id" : "minecraft:white_candle",
+            "blockRuntimeId" : 7948
+        },
+        {
+            "id" : "minecraft:orange_candle",
+            "blockRuntimeId" : 660
+        },
+        {
+            "id" : "minecraft:magenta_candle",
+            "blockRuntimeId" : 716
+        },
+        {
+            "id" : "minecraft:light_blue_candle",
+            "blockRuntimeId" : 6417
+        },
+        {
+            "id" : "minecraft:yellow_candle",
+            "blockRuntimeId" : 10022
+        },
+        {
+            "id" : "minecraft:lime_candle",
+            "blockRuntimeId" : 10206
+        },
+        {
+            "id" : "minecraft:pink_candle",
+            "blockRuntimeId" : 11633
+        },
+        {
+            "id" : "minecraft:gray_candle",
+            "blockRuntimeId" : 1631
+        },
+        {
+            "id" : "minecraft:light_gray_candle",
+            "blockRuntimeId" : 10062
+        },
+        {
+            "id" : "minecraft:cyan_candle",
+            "blockRuntimeId" : 11989
+        },
+        {
+            "id" : "minecraft:purple_candle",
+            "blockRuntimeId" : 10900
+        },
+        {
+            "id" : "minecraft:blue_candle"
+        },
+        {
+            "id" : "minecraft:brown_candle",
+            "blockRuntimeId" : 9295
+        },
+        {
+            "id" : "minecraft:green_candle",
+            "blockRuntimeId" : 1370
+        },
+        {
+            "id" : "minecraft:red_candle",
+            "blockRuntimeId" : 6913
+        },
+        {
+            "id" : "minecraft:black_candle",
+            "blockRuntimeId" : 176
+        },
+        {
+            "id" : "minecraft:crafting_table",
+            "blockRuntimeId" : 8890
+        },
+        {
+            "id" : "minecraft:cartography_table",
+            "blockRuntimeId" : 12554
+        },
+        {
+            "id" : "minecraft:fletching_table",
+            "blockRuntimeId" : 8869
+        },
+        {
+            "id" : "minecraft:smithing_table",
+            "blockRuntimeId" : 5184
+        },
+        {
+            "id" : "minecraft:beehive",
+            "blockRuntimeId" : 9938
+        },
+        {
+            "id" : "minecraft:campfire"
+        },
+        {
+            "id" : "minecraft:soul_campfire"
+        },
+        {
+            "id" : "minecraft:furnace",
+            "blockRuntimeId" : 12065
+        },
+        {
+            "id" : "minecraft:blast_furnace",
+            "blockRuntimeId" : 11830
+        },
+        {
+            "id" : "minecraft:smoker",
+            "blockRuntimeId" : 1330
+        },
+        {
+            "id" : "minecraft:respawn_anchor",
+            "blockRuntimeId" : 1365
+        },
+        {
+            "id" : "minecraft:brewing_stand"
+        },
+        {
+            "id" : "minecraft:anvil",
+            "blockRuntimeId" : 10486
+        },
+        {
+            "id" : "minecraft:anvil",
+            "blockRuntimeId" : 10490
+        },
+        {
+            "id" : "minecraft:anvil",
+            "blockRuntimeId" : 10494
+        },
+        {
+            "id" : "minecraft:grindstone",
+            "blockRuntimeId" : 12302
+        },
+        {
+            "id" : "minecraft:enchanting_table",
+            "blockRuntimeId" : 10579
+        },
+        {
+            "id" : "minecraft:bookshelf",
+            "blockRuntimeId" : 10523
+        },
+        {
+            "id" : "minecraft:lectern",
+            "blockRuntimeId" : 10802
+        },
+        {
+            "id" : "minecraft:cauldron"
+        },
+        {
+            "id" : "minecraft:composter",
+            "blockRuntimeId" : 8065
+        },
+        {
+            "id" : "minecraft:chest",
+            "blockRuntimeId" : 10978
+        },
+        {
+            "id" : "minecraft:trapped_chest",
+            "blockRuntimeId" : 8234
+        },
+        {
+            "id" : "minecraft:ender_chest",
+            "blockRuntimeId" : 6217
+        },
+        {
+            "id" : "minecraft:barrel",
+            "blockRuntimeId" : 6366
+        },
+        {
+            "id" : "minecraft:undyed_shulker_box",
+            "blockRuntimeId" : 5139
+        },
+        {
+            "id" : "minecraft:shulker_box",
+            "blockRuntimeId" : 7964
+        },
+        {
+            "id" : "minecraft:shulker_box",
+            "blockRuntimeId" : 7972
+        },
+        {
+            "id" : "minecraft:shulker_box",
+            "blockRuntimeId" : 7971
+        },
+        {
+            "id" : "minecraft:shulker_box",
+            "blockRuntimeId" : 7979
+        },
+        {
+            "id" : "minecraft:shulker_box",
+            "blockRuntimeId" : 7976
+        },
+        {
+            "id" : "minecraft:shulker_box",
+            "blockRuntimeId" : 7978
+        },
+        {
+            "id" : "minecraft:shulker_box",
+            "blockRuntimeId" : 7965
+        },
+        {
+            "id" : "minecraft:shulker_box",
+            "blockRuntimeId" : 7968
+        },
+        {
+            "id" : "minecraft:shulker_box",
+            "blockRuntimeId" : 7969
+        },
+        {
+            "id" : "minecraft:shulker_box",
+            "blockRuntimeId" : 7977
+        },
+        {
+            "id" : "minecraft:shulker_box",
+            "blockRuntimeId" : 7973
+        },
+        {
+            "id" : "minecraft:shulker_box",
+            "blockRuntimeId" : 7967
+        },
+        {
+            "id" : "minecraft:shulker_box",
+            "blockRuntimeId" : 7975
+        },
+        {
+            "id" : "minecraft:shulker_box",
+            "blockRuntimeId" : 7974
+        },
+        {
+            "id" : "minecraft:shulker_box",
+            "blockRuntimeId" : 7966
+        },
+        {
+            "id" : "minecraft:shulker_box",
+            "blockRuntimeId" : 7970
+        },
+        {
+            "id" : "minecraft:armor_stand"
+        },
+        {
+            "id" : "minecraft:noteblock",
+            "blockRuntimeId" : 643
+        },
+        {
+            "id" : "minecraft:jukebox",
+            "blockRuntimeId" : 7490
+        },
+        {
+            "id" : "minecraft:music_disc_13"
+        },
+        {
+            "id" : "minecraft:music_disc_cat"
+        },
+        {
+            "id" : "minecraft:music_disc_blocks"
+        },
+        {
+            "id" : "minecraft:music_disc_chirp"
+        },
+        {
+            "id" : "minecraft:music_disc_far"
+        },
+        {
+            "id" : "minecraft:music_disc_mall"
+        },
+        {
+            "id" : "minecraft:music_disc_mellohi"
+        },
+        {
+            "id" : "minecraft:music_disc_stal"
+        },
+        {
+            "id" : "minecraft:music_disc_strad"
+        },
+        {
+            "id" : "minecraft:music_disc_ward"
+        },
+        {
+            "id" : "minecraft:music_disc_11"
+        },
+        {
+            "id" : "minecraft:music_disc_wait"
+        },
+        {
+            "id" : "minecraft:music_disc_otherside"
+        },
+        {
+            "id" : "minecraft:music_disc_5"
+        },
+        {
+            "id" : "minecraft:music_disc_pigstep"
+        },
+        {
+            "id" : "minecraft:disc_fragment_5"
+        },
+        {
+            "id" : "minecraft:glowstone_dust"
+        },
+        {
+            "id" : "minecraft:glowstone",
+            "blockRuntimeId" : 5729
+        },
+        {
+            "id" : "minecraft:redstone_lamp",
+            "blockRuntimeId" : 257
+        },
+        {
+            "id" : "minecraft:sea_lantern",
+            "blockRuntimeId" : 11809
+        },
+        {
+            "id" : "minecraft:oak_sign"
+        },
+        {
+            "id" : "minecraft:spruce_sign"
+        },
+        {
+            "id" : "minecraft:birch_sign"
+        },
+        {
+            "id" : "minecraft:jungle_sign"
+        },
+        {
+            "id" : "minecraft:acacia_sign"
+        },
+        {
+            "id" : "minecraft:dark_oak_sign"
+        },
+        {
+            "id" : "minecraft:mangrove_sign"
+        },
+        {
+            "id" : "minecraft:crimson_sign"
+        },
+        {
+            "id" : "minecraft:warped_sign"
+        },
+        {
+            "id" : "minecraft:painting"
+        },
+        {
+            "id" : "minecraft:frame"
+        },
+        {
+            "id" : "minecraft:glow_frame"
+        },
+        {
+            "id" : "minecraft:honey_bottle"
+        },
+        {
+            "id" : "minecraft:flower_pot"
+        },
+        {
+            "id" : "minecraft:bowl"
+        },
+        {
+            "id" : "minecraft:bucket"
+        },
+        {
+            "id" : "minecraft:milk_bucket"
+        },
+        {
+            "id" : "minecraft:water_bucket"
+        },
+        {
+            "id" : "minecraft:lava_bucket"
+        },
+        {
+            "id" : "minecraft:cod_bucket"
+        },
+        {
+            "id" : "minecraft:salmon_bucket"
+        },
+        {
+            "id" : "minecraft:tropical_fish_bucket"
+        },
+        {
+            "id" : "minecraft:pufferfish_bucket"
+        },
+        {
+            "id" : "minecraft:powder_snow_bucket"
+        },
+        {
+            "id" : "minecraft:axolotl_bucket"
+        },
+        {
+            "id" : "minecraft:tadpole_bucket"
+        },
+        {
+            "id" : "minecraft:skull",
+            "damage" : 3
+        },
+        {
+            "id" : "minecraft:skull",
+            "damage" : 2
+        },
+        {
+            "id" : "minecraft:skull",
+            "damage" : 4
+        },
+        {
+            "id" : "minecraft:skull",
+            "damage" : 5
+        },
+        {
+            "id" : "minecraft:skull"
+        },
+        {
+            "id" : "minecraft:skull",
+            "damage" : 1
+        },
+        {
+            "id" : "minecraft:beacon",
+            "blockRuntimeId" : 150
+        },
+        {
+            "id" : "minecraft:bell",
+            "blockRuntimeId" : 10770
+        },
+        {
+            "id" : "minecraft:conduit",
+            "blockRuntimeId" : 6078
+        },
+        {
+            "id" : "minecraft:stonecutter_block",
+            "blockRuntimeId" : 11837
+        },
+        {
+            "id" : "minecraft:end_portal_frame",
+            "blockRuntimeId" : 9891
+        },
+        {
+            "id" : "minecraft:coal"
+        },
+        {
+            "id" : "minecraft:charcoal"
+        },
+        {
+            "id" : "minecraft:diamond"
+        },
+        {
+            "id" : "minecraft:iron_nugget"
+        },
+        {
+            "id" : "minecraft:raw_iron"
+        },
+        {
+            "id" : "minecraft:raw_gold"
+        },
+        {
+            "id" : "minecraft:raw_copper"
+        },
+        {
+            "id" : "minecraft:copper_ingot"
+        },
+        {
+            "id" : "minecraft:iron_ingot"
+        },
+        {
+            "id" : "minecraft:netherite_scrap"
+        },
+        {
+            "id" : "minecraft:netherite_ingot"
+        },
+        {
+            "id" : "minecraft:gold_nugget"
+        },
+        {
+            "id" : "minecraft:gold_ingot"
+        },
+        {
+            "id" : "minecraft:emerald"
+        },
+        {
+            "id" : "minecraft:quartz"
+        },
+        {
+            "id" : "minecraft:clay_ball"
+        },
+        {
+            "id" : "minecraft:brick"
+        },
+        {
+            "id" : "minecraft:netherbrick"
+        },
+        {
+            "id" : "minecraft:prismarine_shard"
+        },
+        {
+            "id" : "minecraft:amethyst_shard"
+        },
+        {
+            "id" : "minecraft:prismarine_crystals"
+        },
+        {
+            "id" : "minecraft:nautilus_shell"
+        },
+        {
+            "id" : "minecraft:heart_of_the_sea"
+        },
+        {
+            "id" : "minecraft:scute"
+        },
+        {
+            "id" : "minecraft:phantom_membrane"
+        },
+        {
+            "id" : "minecraft:string"
+        },
+        {
+            "id" : "minecraft:feather"
+        },
+        {
+            "id" : "minecraft:flint"
+        },
+        {
+            "id" : "minecraft:gunpowder"
+        },
+        {
+            "id" : "minecraft:leather"
+        },
+        {
+            "id" : "minecraft:rabbit_hide"
+        },
+        {
+            "id" : "minecraft:rabbit_foot"
+        },
+        {
+            "id" : "minecraft:fire_charge"
+        },
+        {
+            "id" : "minecraft:blaze_rod"
+        },
+        {
+            "id" : "minecraft:blaze_powder"
+        },
+        {
+            "id" : "minecraft:magma_cream"
+        },
+        {
+            "id" : "minecraft:fermented_spider_eye"
+        },
+        {
+            "id" : "minecraft:echo_shard"
+        },
+        {
+            "id" : "minecraft:dragon_breath"
+        },
+        {
+            "id" : "minecraft:shulker_shell"
+        },
+        {
+            "id" : "minecraft:ghast_tear"
+        },
+        {
+            "id" : "minecraft:slime_ball"
+        },
+        {
+            "id" : "minecraft:ender_pearl"
+        },
+        {
+            "id" : "minecraft:ender_eye"
+        },
+        {
+            "id" : "minecraft:nether_star"
+        },
+        {
+            "id" : "minecraft:end_rod",
+            "blockRuntimeId" : 9311
+        },
+        {
+            "id" : "minecraft:lightning_rod",
+            "blockRuntimeId" : 1877
+        },
+        {
+            "id" : "minecraft:end_crystal"
+        },
+        {
+            "id" : "minecraft:paper"
+        },
+        {
+            "id" : "minecraft:book"
+        },
+        {
+            "id" : "minecraft:writable_book"
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAQAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAQAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAQAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAQAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAQAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQIAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAQAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAUAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAQAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAUAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAQAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAUAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAQAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAUAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQQAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAQAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAUAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQVAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQWAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQaAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQbAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQcAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAQAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAUAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQgAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQhAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAQAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAEAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAIAAAA="
+        },
+        {
+            "id" : "minecraft:enchanted_book",
+            "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAMAAAA="
+        },
+        {
+            "id" : "minecraft:oak_boat"
+        },
+        {
+            "id" : "minecraft:spruce_boat"
+        },
+        {
+            "id" : "minecraft:birch_boat"
+        },
+        {
+            "id" : "minecraft:jungle_boat"
+        },
+        {
+            "id" : "minecraft:acacia_boat"
+        },
+        {
+            "id" : "minecraft:dark_oak_boat"
+        },
+        {
+            "id" : "minecraft:mangrove_boat"
+        },
+        {
+            "id" : "minecraft:oak_chest_boat"
+        },
+        {
+            "id" : "minecraft:spruce_chest_boat"
+        },
+        {
+            "id" : "minecraft:birch_chest_boat"
+        },
+        {
+            "id" : "minecraft:jungle_chest_boat"
+        },
+        {
+            "id" : "minecraft:acacia_chest_boat"
+        },
+        {
+            "id" : "minecraft:dark_oak_chest_boat"
+        },
+        {
+            "id" : "minecraft:mangrove_chest_boat"
+        },
+        {
+            "id" : "minecraft:rail",
+            "blockRuntimeId" : 5764
+        },
+        {
+            "id" : "minecraft:golden_rail",
+            "blockRuntimeId" : 7980
+        },
+        {
+            "id" : "minecraft:detector_rail",
+            "blockRuntimeId" : 5976
+        },
+        {
+            "id" : "minecraft:activator_rail",
+            "blockRuntimeId" : 604
+        },
+        {
+            "id" : "minecraft:minecart"
+        },
+        {
+            "id" : "minecraft:chest_minecart"
+        },
+        {
+            "id" : "minecraft:hopper_minecart"
+        },
+        {
+            "id" : "minecraft:tnt_minecart"
+        },
+        {
+            "id" : "minecraft:redstone"
+        },
+        {
+            "id" : "minecraft:redstone_block",
+            "blockRuntimeId" : 5236
+        },
+        {
+            "id" : "minecraft:redstone_torch",
+            "blockRuntimeId" : 4596
+        },
+        {
+            "id" : "minecraft:lever",
+            "blockRuntimeId" : 10364
+        },
+        {
+            "id" : "minecraft:wooden_button",
+            "blockRuntimeId" : 10229
+        },
+        {
+            "id" : "minecraft:spruce_button",
+            "blockRuntimeId" : 6169
+        },
+        {
+            "id" : "minecraft:birch_button",
+            "blockRuntimeId" : 12029
+        },
+        {
+            "id" : "minecraft:jungle_button",
+            "blockRuntimeId" : 120
+        },
+        {
+            "id" : "minecraft:acacia_button",
+            "blockRuntimeId" : 11494
+        },
+        {
+            "id" : "minecraft:dark_oak_button",
+            "blockRuntimeId" : 96
+        },
+        {
+            "id" : "minecraft:mangrove_button",
+            "blockRuntimeId" : 10924
+        },
+        {
+            "id" : "minecraft:stone_button",
+            "blockRuntimeId" : 894
+        },
+        {
+            "id" : "minecraft:crimson_button",
+            "blockRuntimeId" : 6280
+        },
+        {
+            "id" : "minecraft:warped_button",
+            "blockRuntimeId" : 11513
+        },
+        {
+            "id" : "minecraft:polished_blackstone_button",
+            "blockRuntimeId" : 12053
+        },
+        {
+            "id" : "minecraft:tripwire_hook",
+            "blockRuntimeId" : 9334
+        },
+        {
+            "id" : "minecraft:wooden_pressure_plate",
+            "blockRuntimeId" : 12327
+        },
+        {
+            "id" : "minecraft:spruce_pressure_plate",
+            "blockRuntimeId" : 5218
+        },
+        {
+            "id" : "minecraft:birch_pressure_plate",
+            "blockRuntimeId" : 5010
+        },
+        {
+            "id" : "minecraft:jungle_pressure_plate",
+            "blockRuntimeId" : 5093
+        },
+        {
+            "id" : "minecraft:acacia_pressure_plate",
+            "blockRuntimeId" : 7879
+        },
+        {
+            "id" : "minecraft:dark_oak_pressure_plate",
+            "blockRuntimeId" : 9376
+        },
+        {
+            "id" : "minecraft:mangrove_pressure_plate",
+            "blockRuntimeId" : 5713
+        },
+        {
+            "id" : "minecraft:crimson_pressure_plate",
+            "blockRuntimeId" : 12534
+        },
+        {
+            "id" : "minecraft:warped_pressure_plate",
+            "blockRuntimeId" : 263
+        },
+        {
+            "id" : "minecraft:stone_pressure_plate",
+            "blockRuntimeId" : 5730
+        },
+        {
+            "id" : "minecraft:light_weighted_pressure_plate",
+            "blockRuntimeId" : 5123
+        },
+        {
+            "id" : "minecraft:heavy_weighted_pressure_plate",
+            "blockRuntimeId" : 1861
+        },
+        {
+            "id" : "minecraft:polished_blackstone_pressure_plate",
+            "blockRuntimeId" : 10070
+        },
+        {
+            "id" : "minecraft:observer",
+            "blockRuntimeId" : 4584
+        },
+        {
+            "id" : "minecraft:daylight_detector",
+            "blockRuntimeId" : 6043
+        },
+        {
+            "id" : "minecraft:repeater"
+        },
+        {
+            "id" : "minecraft:comparator"
+        },
+        {
+            "id" : "minecraft:hopper"
+        },
+        {
+            "id" : "minecraft:dropper",
+            "blockRuntimeId" : 11648
+        },
+        {
+            "id" : "minecraft:dispenser",
+            "blockRuntimeId" : 12276
+        },
+        {
+            "id" : "minecraft:piston",
+            "blockRuntimeId" : 1614
+        },
+        {
+            "id" : "minecraft:sticky_piston",
+            "blockRuntimeId" : 6212
+        },
+        {
+            "id" : "minecraft:tnt",
+            "blockRuntimeId" : 10559
+        },
+        {
+            "id" : "minecraft:name_tag"
+        },
+        {
+            "id" : "minecraft:loom",
+            "blockRuntimeId" : 5670
+        },
+        {
+            "id" : "minecraft:banner"
+        },
+        {
+            "id" : "minecraft:banner",
+            "damage" : 8
+        },
+        {
+            "id" : "minecraft:banner",
+            "damage" : 7
+        },
+        {
+            "id" : "minecraft:banner",
+            "damage" : 15
+        },
+        {
+            "id" : "minecraft:banner",
+            "damage" : 12
+        },
+        {
+            "id" : "minecraft:banner",
+            "damage" : 14
+        },
+        {
+            "id" : "minecraft:banner",
+            "damage" : 1
+        },
+        {
+            "id" : "minecraft:banner",
+            "damage" : 4
+        },
+        {
+            "id" : "minecraft:banner",
+            "damage" : 5
+        },
+        {
+            "id" : "minecraft:banner",
+            "damage" : 13
+        },
+        {
+            "id" : "minecraft:banner",
+            "damage" : 9
+        },
+        {
+            "id" : "minecraft:banner",
+            "damage" : 3
+        },
+        {
+            "id" : "minecraft:banner",
+            "damage" : 11
+        },
+        {
+            "id" : "minecraft:banner",
+            "damage" : 10
+        },
+        {
+            "id" : "minecraft:banner",
+            "damage" : 2
+        },
+        {
+            "id" : "minecraft:banner",
+            "damage" : 6
+        },
+        {
+            "id" : "minecraft:banner",
+            "damage" : 15,
+            "nbt_b64" : "CgAAAwQAVHlwZQEAAAAA"
+        },
+        {
+            "id" : "minecraft:creeper_banner_pattern"
+        },
+        {
+            "id" : "minecraft:skull_banner_pattern"
+        },
+        {
+            "id" : "minecraft:flower_banner_pattern"
+        },
+        {
+            "id" : "minecraft:mojang_banner_pattern"
+        },
+        {
+            "id" : "minecraft:field_masoned_banner_pattern"
+        },
+        {
+            "id" : "minecraft:bordure_indented_banner_pattern"
+        },
+        {
+            "id" : "minecraft:piglin_banner_pattern"
+        },
+        {
+            "id" : "minecraft:globe_banner_pattern"
+        },
+        {
+            "id" : "minecraft:firework_rocket",
+            "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwAAAAAAAQYARmxpZ2h0AQAA"
+        },
+        {
+            "id" : "minecraft:firework_rocket",
+            "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAABwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"
+        },
+        {
+            "id" : "minecraft:firework_rocket",
+            "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAIBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"
+        },
+        {
+            "id" : "minecraft:firework_rocket",
+            "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAHBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"
+        },
+        {
+            "id" : "minecraft:firework_rocket",
+            "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAPBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"
+        },
+        {
+            "id" : "minecraft:firework_rocket",
+            "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAMBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"
+        },
+        {
+            "id" : "minecraft:firework_rocket",
+            "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAOBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"
+        },
+        {
+            "id" : "minecraft:firework_rocket",
+            "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAABBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"
+        },
+        {
+            "id" : "minecraft:firework_rocket",
+            "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAEBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"
+        },
+        {
+            "id" : "minecraft:firework_rocket",
+            "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAFBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"
+        },
+        {
+            "id" : "minecraft:firework_rocket",
+            "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAANBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"
+        },
+        {
+            "id" : "minecraft:firework_rocket",
+            "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAJBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"
+        },
+        {
+            "id" : "minecraft:firework_rocket",
+            "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAADBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"
+        },
+        {
+            "id" : "minecraft:firework_rocket",
+            "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAALBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"
+        },
+        {
+            "id" : "minecraft:firework_rocket",
+            "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAKBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"
+        },
+        {
+            "id" : "minecraft:firework_rocket",
+            "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAACBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"
+        },
+        {
+            "id" : "minecraft:firework_rocket",
+            "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAGBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA"
+        },
+        {
+            "id" : "minecraft:firework_star",
+            "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yIR0d/wA="
+        },
+        {
+            "id" : "minecraft:firework_star",
+            "damage" : 8,
+            "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yUk9H/wA="
+        },
+        {
+            "id" : "minecraft:firework_star",
+            "damage" : 7,
+            "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yl52d/wA="
+        },
+        {
+            "id" : "minecraft:firework_star",
+            "damage" : 15,
+            "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y8PDw/wA="
+        },
+        {
+            "id" : "minecraft:firework_star",
+            "damage" : 12,
+            "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y2rM6/wA="
+        },
+        {
+            "id" : "minecraft:firework_star",
+            "damage" : 14,
+            "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yHYD5/wA="
+        },
+        {
+            "id" : "minecraft:firework_star",
+            "damage" : 1,
+            "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yJi6w/wA="
+        },
+        {
+            "id" : "minecraft:firework_star",
+            "damage" : 4,
+            "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqkQ8/wA="
+        },
+        {
+            "id" : "minecraft:firework_star",
+            "damage" : 5,
+            "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yuDKJ/wA="
+        },
+        {
+            "id" : "minecraft:firework_star",
+            "damage" : 13,
+            "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yvU7H/wA="
+        },
+        {
+            "id" : "minecraft:firework_star",
+            "damage" : 9,
+            "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqovz/wA="
+        },
+        {
+            "id" : "minecraft:firework_star",
+            "damage" : 3,
+            "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yMlSD/wA="
+        },
+        {
+            "id" : "minecraft:firework_star",
+            "damage" : 11,
+            "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yPdj+/wA="
+        },
+        {
+            "id" : "minecraft:firework_star",
+            "damage" : 10,
+            "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yH8eA/wA="
+        },
+        {
+            "id" : "minecraft:firework_star",
+            "damage" : 2,
+            "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yFnxe/wA="
+        },
+        {
+            "id" : "minecraft:firework_star",
+            "damage" : 6,
+            "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9ynJwW/wA="
+        },
+        {
+            "id" : "minecraft:chain"
+        },
+        {
+            "id" : "minecraft:target",
+            "blockRuntimeId" : 10228
+        },
+        {
+            "id" : "minecraft:lodestone_compass"
+        },
+        {
+            "id" : "minecraft:wither_spawn_egg"
+        },
+        {
+            "id" : "minecraft:ender_dragon_spawn_egg"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/core/src/main/resources/bedrock/runtime_item_states.1_19_70.json b/core/src/main/resources/bedrock/runtime_item_states.1_19_70.json
new file mode 100644
index 000000000..500fcc4f6
--- /dev/null
+++ b/core/src/main/resources/bedrock/runtime_item_states.1_19_70.json
@@ -0,0 +1,4786 @@
+[
+    {
+        "name" : "minecraft:acacia_boat",
+        "id" : 380
+    },
+    {
+        "name" : "minecraft:acacia_button",
+        "id" : -140
+    },
+    {
+        "name" : "minecraft:acacia_chest_boat",
+        "id" : 648
+    },
+    {
+        "name" : "minecraft:acacia_door",
+        "id" : 562
+    },
+    {
+        "name" : "minecraft:acacia_fence_gate",
+        "id" : 187
+    },
+    {
+        "name" : "minecraft:acacia_hanging_sign",
+        "id" : -504
+    },
+    {
+        "name" : "minecraft:acacia_pressure_plate",
+        "id" : -150
+    },
+    {
+        "name" : "minecraft:acacia_sign",
+        "id" : 585
+    },
+    {
+        "name" : "minecraft:acacia_stairs",
+        "id" : 163
+    },
+    {
+        "name" : "minecraft:acacia_standing_sign",
+        "id" : -190
+    },
+    {
+        "name" : "minecraft:acacia_trapdoor",
+        "id" : -145
+    },
+    {
+        "name" : "minecraft:acacia_wall_sign",
+        "id" : -191
+    },
+    {
+        "name" : "minecraft:activator_rail",
+        "id" : 126
+    },
+    {
+        "name" : "minecraft:agent_spawn_egg",
+        "id" : 488
+    },
+    {
+        "name" : "minecraft:air",
+        "id" : -158
+    },
+    {
+        "name" : "minecraft:allay_spawn_egg",
+        "id" : 637
+    },
+    {
+        "name" : "minecraft:allow",
+        "id" : 210
+    },
+    {
+        "name" : "minecraft:amethyst_block",
+        "id" : -327
+    },
+    {
+        "name" : "minecraft:amethyst_cluster",
+        "id" : -329
+    },
+    {
+        "name" : "minecraft:amethyst_shard",
+        "id" : 630
+    },
+    {
+        "name" : "minecraft:ancient_debris",
+        "id" : -271
+    },
+    {
+        "name" : "minecraft:andesite_stairs",
+        "id" : -171
+    },
+    {
+        "name" : "minecraft:anvil",
+        "id" : 145
+    },
+    {
+        "name" : "minecraft:apple",
+        "id" : 257
+    },
+    {
+        "name" : "minecraft:archer_pottery_shard",
+        "id" : 659
+    },
+    {
+        "name" : "minecraft:armor_stand",
+        "id" : 558
+    },
+    {
+        "name" : "minecraft:arms_up_pottery_shard",
+        "id" : 660
+    },
+    {
+        "name" : "minecraft:arrow",
+        "id" : 302
+    },
+    {
+        "name" : "minecraft:axolotl_bucket",
+        "id" : 370
+    },
+    {
+        "name" : "minecraft:axolotl_spawn_egg",
+        "id" : 502
+    },
+    {
+        "name" : "minecraft:azalea",
+        "id" : -337
+    },
+    {
+        "name" : "minecraft:azalea_leaves",
+        "id" : -324
+    },
+    {
+        "name" : "minecraft:azalea_leaves_flowered",
+        "id" : -325
+    },
+    {
+        "name" : "minecraft:baked_potato",
+        "id" : 281
+    },
+    {
+        "name" : "minecraft:balloon",
+        "id" : 604
+    },
+    {
+        "name" : "minecraft:bamboo",
+        "id" : -163
+    },
+    {
+        "name" : "minecraft:bamboo_block",
+        "id" : -527
+    },
+    {
+        "name" : "minecraft:bamboo_button",
+        "id" : -511
+    },
+    {
+        "name" : "minecraft:bamboo_chest_raft",
+        "id" : 657
+    },
+    {
+        "name" : "minecraft:bamboo_door",
+        "id" : -517
+    },
+    {
+        "name" : "minecraft:bamboo_double_slab",
+        "id" : -521
+    },
+    {
+        "name" : "minecraft:bamboo_fence",
+        "id" : -515
+    },
+    {
+        "name" : "minecraft:bamboo_fence_gate",
+        "id" : -516
+    },
+    {
+        "name" : "minecraft:bamboo_hanging_sign",
+        "id" : -522
+    },
+    {
+        "name" : "minecraft:bamboo_mosaic",
+        "id" : -509
+    },
+    {
+        "name" : "minecraft:bamboo_mosaic_double_slab",
+        "id" : -525
+    },
+    {
+        "name" : "minecraft:bamboo_mosaic_slab",
+        "id" : -524
+    },
+    {
+        "name" : "minecraft:bamboo_mosaic_stairs",
+        "id" : -523
+    },
+    {
+        "name" : "minecraft:bamboo_planks",
+        "id" : -510
+    },
+    {
+        "name" : "minecraft:bamboo_pressure_plate",
+        "id" : -514
+    },
+    {
+        "name" : "minecraft:bamboo_raft",
+        "id" : 656
+    },
+    {
+        "name" : "minecraft:bamboo_sapling",
+        "id" : -164
+    },
+    {
+        "name" : "minecraft:bamboo_sign",
+        "id" : 655
+    },
+    {
+        "name" : "minecraft:bamboo_slab",
+        "id" : -513
+    },
+    {
+        "name" : "minecraft:bamboo_stairs",
+        "id" : -512
+    },
+    {
+        "name" : "minecraft:bamboo_standing_sign",
+        "id" : -518
+    },
+    {
+        "name" : "minecraft:bamboo_trapdoor",
+        "id" : -520
+    },
+    {
+        "name" : "minecraft:bamboo_wall_sign",
+        "id" : -519
+    },
+    {
+        "name" : "minecraft:banner",
+        "id" : 573
+    },
+    {
+        "name" : "minecraft:banner_pattern",
+        "id" : 667
+    },
+    {
+        "name" : "minecraft:barrel",
+        "id" : -203
+    },
+    {
+        "name" : "minecraft:barrier",
+        "id" : -161
+    },
+    {
+        "name" : "minecraft:basalt",
+        "id" : -234
+    },
+    {
+        "name" : "minecraft:bat_spawn_egg",
+        "id" : 454
+    },
+    {
+        "name" : "minecraft:beacon",
+        "id" : 138
+    },
+    {
+        "name" : "minecraft:bed",
+        "id" : 419
+    },
+    {
+        "name" : "minecraft:bedrock",
+        "id" : 7
+    },
+    {
+        "name" : "minecraft:bee_nest",
+        "id" : -218
+    },
+    {
+        "name" : "minecraft:bee_spawn_egg",
+        "id" : 495
+    },
+    {
+        "name" : "minecraft:beef",
+        "id" : 273
+    },
+    {
+        "name" : "minecraft:beehive",
+        "id" : -219
+    },
+    {
+        "name" : "minecraft:beetroot",
+        "id" : 285
+    },
+    {
+        "name" : "minecraft:beetroot_seeds",
+        "id" : 295
+    },
+    {
+        "name" : "minecraft:beetroot_soup",
+        "id" : 286
+    },
+    {
+        "name" : "minecraft:bell",
+        "id" : -206
+    },
+    {
+        "name" : "minecraft:big_dripleaf",
+        "id" : -323
+    },
+    {
+        "name" : "minecraft:birch_boat",
+        "id" : 377
+    },
+    {
+        "name" : "minecraft:birch_button",
+        "id" : -141
+    },
+    {
+        "name" : "minecraft:birch_chest_boat",
+        "id" : 645
+    },
+    {
+        "name" : "minecraft:birch_door",
+        "id" : 560
+    },
+    {
+        "name" : "minecraft:birch_fence_gate",
+        "id" : 184
+    },
+    {
+        "name" : "minecraft:birch_hanging_sign",
+        "id" : -502
+    },
+    {
+        "name" : "minecraft:birch_pressure_plate",
+        "id" : -151
+    },
+    {
+        "name" : "minecraft:birch_sign",
+        "id" : 583
+    },
+    {
+        "name" : "minecraft:birch_stairs",
+        "id" : 135
+    },
+    {
+        "name" : "minecraft:birch_standing_sign",
+        "id" : -186
+    },
+    {
+        "name" : "minecraft:birch_trapdoor",
+        "id" : -146
+    },
+    {
+        "name" : "minecraft:birch_wall_sign",
+        "id" : -187
+    },
+    {
+        "name" : "minecraft:black_candle",
+        "id" : -428
+    },
+    {
+        "name" : "minecraft:black_candle_cake",
+        "id" : -445
+    },
+    {
+        "name" : "minecraft:black_dye",
+        "id" : 396
+    },
+    {
+        "name" : "minecraft:black_glazed_terracotta",
+        "id" : 235
+    },
+    {
+        "name" : "minecraft:black_wool",
+        "id" : -554
+    },
+    {
+        "name" : "minecraft:blackstone",
+        "id" : -273
+    },
+    {
+        "name" : "minecraft:blackstone_double_slab",
+        "id" : -283
+    },
+    {
+        "name" : "minecraft:blackstone_slab",
+        "id" : -282
+    },
+    {
+        "name" : "minecraft:blackstone_stairs",
+        "id" : -276
+    },
+    {
+        "name" : "minecraft:blackstone_wall",
+        "id" : -277
+    },
+    {
+        "name" : "minecraft:blast_furnace",
+        "id" : -196
+    },
+    {
+        "name" : "minecraft:blaze_powder",
+        "id" : 430
+    },
+    {
+        "name" : "minecraft:blaze_rod",
+        "id" : 424
+    },
+    {
+        "name" : "minecraft:blaze_spawn_egg",
+        "id" : 457
+    },
+    {
+        "name" : "minecraft:bleach",
+        "id" : 602
+    },
+    {
+        "name" : "minecraft:blue_candle",
+        "id" : -424
+    },
+    {
+        "name" : "minecraft:blue_candle_cake",
+        "id" : -441
+    },
+    {
+        "name" : "minecraft:blue_dye",
+        "id" : 400
+    },
+    {
+        "name" : "minecraft:blue_glazed_terracotta",
+        "id" : 231
+    },
+    {
+        "name" : "minecraft:blue_ice",
+        "id" : -11
+    },
+    {
+        "name" : "minecraft:blue_wool",
+        "id" : -563
+    },
+    {
+        "name" : "minecraft:boat",
+        "id" : 665
+    },
+    {
+        "name" : "minecraft:bone",
+        "id" : 416
+    },
+    {
+        "name" : "minecraft:bone_block",
+        "id" : 216
+    },
+    {
+        "name" : "minecraft:bone_meal",
+        "id" : 412
+    },
+    {
+        "name" : "minecraft:book",
+        "id" : 388
+    },
+    {
+        "name" : "minecraft:bookshelf",
+        "id" : 47
+    },
+    {
+        "name" : "minecraft:border_block",
+        "id" : 212
+    },
+    {
+        "name" : "minecraft:bordure_indented_banner_pattern",
+        "id" : 592
+    },
+    {
+        "name" : "minecraft:bow",
+        "id" : 301
+    },
+    {
+        "name" : "minecraft:bowl",
+        "id" : 322
+    },
+    {
+        "name" : "minecraft:bread",
+        "id" : 261
+    },
+    {
+        "name" : "minecraft:brewing_stand",
+        "id" : 432
+    },
+    {
+        "name" : "minecraft:brick",
+        "id" : 384
+    },
+    {
+        "name" : "minecraft:brick_block",
+        "id" : 45
+    },
+    {
+        "name" : "minecraft:brick_stairs",
+        "id" : 108
+    },
+    {
+        "name" : "minecraft:brown_candle",
+        "id" : -425
+    },
+    {
+        "name" : "minecraft:brown_candle_cake",
+        "id" : -442
+    },
+    {
+        "name" : "minecraft:brown_dye",
+        "id" : 399
+    },
+    {
+        "name" : "minecraft:brown_glazed_terracotta",
+        "id" : 232
+    },
+    {
+        "name" : "minecraft:brown_mushroom",
+        "id" : 39
+    },
+    {
+        "name" : "minecraft:brown_mushroom_block",
+        "id" : 99
+    },
+    {
+        "name" : "minecraft:brown_wool",
+        "id" : -555
+    },
+    {
+        "name" : "minecraft:brush",
+        "id" : 663
+    },
+    {
+        "name" : "minecraft:bubble_column",
+        "id" : -160
+    },
+    {
+        "name" : "minecraft:bucket",
+        "id" : 361
+    },
+    {
+        "name" : "minecraft:budding_amethyst",
+        "id" : -328
+    },
+    {
+        "name" : "minecraft:cactus",
+        "id" : 81
+    },
+    {
+        "name" : "minecraft:cake",
+        "id" : 418
+    },
+    {
+        "name" : "minecraft:calcite",
+        "id" : -326
+    },
+    {
+        "name" : "minecraft:camel_spawn_egg",
+        "id" : 658
+    },
+    {
+        "name" : "minecraft:camera",
+        "id" : 599
+    },
+    {
+        "name" : "minecraft:campfire",
+        "id" : 595
+    },
+    {
+        "name" : "minecraft:candle",
+        "id" : -412
+    },
+    {
+        "name" : "minecraft:candle_cake",
+        "id" : -429
+    },
+    {
+        "name" : "minecraft:carpet",
+        "id" : 171
+    },
+    {
+        "name" : "minecraft:carrot",
+        "id" : 279
+    },
+    {
+        "name" : "minecraft:carrot_on_a_stick",
+        "id" : 523
+    },
+    {
+        "name" : "minecraft:carrots",
+        "id" : 141
+    },
+    {
+        "name" : "minecraft:cartography_table",
+        "id" : -200
+    },
+    {
+        "name" : "minecraft:carved_pumpkin",
+        "id" : -155
+    },
+    {
+        "name" : "minecraft:cat_spawn_egg",
+        "id" : 489
+    },
+    {
+        "name" : "minecraft:cauldron",
+        "id" : 433
+    },
+    {
+        "name" : "minecraft:cave_spider_spawn_egg",
+        "id" : 458
+    },
+    {
+        "name" : "minecraft:cave_vines",
+        "id" : -322
+    },
+    {
+        "name" : "minecraft:cave_vines_body_with_berries",
+        "id" : -375
+    },
+    {
+        "name" : "minecraft:cave_vines_head_with_berries",
+        "id" : -376
+    },
+    {
+        "name" : "minecraft:chain",
+        "id" : 625
+    },
+    {
+        "name" : "minecraft:chain_command_block",
+        "id" : 189
+    },
+    {
+        "name" : "minecraft:chainmail_boots",
+        "id" : 343
+    },
+    {
+        "name" : "minecraft:chainmail_chestplate",
+        "id" : 341
+    },
+    {
+        "name" : "minecraft:chainmail_helmet",
+        "id" : 340
+    },
+    {
+        "name" : "minecraft:chainmail_leggings",
+        "id" : 342
+    },
+    {
+        "name" : "minecraft:charcoal",
+        "id" : 304
+    },
+    {
+        "name" : "minecraft:chemical_heat",
+        "id" : 192
+    },
+    {
+        "name" : "minecraft:chemistry_table",
+        "id" : 238
+    },
+    {
+        "name" : "minecraft:chest",
+        "id" : 54
+    },
+    {
+        "name" : "minecraft:chest_boat",
+        "id" : 651
+    },
+    {
+        "name" : "minecraft:chest_minecart",
+        "id" : 390
+    },
+    {
+        "name" : "minecraft:chicken",
+        "id" : 275
+    },
+    {
+        "name" : "minecraft:chicken_spawn_egg",
+        "id" : 436
+    },
+    {
+        "name" : "minecraft:chiseled_bookshelf",
+        "id" : -526
+    },
+    {
+        "name" : "minecraft:chiseled_deepslate",
+        "id" : -395
+    },
+    {
+        "name" : "minecraft:chiseled_nether_bricks",
+        "id" : -302
+    },
+    {
+        "name" : "minecraft:chiseled_polished_blackstone",
+        "id" : -279
+    },
+    {
+        "name" : "minecraft:chorus_flower",
+        "id" : 200
+    },
+    {
+        "name" : "minecraft:chorus_fruit",
+        "id" : 564
+    },
+    {
+        "name" : "minecraft:chorus_plant",
+        "id" : 240
+    },
+    {
+        "name" : "minecraft:clay",
+        "id" : 82
+    },
+    {
+        "name" : "minecraft:clay_ball",
+        "id" : 385
+    },
+    {
+        "name" : "minecraft:client_request_placeholder_block",
+        "id" : -465
+    },
+    {
+        "name" : "minecraft:clock",
+        "id" : 394
+    },
+    {
+        "name" : "minecraft:coal",
+        "id" : 303
+    },
+    {
+        "name" : "minecraft:coal_block",
+        "id" : 173
+    },
+    {
+        "name" : "minecraft:coal_ore",
+        "id" : 16
+    },
+    {
+        "name" : "minecraft:cobbled_deepslate",
+        "id" : -379
+    },
+    {
+        "name" : "minecraft:cobbled_deepslate_double_slab",
+        "id" : -396
+    },
+    {
+        "name" : "minecraft:cobbled_deepslate_slab",
+        "id" : -380
+    },
+    {
+        "name" : "minecraft:cobbled_deepslate_stairs",
+        "id" : -381
+    },
+    {
+        "name" : "minecraft:cobbled_deepslate_wall",
+        "id" : -382
+    },
+    {
+        "name" : "minecraft:cobblestone",
+        "id" : 4
+    },
+    {
+        "name" : "minecraft:cobblestone_wall",
+        "id" : 139
+    },
+    {
+        "name" : "minecraft:cocoa",
+        "id" : 127
+    },
+    {
+        "name" : "minecraft:cocoa_beans",
+        "id" : 413
+    },
+    {
+        "name" : "minecraft:cod",
+        "id" : 264
+    },
+    {
+        "name" : "minecraft:cod_bucket",
+        "id" : 365
+    },
+    {
+        "name" : "minecraft:cod_spawn_egg",
+        "id" : 481
+    },
+    {
+        "name" : "minecraft:colored_torch_bp",
+        "id" : 204
+    },
+    {
+        "name" : "minecraft:colored_torch_rg",
+        "id" : 202
+    },
+    {
+        "name" : "minecraft:command_block",
+        "id" : 137
+    },
+    {
+        "name" : "minecraft:command_block_minecart",
+        "id" : 569
+    },
+    {
+        "name" : "minecraft:comparator",
+        "id" : 528
+    },
+    {
+        "name" : "minecraft:compass",
+        "id" : 392
+    },
+    {
+        "name" : "minecraft:composter",
+        "id" : -213
+    },
+    {
+        "name" : "minecraft:compound",
+        "id" : 600
+    },
+    {
+        "name" : "minecraft:concrete",
+        "id" : 236
+    },
+    {
+        "name" : "minecraft:concrete_powder",
+        "id" : 237
+    },
+    {
+        "name" : "minecraft:conduit",
+        "id" : -157
+    },
+    {
+        "name" : "minecraft:cooked_beef",
+        "id" : 274
+    },
+    {
+        "name" : "minecraft:cooked_chicken",
+        "id" : 276
+    },
+    {
+        "name" : "minecraft:cooked_cod",
+        "id" : 268
+    },
+    {
+        "name" : "minecraft:cooked_mutton",
+        "id" : 557
+    },
+    {
+        "name" : "minecraft:cooked_porkchop",
+        "id" : 263
+    },
+    {
+        "name" : "minecraft:cooked_rabbit",
+        "id" : 289
+    },
+    {
+        "name" : "minecraft:cooked_salmon",
+        "id" : 269
+    },
+    {
+        "name" : "minecraft:cookie",
+        "id" : 271
+    },
+    {
+        "name" : "minecraft:copper_block",
+        "id" : -340
+    },
+    {
+        "name" : "minecraft:copper_ingot",
+        "id" : 510
+    },
+    {
+        "name" : "minecraft:copper_ore",
+        "id" : -311
+    },
+    {
+        "name" : "minecraft:coral",
+        "id" : -131
+    },
+    {
+        "name" : "minecraft:coral_block",
+        "id" : -132
+    },
+    {
+        "name" : "minecraft:coral_fan",
+        "id" : -133
+    },
+    {
+        "name" : "minecraft:coral_fan_dead",
+        "id" : -134
+    },
+    {
+        "name" : "minecraft:coral_fan_hang",
+        "id" : -135
+    },
+    {
+        "name" : "minecraft:coral_fan_hang2",
+        "id" : -136
+    },
+    {
+        "name" : "minecraft:coral_fan_hang3",
+        "id" : -137
+    },
+    {
+        "name" : "minecraft:cow_spawn_egg",
+        "id" : 437
+    },
+    {
+        "name" : "minecraft:cracked_deepslate_bricks",
+        "id" : -410
+    },
+    {
+        "name" : "minecraft:cracked_deepslate_tiles",
+        "id" : -409
+    },
+    {
+        "name" : "minecraft:cracked_nether_bricks",
+        "id" : -303
+    },
+    {
+        "name" : "minecraft:cracked_polished_blackstone_bricks",
+        "id" : -280
+    },
+    {
+        "name" : "minecraft:crafting_table",
+        "id" : 58
+    },
+    {
+        "name" : "minecraft:creeper_banner_pattern",
+        "id" : 588
+    },
+    {
+        "name" : "minecraft:creeper_spawn_egg",
+        "id" : 442
+    },
+    {
+        "name" : "minecraft:crimson_button",
+        "id" : -260
+    },
+    {
+        "name" : "minecraft:crimson_door",
+        "id" : 622
+    },
+    {
+        "name" : "minecraft:crimson_double_slab",
+        "id" : -266
+    },
+    {
+        "name" : "minecraft:crimson_fence",
+        "id" : -256
+    },
+    {
+        "name" : "minecraft:crimson_fence_gate",
+        "id" : -258
+    },
+    {
+        "name" : "minecraft:crimson_fungus",
+        "id" : -228
+    },
+    {
+        "name" : "minecraft:crimson_hanging_sign",
+        "id" : -506
+    },
+    {
+        "name" : "minecraft:crimson_hyphae",
+        "id" : -299
+    },
+    {
+        "name" : "minecraft:crimson_nylium",
+        "id" : -232
+    },
+    {
+        "name" : "minecraft:crimson_planks",
+        "id" : -242
+    },
+    {
+        "name" : "minecraft:crimson_pressure_plate",
+        "id" : -262
+    },
+    {
+        "name" : "minecraft:crimson_roots",
+        "id" : -223
+    },
+    {
+        "name" : "minecraft:crimson_sign",
+        "id" : 620
+    },
+    {
+        "name" : "minecraft:crimson_slab",
+        "id" : -264
+    },
+    {
+        "name" : "minecraft:crimson_stairs",
+        "id" : -254
+    },
+    {
+        "name" : "minecraft:crimson_standing_sign",
+        "id" : -250
+    },
+    {
+        "name" : "minecraft:crimson_stem",
+        "id" : -225
+    },
+    {
+        "name" : "minecraft:crimson_trapdoor",
+        "id" : -246
+    },
+    {
+        "name" : "minecraft:crimson_wall_sign",
+        "id" : -252
+    },
+    {
+        "name" : "minecraft:crossbow",
+        "id" : 581
+    },
+    {
+        "name" : "minecraft:crying_obsidian",
+        "id" : -289
+    },
+    {
+        "name" : "minecraft:cut_copper",
+        "id" : -347
+    },
+    {
+        "name" : "minecraft:cut_copper_slab",
+        "id" : -361
+    },
+    {
+        "name" : "minecraft:cut_copper_stairs",
+        "id" : -354
+    },
+    {
+        "name" : "minecraft:cyan_candle",
+        "id" : -422
+    },
+    {
+        "name" : "minecraft:cyan_candle_cake",
+        "id" : -439
+    },
+    {
+        "name" : "minecraft:cyan_dye",
+        "id" : 402
+    },
+    {
+        "name" : "minecraft:cyan_glazed_terracotta",
+        "id" : 229
+    },
+    {
+        "name" : "minecraft:cyan_wool",
+        "id" : -561
+    },
+    {
+        "name" : "minecraft:dark_oak_boat",
+        "id" : 381
+    },
+    {
+        "name" : "minecraft:dark_oak_button",
+        "id" : -142
+    },
+    {
+        "name" : "minecraft:dark_oak_chest_boat",
+        "id" : 649
+    },
+    {
+        "name" : "minecraft:dark_oak_door",
+        "id" : 563
+    },
+    {
+        "name" : "minecraft:dark_oak_fence_gate",
+        "id" : 186
+    },
+    {
+        "name" : "minecraft:dark_oak_hanging_sign",
+        "id" : -505
+    },
+    {
+        "name" : "minecraft:dark_oak_pressure_plate",
+        "id" : -152
+    },
+    {
+        "name" : "minecraft:dark_oak_sign",
+        "id" : 586
+    },
+    {
+        "name" : "minecraft:dark_oak_stairs",
+        "id" : 164
+    },
+    {
+        "name" : "minecraft:dark_oak_trapdoor",
+        "id" : -147
+    },
+    {
+        "name" : "minecraft:dark_prismarine_stairs",
+        "id" : -3
+    },
+    {
+        "name" : "minecraft:darkoak_standing_sign",
+        "id" : -192
+    },
+    {
+        "name" : "minecraft:darkoak_wall_sign",
+        "id" : -193
+    },
+    {
+        "name" : "minecraft:daylight_detector",
+        "id" : 151
+    },
+    {
+        "name" : "minecraft:daylight_detector_inverted",
+        "id" : 178
+    },
+    {
+        "name" : "minecraft:deadbush",
+        "id" : 32
+    },
+    {
+        "name" : "minecraft:decorated_pot",
+        "id" : -551
+    },
+    {
+        "name" : "minecraft:deepslate",
+        "id" : -378
+    },
+    {
+        "name" : "minecraft:deepslate_brick_double_slab",
+        "id" : -399
+    },
+    {
+        "name" : "minecraft:deepslate_brick_slab",
+        "id" : -392
+    },
+    {
+        "name" : "minecraft:deepslate_brick_stairs",
+        "id" : -393
+    },
+    {
+        "name" : "minecraft:deepslate_brick_wall",
+        "id" : -394
+    },
+    {
+        "name" : "minecraft:deepslate_bricks",
+        "id" : -391
+    },
+    {
+        "name" : "minecraft:deepslate_coal_ore",
+        "id" : -406
+    },
+    {
+        "name" : "minecraft:deepslate_copper_ore",
+        "id" : -408
+    },
+    {
+        "name" : "minecraft:deepslate_diamond_ore",
+        "id" : -405
+    },
+    {
+        "name" : "minecraft:deepslate_emerald_ore",
+        "id" : -407
+    },
+    {
+        "name" : "minecraft:deepslate_gold_ore",
+        "id" : -402
+    },
+    {
+        "name" : "minecraft:deepslate_iron_ore",
+        "id" : -401
+    },
+    {
+        "name" : "minecraft:deepslate_lapis_ore",
+        "id" : -400
+    },
+    {
+        "name" : "minecraft:deepslate_redstone_ore",
+        "id" : -403
+    },
+    {
+        "name" : "minecraft:deepslate_tile_double_slab",
+        "id" : -398
+    },
+    {
+        "name" : "minecraft:deepslate_tile_slab",
+        "id" : -388
+    },
+    {
+        "name" : "minecraft:deepslate_tile_stairs",
+        "id" : -389
+    },
+    {
+        "name" : "minecraft:deepslate_tile_wall",
+        "id" : -390
+    },
+    {
+        "name" : "minecraft:deepslate_tiles",
+        "id" : -387
+    },
+    {
+        "name" : "minecraft:deny",
+        "id" : 211
+    },
+    {
+        "name" : "minecraft:detector_rail",
+        "id" : 28
+    },
+    {
+        "name" : "minecraft:diamond",
+        "id" : 305
+    },
+    {
+        "name" : "minecraft:diamond_axe",
+        "id" : 320
+    },
+    {
+        "name" : "minecraft:diamond_block",
+        "id" : 57
+    },
+    {
+        "name" : "minecraft:diamond_boots",
+        "id" : 351
+    },
+    {
+        "name" : "minecraft:diamond_chestplate",
+        "id" : 349
+    },
+    {
+        "name" : "minecraft:diamond_helmet",
+        "id" : 348
+    },
+    {
+        "name" : "minecraft:diamond_hoe",
+        "id" : 333
+    },
+    {
+        "name" : "minecraft:diamond_horse_armor",
+        "id" : 539
+    },
+    {
+        "name" : "minecraft:diamond_leggings",
+        "id" : 350
+    },
+    {
+        "name" : "minecraft:diamond_ore",
+        "id" : 56
+    },
+    {
+        "name" : "minecraft:diamond_pickaxe",
+        "id" : 319
+    },
+    {
+        "name" : "minecraft:diamond_shovel",
+        "id" : 318
+    },
+    {
+        "name" : "minecraft:diamond_sword",
+        "id" : 317
+    },
+    {
+        "name" : "minecraft:diorite_stairs",
+        "id" : -170
+    },
+    {
+        "name" : "minecraft:dirt",
+        "id" : 3
+    },
+    {
+        "name" : "minecraft:dirt_with_roots",
+        "id" : -318
+    },
+    {
+        "name" : "minecraft:disc_fragment_5",
+        "id" : 643
+    },
+    {
+        "name" : "minecraft:dispenser",
+        "id" : 23
+    },
+    {
+        "name" : "minecraft:dolphin_spawn_egg",
+        "id" : 485
+    },
+    {
+        "name" : "minecraft:donkey_spawn_egg",
+        "id" : 466
+    },
+    {
+        "name" : "minecraft:double_cut_copper_slab",
+        "id" : -368
+    },
+    {
+        "name" : "minecraft:double_plant",
+        "id" : 175
+    },
+    {
+        "name" : "minecraft:double_stone_block_slab",
+        "id" : 43
+    },
+    {
+        "name" : "minecraft:double_stone_block_slab2",
+        "id" : 181
+    },
+    {
+        "name" : "minecraft:double_stone_block_slab3",
+        "id" : -167
+    },
+    {
+        "name" : "minecraft:double_stone_block_slab4",
+        "id" : -168
+    },
+    {
+        "name" : "minecraft:double_wooden_slab",
+        "id" : 157
+    },
+    {
+        "name" : "minecraft:dragon_breath",
+        "id" : 566
+    },
+    {
+        "name" : "minecraft:dragon_egg",
+        "id" : 122
+    },
+    {
+        "name" : "minecraft:dried_kelp",
+        "id" : 270
+    },
+    {
+        "name" : "minecraft:dried_kelp_block",
+        "id" : -139
+    },
+    {
+        "name" : "minecraft:dripstone_block",
+        "id" : -317
+    },
+    {
+        "name" : "minecraft:dropper",
+        "id" : 125
+    },
+    {
+        "name" : "minecraft:drowned_spawn_egg",
+        "id" : 484
+    },
+    {
+        "name" : "minecraft:dye",
+        "id" : 666
+    },
+    {
+        "name" : "minecraft:echo_shard",
+        "id" : 653
+    },
+    {
+        "name" : "minecraft:egg",
+        "id" : 391
+    },
+    {
+        "name" : "minecraft:elder_guardian_spawn_egg",
+        "id" : 472
+    },
+    {
+        "name" : "minecraft:element_0",
+        "id" : 36
+    },
+    {
+        "name" : "minecraft:element_1",
+        "id" : -12
+    },
+    {
+        "name" : "minecraft:element_10",
+        "id" : -21
+    },
+    {
+        "name" : "minecraft:element_100",
+        "id" : -111
+    },
+    {
+        "name" : "minecraft:element_101",
+        "id" : -112
+    },
+    {
+        "name" : "minecraft:element_102",
+        "id" : -113
+    },
+    {
+        "name" : "minecraft:element_103",
+        "id" : -114
+    },
+    {
+        "name" : "minecraft:element_104",
+        "id" : -115
+    },
+    {
+        "name" : "minecraft:element_105",
+        "id" : -116
+    },
+    {
+        "name" : "minecraft:element_106",
+        "id" : -117
+    },
+    {
+        "name" : "minecraft:element_107",
+        "id" : -118
+    },
+    {
+        "name" : "minecraft:element_108",
+        "id" : -119
+    },
+    {
+        "name" : "minecraft:element_109",
+        "id" : -120
+    },
+    {
+        "name" : "minecraft:element_11",
+        "id" : -22
+    },
+    {
+        "name" : "minecraft:element_110",
+        "id" : -121
+    },
+    {
+        "name" : "minecraft:element_111",
+        "id" : -122
+    },
+    {
+        "name" : "minecraft:element_112",
+        "id" : -123
+    },
+    {
+        "name" : "minecraft:element_113",
+        "id" : -124
+    },
+    {
+        "name" : "minecraft:element_114",
+        "id" : -125
+    },
+    {
+        "name" : "minecraft:element_115",
+        "id" : -126
+    },
+    {
+        "name" : "minecraft:element_116",
+        "id" : -127
+    },
+    {
+        "name" : "minecraft:element_117",
+        "id" : -128
+    },
+    {
+        "name" : "minecraft:element_118",
+        "id" : -129
+    },
+    {
+        "name" : "minecraft:element_12",
+        "id" : -23
+    },
+    {
+        "name" : "minecraft:element_13",
+        "id" : -24
+    },
+    {
+        "name" : "minecraft:element_14",
+        "id" : -25
+    },
+    {
+        "name" : "minecraft:element_15",
+        "id" : -26
+    },
+    {
+        "name" : "minecraft:element_16",
+        "id" : -27
+    },
+    {
+        "name" : "minecraft:element_17",
+        "id" : -28
+    },
+    {
+        "name" : "minecraft:element_18",
+        "id" : -29
+    },
+    {
+        "name" : "minecraft:element_19",
+        "id" : -30
+    },
+    {
+        "name" : "minecraft:element_2",
+        "id" : -13
+    },
+    {
+        "name" : "minecraft:element_20",
+        "id" : -31
+    },
+    {
+        "name" : "minecraft:element_21",
+        "id" : -32
+    },
+    {
+        "name" : "minecraft:element_22",
+        "id" : -33
+    },
+    {
+        "name" : "minecraft:element_23",
+        "id" : -34
+    },
+    {
+        "name" : "minecraft:element_24",
+        "id" : -35
+    },
+    {
+        "name" : "minecraft:element_25",
+        "id" : -36
+    },
+    {
+        "name" : "minecraft:element_26",
+        "id" : -37
+    },
+    {
+        "name" : "minecraft:element_27",
+        "id" : -38
+    },
+    {
+        "name" : "minecraft:element_28",
+        "id" : -39
+    },
+    {
+        "name" : "minecraft:element_29",
+        "id" : -40
+    },
+    {
+        "name" : "minecraft:element_3",
+        "id" : -14
+    },
+    {
+        "name" : "minecraft:element_30",
+        "id" : -41
+    },
+    {
+        "name" : "minecraft:element_31",
+        "id" : -42
+    },
+    {
+        "name" : "minecraft:element_32",
+        "id" : -43
+    },
+    {
+        "name" : "minecraft:element_33",
+        "id" : -44
+    },
+    {
+        "name" : "minecraft:element_34",
+        "id" : -45
+    },
+    {
+        "name" : "minecraft:element_35",
+        "id" : -46
+    },
+    {
+        "name" : "minecraft:element_36",
+        "id" : -47
+    },
+    {
+        "name" : "minecraft:element_37",
+        "id" : -48
+    },
+    {
+        "name" : "minecraft:element_38",
+        "id" : -49
+    },
+    {
+        "name" : "minecraft:element_39",
+        "id" : -50
+    },
+    {
+        "name" : "minecraft:element_4",
+        "id" : -15
+    },
+    {
+        "name" : "minecraft:element_40",
+        "id" : -51
+    },
+    {
+        "name" : "minecraft:element_41",
+        "id" : -52
+    },
+    {
+        "name" : "minecraft:element_42",
+        "id" : -53
+    },
+    {
+        "name" : "minecraft:element_43",
+        "id" : -54
+    },
+    {
+        "name" : "minecraft:element_44",
+        "id" : -55
+    },
+    {
+        "name" : "minecraft:element_45",
+        "id" : -56
+    },
+    {
+        "name" : "minecraft:element_46",
+        "id" : -57
+    },
+    {
+        "name" : "minecraft:element_47",
+        "id" : -58
+    },
+    {
+        "name" : "minecraft:element_48",
+        "id" : -59
+    },
+    {
+        "name" : "minecraft:element_49",
+        "id" : -60
+    },
+    {
+        "name" : "minecraft:element_5",
+        "id" : -16
+    },
+    {
+        "name" : "minecraft:element_50",
+        "id" : -61
+    },
+    {
+        "name" : "minecraft:element_51",
+        "id" : -62
+    },
+    {
+        "name" : "minecraft:element_52",
+        "id" : -63
+    },
+    {
+        "name" : "minecraft:element_53",
+        "id" : -64
+    },
+    {
+        "name" : "minecraft:element_54",
+        "id" : -65
+    },
+    {
+        "name" : "minecraft:element_55",
+        "id" : -66
+    },
+    {
+        "name" : "minecraft:element_56",
+        "id" : -67
+    },
+    {
+        "name" : "minecraft:element_57",
+        "id" : -68
+    },
+    {
+        "name" : "minecraft:element_58",
+        "id" : -69
+    },
+    {
+        "name" : "minecraft:element_59",
+        "id" : -70
+    },
+    {
+        "name" : "minecraft:element_6",
+        "id" : -17
+    },
+    {
+        "name" : "minecraft:element_60",
+        "id" : -71
+    },
+    {
+        "name" : "minecraft:element_61",
+        "id" : -72
+    },
+    {
+        "name" : "minecraft:element_62",
+        "id" : -73
+    },
+    {
+        "name" : "minecraft:element_63",
+        "id" : -74
+    },
+    {
+        "name" : "minecraft:element_64",
+        "id" : -75
+    },
+    {
+        "name" : "minecraft:element_65",
+        "id" : -76
+    },
+    {
+        "name" : "minecraft:element_66",
+        "id" : -77
+    },
+    {
+        "name" : "minecraft:element_67",
+        "id" : -78
+    },
+    {
+        "name" : "minecraft:element_68",
+        "id" : -79
+    },
+    {
+        "name" : "minecraft:element_69",
+        "id" : -80
+    },
+    {
+        "name" : "minecraft:element_7",
+        "id" : -18
+    },
+    {
+        "name" : "minecraft:element_70",
+        "id" : -81
+    },
+    {
+        "name" : "minecraft:element_71",
+        "id" : -82
+    },
+    {
+        "name" : "minecraft:element_72",
+        "id" : -83
+    },
+    {
+        "name" : "minecraft:element_73",
+        "id" : -84
+    },
+    {
+        "name" : "minecraft:element_74",
+        "id" : -85
+    },
+    {
+        "name" : "minecraft:element_75",
+        "id" : -86
+    },
+    {
+        "name" : "minecraft:element_76",
+        "id" : -87
+    },
+    {
+        "name" : "minecraft:element_77",
+        "id" : -88
+    },
+    {
+        "name" : "minecraft:element_78",
+        "id" : -89
+    },
+    {
+        "name" : "minecraft:element_79",
+        "id" : -90
+    },
+    {
+        "name" : "minecraft:element_8",
+        "id" : -19
+    },
+    {
+        "name" : "minecraft:element_80",
+        "id" : -91
+    },
+    {
+        "name" : "minecraft:element_81",
+        "id" : -92
+    },
+    {
+        "name" : "minecraft:element_82",
+        "id" : -93
+    },
+    {
+        "name" : "minecraft:element_83",
+        "id" : -94
+    },
+    {
+        "name" : "minecraft:element_84",
+        "id" : -95
+    },
+    {
+        "name" : "minecraft:element_85",
+        "id" : -96
+    },
+    {
+        "name" : "minecraft:element_86",
+        "id" : -97
+    },
+    {
+        "name" : "minecraft:element_87",
+        "id" : -98
+    },
+    {
+        "name" : "minecraft:element_88",
+        "id" : -99
+    },
+    {
+        "name" : "minecraft:element_89",
+        "id" : -100
+    },
+    {
+        "name" : "minecraft:element_9",
+        "id" : -20
+    },
+    {
+        "name" : "minecraft:element_90",
+        "id" : -101
+    },
+    {
+        "name" : "minecraft:element_91",
+        "id" : -102
+    },
+    {
+        "name" : "minecraft:element_92",
+        "id" : -103
+    },
+    {
+        "name" : "minecraft:element_93",
+        "id" : -104
+    },
+    {
+        "name" : "minecraft:element_94",
+        "id" : -105
+    },
+    {
+        "name" : "minecraft:element_95",
+        "id" : -106
+    },
+    {
+        "name" : "minecraft:element_96",
+        "id" : -107
+    },
+    {
+        "name" : "minecraft:element_97",
+        "id" : -108
+    },
+    {
+        "name" : "minecraft:element_98",
+        "id" : -109
+    },
+    {
+        "name" : "minecraft:element_99",
+        "id" : -110
+    },
+    {
+        "name" : "minecraft:elytra",
+        "id" : 570
+    },
+    {
+        "name" : "minecraft:emerald",
+        "id" : 518
+    },
+    {
+        "name" : "minecraft:emerald_block",
+        "id" : 133
+    },
+    {
+        "name" : "minecraft:emerald_ore",
+        "id" : 129
+    },
+    {
+        "name" : "minecraft:empty_map",
+        "id" : 521
+    },
+    {
+        "name" : "minecraft:enchanted_book",
+        "id" : 527
+    },
+    {
+        "name" : "minecraft:enchanted_golden_apple",
+        "id" : 259
+    },
+    {
+        "name" : "minecraft:enchanting_table",
+        "id" : 116
+    },
+    {
+        "name" : "minecraft:end_brick_stairs",
+        "id" : -178
+    },
+    {
+        "name" : "minecraft:end_bricks",
+        "id" : 206
+    },
+    {
+        "name" : "minecraft:end_crystal",
+        "id" : 669
+    },
+    {
+        "name" : "minecraft:end_gateway",
+        "id" : 209
+    },
+    {
+        "name" : "minecraft:end_portal",
+        "id" : 119
+    },
+    {
+        "name" : "minecraft:end_portal_frame",
+        "id" : 120
+    },
+    {
+        "name" : "minecraft:end_rod",
+        "id" : 208
+    },
+    {
+        "name" : "minecraft:end_stone",
+        "id" : 121
+    },
+    {
+        "name" : "minecraft:ender_chest",
+        "id" : 130
+    },
+    {
+        "name" : "minecraft:ender_dragon_spawn_egg",
+        "id" : 507
+    },
+    {
+        "name" : "minecraft:ender_eye",
+        "id" : 434
+    },
+    {
+        "name" : "minecraft:ender_pearl",
+        "id" : 423
+    },
+    {
+        "name" : "minecraft:enderman_spawn_egg",
+        "id" : 443
+    },
+    {
+        "name" : "minecraft:endermite_spawn_egg",
+        "id" : 461
+    },
+    {
+        "name" : "minecraft:evoker_spawn_egg",
+        "id" : 476
+    },
+    {
+        "name" : "minecraft:experience_bottle",
+        "id" : 514
+    },
+    {
+        "name" : "minecraft:exposed_copper",
+        "id" : -341
+    },
+    {
+        "name" : "minecraft:exposed_cut_copper",
+        "id" : -348
+    },
+    {
+        "name" : "minecraft:exposed_cut_copper_slab",
+        "id" : -362
+    },
+    {
+        "name" : "minecraft:exposed_cut_copper_stairs",
+        "id" : -355
+    },
+    {
+        "name" : "minecraft:exposed_double_cut_copper_slab",
+        "id" : -369
+    },
+    {
+        "name" : "minecraft:farmland",
+        "id" : 60
+    },
+    {
+        "name" : "minecraft:feather",
+        "id" : 328
+    },
+    {
+        "name" : "minecraft:fence",
+        "id" : 85
+    },
+    {
+        "name" : "minecraft:fence_gate",
+        "id" : 107
+    },
+    {
+        "name" : "minecraft:fermented_spider_eye",
+        "id" : 429
+    },
+    {
+        "name" : "minecraft:field_masoned_banner_pattern",
+        "id" : 591
+    },
+    {
+        "name" : "minecraft:filled_map",
+        "id" : 421
+    },
+    {
+        "name" : "minecraft:fire",
+        "id" : 51
+    },
+    {
+        "name" : "minecraft:fire_charge",
+        "id" : 515
+    },
+    {
+        "name" : "minecraft:firework_rocket",
+        "id" : 525
+    },
+    {
+        "name" : "minecraft:firework_star",
+        "id" : 526
+    },
+    {
+        "name" : "minecraft:fishing_rod",
+        "id" : 393
+    },
+    {
+        "name" : "minecraft:fletching_table",
+        "id" : -201
+    },
+    {
+        "name" : "minecraft:flint",
+        "id" : 357
+    },
+    {
+        "name" : "minecraft:flint_and_steel",
+        "id" : 300
+    },
+    {
+        "name" : "minecraft:flower_banner_pattern",
+        "id" : 587
+    },
+    {
+        "name" : "minecraft:flower_pot",
+        "id" : 520
+    },
+    {
+        "name" : "minecraft:flowering_azalea",
+        "id" : -338
+    },
+    {
+        "name" : "minecraft:flowing_lava",
+        "id" : 10
+    },
+    {
+        "name" : "minecraft:flowing_water",
+        "id" : 8
+    },
+    {
+        "name" : "minecraft:fox_spawn_egg",
+        "id" : 491
+    },
+    {
+        "name" : "minecraft:frame",
+        "id" : 519
+    },
+    {
+        "name" : "minecraft:frog_spawn",
+        "id" : -468
+    },
+    {
+        "name" : "minecraft:frog_spawn_egg",
+        "id" : 634
+    },
+    {
+        "name" : "minecraft:frosted_ice",
+        "id" : 207
+    },
+    {
+        "name" : "minecraft:furnace",
+        "id" : 61
+    },
+    {
+        "name" : "minecraft:ghast_spawn_egg",
+        "id" : 455
+    },
+    {
+        "name" : "minecraft:ghast_tear",
+        "id" : 425
+    },
+    {
+        "name" : "minecraft:gilded_blackstone",
+        "id" : -281
+    },
+    {
+        "name" : "minecraft:glass",
+        "id" : 20
+    },
+    {
+        "name" : "minecraft:glass_bottle",
+        "id" : 428
+    },
+    {
+        "name" : "minecraft:glass_pane",
+        "id" : 102
+    },
+    {
+        "name" : "minecraft:glistering_melon_slice",
+        "id" : 435
+    },
+    {
+        "name" : "minecraft:globe_banner_pattern",
+        "id" : 594
+    },
+    {
+        "name" : "minecraft:glow_berries",
+        "id" : 670
+    },
+    {
+        "name" : "minecraft:glow_frame",
+        "id" : 629
+    },
+    {
+        "name" : "minecraft:glow_ink_sac",
+        "id" : 509
+    },
+    {
+        "name" : "minecraft:glow_lichen",
+        "id" : -411
+    },
+    {
+        "name" : "minecraft:glow_squid_spawn_egg",
+        "id" : 504
+    },
+    {
+        "name" : "minecraft:glow_stick",
+        "id" : 607
+    },
+    {
+        "name" : "minecraft:glowingobsidian",
+        "id" : 246
+    },
+    {
+        "name" : "minecraft:glowstone",
+        "id" : 89
+    },
+    {
+        "name" : "minecraft:glowstone_dust",
+        "id" : 395
+    },
+    {
+        "name" : "minecraft:goat_horn",
+        "id" : 633
+    },
+    {
+        "name" : "minecraft:goat_spawn_egg",
+        "id" : 503
+    },
+    {
+        "name" : "minecraft:gold_block",
+        "id" : 41
+    },
+    {
+        "name" : "minecraft:gold_ingot",
+        "id" : 307
+    },
+    {
+        "name" : "minecraft:gold_nugget",
+        "id" : 426
+    },
+    {
+        "name" : "minecraft:gold_ore",
+        "id" : 14
+    },
+    {
+        "name" : "minecraft:golden_apple",
+        "id" : 258
+    },
+    {
+        "name" : "minecraft:golden_axe",
+        "id" : 326
+    },
+    {
+        "name" : "minecraft:golden_boots",
+        "id" : 355
+    },
+    {
+        "name" : "minecraft:golden_carrot",
+        "id" : 283
+    },
+    {
+        "name" : "minecraft:golden_chestplate",
+        "id" : 353
+    },
+    {
+        "name" : "minecraft:golden_helmet",
+        "id" : 352
+    },
+    {
+        "name" : "minecraft:golden_hoe",
+        "id" : 334
+    },
+    {
+        "name" : "minecraft:golden_horse_armor",
+        "id" : 538
+    },
+    {
+        "name" : "minecraft:golden_leggings",
+        "id" : 354
+    },
+    {
+        "name" : "minecraft:golden_pickaxe",
+        "id" : 325
+    },
+    {
+        "name" : "minecraft:golden_rail",
+        "id" : 27
+    },
+    {
+        "name" : "minecraft:golden_shovel",
+        "id" : 324
+    },
+    {
+        "name" : "minecraft:golden_sword",
+        "id" : 323
+    },
+    {
+        "name" : "minecraft:granite_stairs",
+        "id" : -169
+    },
+    {
+        "name" : "minecraft:grass",
+        "id" : 2
+    },
+    {
+        "name" : "minecraft:grass_path",
+        "id" : 198
+    },
+    {
+        "name" : "minecraft:gravel",
+        "id" : 13
+    },
+    {
+        "name" : "minecraft:gray_candle",
+        "id" : -420
+    },
+    {
+        "name" : "minecraft:gray_candle_cake",
+        "id" : -437
+    },
+    {
+        "name" : "minecraft:gray_dye",
+        "id" : 404
+    },
+    {
+        "name" : "minecraft:gray_glazed_terracotta",
+        "id" : 227
+    },
+    {
+        "name" : "minecraft:gray_wool",
+        "id" : -553
+    },
+    {
+        "name" : "minecraft:green_candle",
+        "id" : -426
+    },
+    {
+        "name" : "minecraft:green_candle_cake",
+        "id" : -443
+    },
+    {
+        "name" : "minecraft:green_dye",
+        "id" : 398
+    },
+    {
+        "name" : "minecraft:green_glazed_terracotta",
+        "id" : 233
+    },
+    {
+        "name" : "minecraft:green_wool",
+        "id" : -560
+    },
+    {
+        "name" : "minecraft:grindstone",
+        "id" : -195
+    },
+    {
+        "name" : "minecraft:guardian_spawn_egg",
+        "id" : 462
+    },
+    {
+        "name" : "minecraft:gunpowder",
+        "id" : 329
+    },
+    {
+        "name" : "minecraft:hanging_roots",
+        "id" : -319
+    },
+    {
+        "name" : "minecraft:hard_glass",
+        "id" : 253
+    },
+    {
+        "name" : "minecraft:hard_glass_pane",
+        "id" : 190
+    },
+    {
+        "name" : "minecraft:hard_stained_glass",
+        "id" : 254
+    },
+    {
+        "name" : "minecraft:hard_stained_glass_pane",
+        "id" : 191
+    },
+    {
+        "name" : "minecraft:hardened_clay",
+        "id" : 172
+    },
+    {
+        "name" : "minecraft:hay_block",
+        "id" : 170
+    },
+    {
+        "name" : "minecraft:heart_of_the_sea",
+        "id" : 577
+    },
+    {
+        "name" : "minecraft:heavy_weighted_pressure_plate",
+        "id" : 148
+    },
+    {
+        "name" : "minecraft:hoglin_spawn_egg",
+        "id" : 497
+    },
+    {
+        "name" : "minecraft:honey_block",
+        "id" : -220
+    },
+    {
+        "name" : "minecraft:honey_bottle",
+        "id" : 598
+    },
+    {
+        "name" : "minecraft:honeycomb",
+        "id" : 597
+    },
+    {
+        "name" : "minecraft:honeycomb_block",
+        "id" : -221
+    },
+    {
+        "name" : "minecraft:hopper",
+        "id" : 533
+    },
+    {
+        "name" : "minecraft:hopper_minecart",
+        "id" : 532
+    },
+    {
+        "name" : "minecraft:horse_spawn_egg",
+        "id" : 459
+    },
+    {
+        "name" : "minecraft:husk_spawn_egg",
+        "id" : 464
+    },
+    {
+        "name" : "minecraft:ice",
+        "id" : 79
+    },
+    {
+        "name" : "minecraft:ice_bomb",
+        "id" : 601
+    },
+    {
+        "name" : "minecraft:infested_deepslate",
+        "id" : -454
+    },
+    {
+        "name" : "minecraft:info_update",
+        "id" : 248
+    },
+    {
+        "name" : "minecraft:info_update2",
+        "id" : 249
+    },
+    {
+        "name" : "minecraft:ink_sac",
+        "id" : 414
+    },
+    {
+        "name" : "minecraft:invisible_bedrock",
+        "id" : 95
+    },
+    {
+        "name" : "minecraft:iron_axe",
+        "id" : 299
+    },
+    {
+        "name" : "minecraft:iron_bars",
+        "id" : 101
+    },
+    {
+        "name" : "minecraft:iron_block",
+        "id" : 42
+    },
+    {
+        "name" : "minecraft:iron_boots",
+        "id" : 347
+    },
+    {
+        "name" : "minecraft:iron_chestplate",
+        "id" : 345
+    },
+    {
+        "name" : "minecraft:iron_door",
+        "id" : 373
+    },
+    {
+        "name" : "minecraft:iron_golem_spawn_egg",
+        "id" : 505
+    },
+    {
+        "name" : "minecraft:iron_helmet",
+        "id" : 344
+    },
+    {
+        "name" : "minecraft:iron_hoe",
+        "id" : 332
+    },
+    {
+        "name" : "minecraft:iron_horse_armor",
+        "id" : 537
+    },
+    {
+        "name" : "minecraft:iron_ingot",
+        "id" : 306
+    },
+    {
+        "name" : "minecraft:iron_leggings",
+        "id" : 346
+    },
+    {
+        "name" : "minecraft:iron_nugget",
+        "id" : 575
+    },
+    {
+        "name" : "minecraft:iron_ore",
+        "id" : 15
+    },
+    {
+        "name" : "minecraft:iron_pickaxe",
+        "id" : 298
+    },
+    {
+        "name" : "minecraft:iron_shovel",
+        "id" : 297
+    },
+    {
+        "name" : "minecraft:iron_sword",
+        "id" : 308
+    },
+    {
+        "name" : "minecraft:iron_trapdoor",
+        "id" : 167
+    },
+    {
+        "name" : "minecraft:item.acacia_door",
+        "id" : 196
+    },
+    {
+        "name" : "minecraft:item.bed",
+        "id" : 26
+    },
+    {
+        "name" : "minecraft:item.beetroot",
+        "id" : 244
+    },
+    {
+        "name" : "minecraft:item.birch_door",
+        "id" : 194
+    },
+    {
+        "name" : "minecraft:item.brewing_stand",
+        "id" : 117
+    },
+    {
+        "name" : "minecraft:item.cake",
+        "id" : 92
+    },
+    {
+        "name" : "minecraft:item.camera",
+        "id" : 242
+    },
+    {
+        "name" : "minecraft:item.campfire",
+        "id" : -209
+    },
+    {
+        "name" : "minecraft:item.cauldron",
+        "id" : 118
+    },
+    {
+        "name" : "minecraft:item.chain",
+        "id" : -286
+    },
+    {
+        "name" : "minecraft:item.crimson_door",
+        "id" : -244
+    },
+    {
+        "name" : "minecraft:item.dark_oak_door",
+        "id" : 197
+    },
+    {
+        "name" : "minecraft:item.flower_pot",
+        "id" : 140
+    },
+    {
+        "name" : "minecraft:item.frame",
+        "id" : 199
+    },
+    {
+        "name" : "minecraft:item.glow_frame",
+        "id" : -339
+    },
+    {
+        "name" : "minecraft:item.hopper",
+        "id" : 154
+    },
+    {
+        "name" : "minecraft:item.iron_door",
+        "id" : 71
+    },
+    {
+        "name" : "minecraft:item.jungle_door",
+        "id" : 195
+    },
+    {
+        "name" : "minecraft:item.kelp",
+        "id" : -138
+    },
+    {
+        "name" : "minecraft:item.mangrove_door",
+        "id" : -493
+    },
+    {
+        "name" : "minecraft:item.nether_sprouts",
+        "id" : -238
+    },
+    {
+        "name" : "minecraft:item.nether_wart",
+        "id" : 115
+    },
+    {
+        "name" : "minecraft:item.reeds",
+        "id" : 83
+    },
+    {
+        "name" : "minecraft:item.skull",
+        "id" : 144
+    },
+    {
+        "name" : "minecraft:item.soul_campfire",
+        "id" : -290
+    },
+    {
+        "name" : "minecraft:item.spruce_door",
+        "id" : 193
+    },
+    {
+        "name" : "minecraft:item.warped_door",
+        "id" : -245
+    },
+    {
+        "name" : "minecraft:item.wheat",
+        "id" : 59
+    },
+    {
+        "name" : "minecraft:item.wooden_door",
+        "id" : 64
+    },
+    {
+        "name" : "minecraft:jigsaw",
+        "id" : -211
+    },
+    {
+        "name" : "minecraft:jukebox",
+        "id" : 84
+    },
+    {
+        "name" : "minecraft:jungle_boat",
+        "id" : 378
+    },
+    {
+        "name" : "minecraft:jungle_button",
+        "id" : -143
+    },
+    {
+        "name" : "minecraft:jungle_chest_boat",
+        "id" : 646
+    },
+    {
+        "name" : "minecraft:jungle_door",
+        "id" : 561
+    },
+    {
+        "name" : "minecraft:jungle_fence_gate",
+        "id" : 185
+    },
+    {
+        "name" : "minecraft:jungle_hanging_sign",
+        "id" : -503
+    },
+    {
+        "name" : "minecraft:jungle_pressure_plate",
+        "id" : -153
+    },
+    {
+        "name" : "minecraft:jungle_sign",
+        "id" : 584
+    },
+    {
+        "name" : "minecraft:jungle_stairs",
+        "id" : 136
+    },
+    {
+        "name" : "minecraft:jungle_standing_sign",
+        "id" : -188
+    },
+    {
+        "name" : "minecraft:jungle_trapdoor",
+        "id" : -148
+    },
+    {
+        "name" : "minecraft:jungle_wall_sign",
+        "id" : -189
+    },
+    {
+        "name" : "minecraft:kelp",
+        "id" : 383
+    },
+    {
+        "name" : "minecraft:ladder",
+        "id" : 65
+    },
+    {
+        "name" : "minecraft:lantern",
+        "id" : -208
+    },
+    {
+        "name" : "minecraft:lapis_block",
+        "id" : 22
+    },
+    {
+        "name" : "minecraft:lapis_lazuli",
+        "id" : 415
+    },
+    {
+        "name" : "minecraft:lapis_ore",
+        "id" : 21
+    },
+    {
+        "name" : "minecraft:large_amethyst_bud",
+        "id" : -330
+    },
+    {
+        "name" : "minecraft:lava",
+        "id" : 11
+    },
+    {
+        "name" : "minecraft:lava_bucket",
+        "id" : 364
+    },
+    {
+        "name" : "minecraft:lava_cauldron",
+        "id" : -210
+    },
+    {
+        "name" : "minecraft:lead",
+        "id" : 553
+    },
+    {
+        "name" : "minecraft:leather",
+        "id" : 382
+    },
+    {
+        "name" : "minecraft:leather_boots",
+        "id" : 339
+    },
+    {
+        "name" : "minecraft:leather_chestplate",
+        "id" : 337
+    },
+    {
+        "name" : "minecraft:leather_helmet",
+        "id" : 336
+    },
+    {
+        "name" : "minecraft:leather_horse_armor",
+        "id" : 536
+    },
+    {
+        "name" : "minecraft:leather_leggings",
+        "id" : 338
+    },
+    {
+        "name" : "minecraft:leaves",
+        "id" : 18
+    },
+    {
+        "name" : "minecraft:leaves2",
+        "id" : 161
+    },
+    {
+        "name" : "minecraft:lectern",
+        "id" : -194
+    },
+    {
+        "name" : "minecraft:lever",
+        "id" : 69
+    },
+    {
+        "name" : "minecraft:light_block",
+        "id" : -215
+    },
+    {
+        "name" : "minecraft:light_blue_candle",
+        "id" : -416
+    },
+    {
+        "name" : "minecraft:light_blue_candle_cake",
+        "id" : -433
+    },
+    {
+        "name" : "minecraft:light_blue_dye",
+        "id" : 408
+    },
+    {
+        "name" : "minecraft:light_blue_glazed_terracotta",
+        "id" : 223
+    },
+    {
+        "name" : "minecraft:light_blue_wool",
+        "id" : -562
+    },
+    {
+        "name" : "minecraft:light_gray_candle",
+        "id" : -421
+    },
+    {
+        "name" : "minecraft:light_gray_candle_cake",
+        "id" : -438
+    },
+    {
+        "name" : "minecraft:light_gray_dye",
+        "id" : 403
+    },
+    {
+        "name" : "minecraft:light_gray_wool",
+        "id" : -552
+    },
+    {
+        "name" : "minecraft:light_weighted_pressure_plate",
+        "id" : 147
+    },
+    {
+        "name" : "minecraft:lightning_rod",
+        "id" : -312
+    },
+    {
+        "name" : "minecraft:lime_candle",
+        "id" : -418
+    },
+    {
+        "name" : "minecraft:lime_candle_cake",
+        "id" : -435
+    },
+    {
+        "name" : "minecraft:lime_dye",
+        "id" : 406
+    },
+    {
+        "name" : "minecraft:lime_glazed_terracotta",
+        "id" : 225
+    },
+    {
+        "name" : "minecraft:lime_wool",
+        "id" : -559
+    },
+    {
+        "name" : "minecraft:lingering_potion",
+        "id" : 568
+    },
+    {
+        "name" : "minecraft:lit_blast_furnace",
+        "id" : -214
+    },
+    {
+        "name" : "minecraft:lit_deepslate_redstone_ore",
+        "id" : -404
+    },
+    {
+        "name" : "minecraft:lit_furnace",
+        "id" : 62
+    },
+    {
+        "name" : "minecraft:lit_pumpkin",
+        "id" : 91
+    },
+    {
+        "name" : "minecraft:lit_redstone_lamp",
+        "id" : 124
+    },
+    {
+        "name" : "minecraft:lit_redstone_ore",
+        "id" : 74
+    },
+    {
+        "name" : "minecraft:lit_smoker",
+        "id" : -199
+    },
+    {
+        "name" : "minecraft:llama_spawn_egg",
+        "id" : 474
+    },
+    {
+        "name" : "minecraft:lodestone",
+        "id" : -222
+    },
+    {
+        "name" : "minecraft:lodestone_compass",
+        "id" : 608
+    },
+    {
+        "name" : "minecraft:log",
+        "id" : 17
+    },
+    {
+        "name" : "minecraft:log2",
+        "id" : 162
+    },
+    {
+        "name" : "minecraft:loom",
+        "id" : -204
+    },
+    {
+        "name" : "minecraft:magenta_candle",
+        "id" : -415
+    },
+    {
+        "name" : "minecraft:magenta_candle_cake",
+        "id" : -432
+    },
+    {
+        "name" : "minecraft:magenta_dye",
+        "id" : 409
+    },
+    {
+        "name" : "minecraft:magenta_glazed_terracotta",
+        "id" : 222
+    },
+    {
+        "name" : "minecraft:magenta_wool",
+        "id" : -565
+    },
+    {
+        "name" : "minecraft:magma",
+        "id" : 213
+    },
+    {
+        "name" : "minecraft:magma_cream",
+        "id" : 431
+    },
+    {
+        "name" : "minecraft:magma_cube_spawn_egg",
+        "id" : 456
+    },
+    {
+        "name" : "minecraft:mangrove_boat",
+        "id" : 641
+    },
+    {
+        "name" : "minecraft:mangrove_button",
+        "id" : -487
+    },
+    {
+        "name" : "minecraft:mangrove_chest_boat",
+        "id" : 650
+    },
+    {
+        "name" : "minecraft:mangrove_door",
+        "id" : 639
+    },
+    {
+        "name" : "minecraft:mangrove_double_slab",
+        "id" : -499
+    },
+    {
+        "name" : "minecraft:mangrove_fence",
+        "id" : -491
+    },
+    {
+        "name" : "minecraft:mangrove_fence_gate",
+        "id" : -492
+    },
+    {
+        "name" : "minecraft:mangrove_hanging_sign",
+        "id" : -508
+    },
+    {
+        "name" : "minecraft:mangrove_leaves",
+        "id" : -472
+    },
+    {
+        "name" : "minecraft:mangrove_log",
+        "id" : -484
+    },
+    {
+        "name" : "minecraft:mangrove_planks",
+        "id" : -486
+    },
+    {
+        "name" : "minecraft:mangrove_pressure_plate",
+        "id" : -490
+    },
+    {
+        "name" : "minecraft:mangrove_propagule",
+        "id" : -474
+    },
+    {
+        "name" : "minecraft:mangrove_roots",
+        "id" : -482
+    },
+    {
+        "name" : "minecraft:mangrove_sign",
+        "id" : 640
+    },
+    {
+        "name" : "minecraft:mangrove_slab",
+        "id" : -489
+    },
+    {
+        "name" : "minecraft:mangrove_stairs",
+        "id" : -488
+    },
+    {
+        "name" : "minecraft:mangrove_standing_sign",
+        "id" : -494
+    },
+    {
+        "name" : "minecraft:mangrove_trapdoor",
+        "id" : -496
+    },
+    {
+        "name" : "minecraft:mangrove_wall_sign",
+        "id" : -495
+    },
+    {
+        "name" : "minecraft:mangrove_wood",
+        "id" : -497
+    },
+    {
+        "name" : "minecraft:medicine",
+        "id" : 605
+    },
+    {
+        "name" : "minecraft:medium_amethyst_bud",
+        "id" : -331
+    },
+    {
+        "name" : "minecraft:melon_block",
+        "id" : 103
+    },
+    {
+        "name" : "minecraft:melon_seeds",
+        "id" : 293
+    },
+    {
+        "name" : "minecraft:melon_slice",
+        "id" : 272
+    },
+    {
+        "name" : "minecraft:melon_stem",
+        "id" : 105
+    },
+    {
+        "name" : "minecraft:milk_bucket",
+        "id" : 362
+    },
+    {
+        "name" : "minecraft:minecart",
+        "id" : 371
+    },
+    {
+        "name" : "minecraft:mob_spawner",
+        "id" : 52
+    },
+    {
+        "name" : "minecraft:mojang_banner_pattern",
+        "id" : 590
+    },
+    {
+        "name" : "minecraft:monster_egg",
+        "id" : 97
+    },
+    {
+        "name" : "minecraft:mooshroom_spawn_egg",
+        "id" : 441
+    },
+    {
+        "name" : "minecraft:moss_block",
+        "id" : -320
+    },
+    {
+        "name" : "minecraft:moss_carpet",
+        "id" : -335
+    },
+    {
+        "name" : "minecraft:mossy_cobblestone",
+        "id" : 48
+    },
+    {
+        "name" : "minecraft:mossy_cobblestone_stairs",
+        "id" : -179
+    },
+    {
+        "name" : "minecraft:mossy_stone_brick_stairs",
+        "id" : -175
+    },
+    {
+        "name" : "minecraft:moving_block",
+        "id" : 250
+    },
+    {
+        "name" : "minecraft:mud",
+        "id" : -473
+    },
+    {
+        "name" : "minecraft:mud_brick_double_slab",
+        "id" : -479
+    },
+    {
+        "name" : "minecraft:mud_brick_slab",
+        "id" : -478
+    },
+    {
+        "name" : "minecraft:mud_brick_stairs",
+        "id" : -480
+    },
+    {
+        "name" : "minecraft:mud_brick_wall",
+        "id" : -481
+    },
+    {
+        "name" : "minecraft:mud_bricks",
+        "id" : -475
+    },
+    {
+        "name" : "minecraft:muddy_mangrove_roots",
+        "id" : -483
+    },
+    {
+        "name" : "minecraft:mule_spawn_egg",
+        "id" : 467
+    },
+    {
+        "name" : "minecraft:mushroom_stew",
+        "id" : 260
+    },
+    {
+        "name" : "minecraft:music_disc_11",
+        "id" : 550
+    },
+    {
+        "name" : "minecraft:music_disc_13",
+        "id" : 540
+    },
+    {
+        "name" : "minecraft:music_disc_5",
+        "id" : 642
+    },
+    {
+        "name" : "minecraft:music_disc_blocks",
+        "id" : 542
+    },
+    {
+        "name" : "minecraft:music_disc_cat",
+        "id" : 541
+    },
+    {
+        "name" : "minecraft:music_disc_chirp",
+        "id" : 543
+    },
+    {
+        "name" : "minecraft:music_disc_far",
+        "id" : 544
+    },
+    {
+        "name" : "minecraft:music_disc_mall",
+        "id" : 545
+    },
+    {
+        "name" : "minecraft:music_disc_mellohi",
+        "id" : 546
+    },
+    {
+        "name" : "minecraft:music_disc_otherside",
+        "id" : 632
+    },
+    {
+        "name" : "minecraft:music_disc_pigstep",
+        "id" : 626
+    },
+    {
+        "name" : "minecraft:music_disc_stal",
+        "id" : 547
+    },
+    {
+        "name" : "minecraft:music_disc_strad",
+        "id" : 548
+    },
+    {
+        "name" : "minecraft:music_disc_wait",
+        "id" : 551
+    },
+    {
+        "name" : "minecraft:music_disc_ward",
+        "id" : 549
+    },
+    {
+        "name" : "minecraft:mutton",
+        "id" : 556
+    },
+    {
+        "name" : "minecraft:mycelium",
+        "id" : 110
+    },
+    {
+        "name" : "minecraft:name_tag",
+        "id" : 554
+    },
+    {
+        "name" : "minecraft:nautilus_shell",
+        "id" : 576
+    },
+    {
+        "name" : "minecraft:nether_brick",
+        "id" : 112
+    },
+    {
+        "name" : "minecraft:nether_brick_fence",
+        "id" : 113
+    },
+    {
+        "name" : "minecraft:nether_brick_stairs",
+        "id" : 114
+    },
+    {
+        "name" : "minecraft:nether_gold_ore",
+        "id" : -288
+    },
+    {
+        "name" : "minecraft:nether_sprouts",
+        "id" : 627
+    },
+    {
+        "name" : "minecraft:nether_star",
+        "id" : 524
+    },
+    {
+        "name" : "minecraft:nether_wart",
+        "id" : 294
+    },
+    {
+        "name" : "minecraft:nether_wart_block",
+        "id" : 214
+    },
+    {
+        "name" : "minecraft:netherbrick",
+        "id" : 529
+    },
+    {
+        "name" : "minecraft:netherite_axe",
+        "id" : 613
+    },
+    {
+        "name" : "minecraft:netherite_block",
+        "id" : -270
+    },
+    {
+        "name" : "minecraft:netherite_boots",
+        "id" : 618
+    },
+    {
+        "name" : "minecraft:netherite_chestplate",
+        "id" : 616
+    },
+    {
+        "name" : "minecraft:netherite_helmet",
+        "id" : 615
+    },
+    {
+        "name" : "minecraft:netherite_hoe",
+        "id" : 614
+    },
+    {
+        "name" : "minecraft:netherite_ingot",
+        "id" : 609
+    },
+    {
+        "name" : "minecraft:netherite_leggings",
+        "id" : 617
+    },
+    {
+        "name" : "minecraft:netherite_pickaxe",
+        "id" : 612
+    },
+    {
+        "name" : "minecraft:netherite_scrap",
+        "id" : 619
+    },
+    {
+        "name" : "minecraft:netherite_shovel",
+        "id" : 611
+    },
+    {
+        "name" : "minecraft:netherite_sword",
+        "id" : 610
+    },
+    {
+        "name" : "minecraft:netherrack",
+        "id" : 87
+    },
+    {
+        "name" : "minecraft:netherreactor",
+        "id" : 247
+    },
+    {
+        "name" : "minecraft:normal_stone_stairs",
+        "id" : -180
+    },
+    {
+        "name" : "minecraft:noteblock",
+        "id" : 25
+    },
+    {
+        "name" : "minecraft:npc_spawn_egg",
+        "id" : 471
+    },
+    {
+        "name" : "minecraft:oak_boat",
+        "id" : 376
+    },
+    {
+        "name" : "minecraft:oak_chest_boat",
+        "id" : 644
+    },
+    {
+        "name" : "minecraft:oak_hanging_sign",
+        "id" : -500
+    },
+    {
+        "name" : "minecraft:oak_sign",
+        "id" : 359
+    },
+    {
+        "name" : "minecraft:oak_stairs",
+        "id" : 53
+    },
+    {
+        "name" : "minecraft:observer",
+        "id" : 251
+    },
+    {
+        "name" : "minecraft:obsidian",
+        "id" : 49
+    },
+    {
+        "name" : "minecraft:ocelot_spawn_egg",
+        "id" : 452
+    },
+    {
+        "name" : "minecraft:ochre_froglight",
+        "id" : -471
+    },
+    {
+        "name" : "minecraft:orange_candle",
+        "id" : -414
+    },
+    {
+        "name" : "minecraft:orange_candle_cake",
+        "id" : -431
+    },
+    {
+        "name" : "minecraft:orange_dye",
+        "id" : 410
+    },
+    {
+        "name" : "minecraft:orange_glazed_terracotta",
+        "id" : 221
+    },
+    {
+        "name" : "minecraft:orange_wool",
+        "id" : -557
+    },
+    {
+        "name" : "minecraft:oxidized_copper",
+        "id" : -343
+    },
+    {
+        "name" : "minecraft:oxidized_cut_copper",
+        "id" : -350
+    },
+    {
+        "name" : "minecraft:oxidized_cut_copper_slab",
+        "id" : -364
+    },
+    {
+        "name" : "minecraft:oxidized_cut_copper_stairs",
+        "id" : -357
+    },
+    {
+        "name" : "minecraft:oxidized_double_cut_copper_slab",
+        "id" : -371
+    },
+    {
+        "name" : "minecraft:packed_ice",
+        "id" : 174
+    },
+    {
+        "name" : "minecraft:packed_mud",
+        "id" : -477
+    },
+    {
+        "name" : "minecraft:painting",
+        "id" : 358
+    },
+    {
+        "name" : "minecraft:panda_spawn_egg",
+        "id" : 490
+    },
+    {
+        "name" : "minecraft:paper",
+        "id" : 387
+    },
+    {
+        "name" : "minecraft:parrot_spawn_egg",
+        "id" : 479
+    },
+    {
+        "name" : "minecraft:pearlescent_froglight",
+        "id" : -469
+    },
+    {
+        "name" : "minecraft:phantom_membrane",
+        "id" : 580
+    },
+    {
+        "name" : "minecraft:phantom_spawn_egg",
+        "id" : 487
+    },
+    {
+        "name" : "minecraft:pig_spawn_egg",
+        "id" : 438
+    },
+    {
+        "name" : "minecraft:piglin_banner_pattern",
+        "id" : 593
+    },
+    {
+        "name" : "minecraft:piglin_brute_spawn_egg",
+        "id" : 500
+    },
+    {
+        "name" : "minecraft:piglin_spawn_egg",
+        "id" : 498
+    },
+    {
+        "name" : "minecraft:pillager_spawn_egg",
+        "id" : 492
+    },
+    {
+        "name" : "minecraft:pink_candle",
+        "id" : -419
+    },
+    {
+        "name" : "minecraft:pink_candle_cake",
+        "id" : -436
+    },
+    {
+        "name" : "minecraft:pink_dye",
+        "id" : 405
+    },
+    {
+        "name" : "minecraft:pink_glazed_terracotta",
+        "id" : 226
+    },
+    {
+        "name" : "minecraft:pink_wool",
+        "id" : -566
+    },
+    {
+        "name" : "minecraft:piston",
+        "id" : 33
+    },
+    {
+        "name" : "minecraft:piston_arm_collision",
+        "id" : 34
+    },
+    {
+        "name" : "minecraft:planks",
+        "id" : 5
+    },
+    {
+        "name" : "minecraft:podzol",
+        "id" : 243
+    },
+    {
+        "name" : "minecraft:pointed_dripstone",
+        "id" : -308
+    },
+    {
+        "name" : "minecraft:poisonous_potato",
+        "id" : 282
+    },
+    {
+        "name" : "minecraft:polar_bear_spawn_egg",
+        "id" : 473
+    },
+    {
+        "name" : "minecraft:polished_andesite_stairs",
+        "id" : -174
+    },
+    {
+        "name" : "minecraft:polished_basalt",
+        "id" : -235
+    },
+    {
+        "name" : "minecraft:polished_blackstone",
+        "id" : -291
+    },
+    {
+        "name" : "minecraft:polished_blackstone_brick_double_slab",
+        "id" : -285
+    },
+    {
+        "name" : "minecraft:polished_blackstone_brick_slab",
+        "id" : -284
+    },
+    {
+        "name" : "minecraft:polished_blackstone_brick_stairs",
+        "id" : -275
+    },
+    {
+        "name" : "minecraft:polished_blackstone_brick_wall",
+        "id" : -278
+    },
+    {
+        "name" : "minecraft:polished_blackstone_bricks",
+        "id" : -274
+    },
+    {
+        "name" : "minecraft:polished_blackstone_button",
+        "id" : -296
+    },
+    {
+        "name" : "minecraft:polished_blackstone_double_slab",
+        "id" : -294
+    },
+    {
+        "name" : "minecraft:polished_blackstone_pressure_plate",
+        "id" : -295
+    },
+    {
+        "name" : "minecraft:polished_blackstone_slab",
+        "id" : -293
+    },
+    {
+        "name" : "minecraft:polished_blackstone_stairs",
+        "id" : -292
+    },
+    {
+        "name" : "minecraft:polished_blackstone_wall",
+        "id" : -297
+    },
+    {
+        "name" : "minecraft:polished_deepslate",
+        "id" : -383
+    },
+    {
+        "name" : "minecraft:polished_deepslate_double_slab",
+        "id" : -397
+    },
+    {
+        "name" : "minecraft:polished_deepslate_slab",
+        "id" : -384
+    },
+    {
+        "name" : "minecraft:polished_deepslate_stairs",
+        "id" : -385
+    },
+    {
+        "name" : "minecraft:polished_deepslate_wall",
+        "id" : -386
+    },
+    {
+        "name" : "minecraft:polished_diorite_stairs",
+        "id" : -173
+    },
+    {
+        "name" : "minecraft:polished_granite_stairs",
+        "id" : -172
+    },
+    {
+        "name" : "minecraft:popped_chorus_fruit",
+        "id" : 565
+    },
+    {
+        "name" : "minecraft:porkchop",
+        "id" : 262
+    },
+    {
+        "name" : "minecraft:portal",
+        "id" : 90
+    },
+    {
+        "name" : "minecraft:potato",
+        "id" : 280
+    },
+    {
+        "name" : "minecraft:potatoes",
+        "id" : 142
+    },
+    {
+        "name" : "minecraft:potion",
+        "id" : 427
+    },
+    {
+        "name" : "minecraft:powder_snow",
+        "id" : -306
+    },
+    {
+        "name" : "minecraft:powder_snow_bucket",
+        "id" : 369
+    },
+    {
+        "name" : "minecraft:powered_comparator",
+        "id" : 150
+    },
+    {
+        "name" : "minecraft:powered_repeater",
+        "id" : 94
+    },
+    {
+        "name" : "minecraft:prismarine",
+        "id" : 168
+    },
+    {
+        "name" : "minecraft:prismarine_bricks_stairs",
+        "id" : -4
+    },
+    {
+        "name" : "minecraft:prismarine_crystals",
+        "id" : 555
+    },
+    {
+        "name" : "minecraft:prismarine_shard",
+        "id" : 571
+    },
+    {
+        "name" : "minecraft:prismarine_stairs",
+        "id" : -2
+    },
+    {
+        "name" : "minecraft:prize_pottery_shard",
+        "id" : 661
+    },
+    {
+        "name" : "minecraft:pufferfish",
+        "id" : 267
+    },
+    {
+        "name" : "minecraft:pufferfish_bucket",
+        "id" : 368
+    },
+    {
+        "name" : "minecraft:pufferfish_spawn_egg",
+        "id" : 482
+    },
+    {
+        "name" : "minecraft:pumpkin",
+        "id" : 86
+    },
+    {
+        "name" : "minecraft:pumpkin_pie",
+        "id" : 284
+    },
+    {
+        "name" : "minecraft:pumpkin_seeds",
+        "id" : 292
+    },
+    {
+        "name" : "minecraft:pumpkin_stem",
+        "id" : 104
+    },
+    {
+        "name" : "minecraft:purple_candle",
+        "id" : -423
+    },
+    {
+        "name" : "minecraft:purple_candle_cake",
+        "id" : -440
+    },
+    {
+        "name" : "minecraft:purple_dye",
+        "id" : 401
+    },
+    {
+        "name" : "minecraft:purple_glazed_terracotta",
+        "id" : 219
+    },
+    {
+        "name" : "minecraft:purple_wool",
+        "id" : -564
+    },
+    {
+        "name" : "minecraft:purpur_block",
+        "id" : 201
+    },
+    {
+        "name" : "minecraft:purpur_stairs",
+        "id" : 203
+    },
+    {
+        "name" : "minecraft:quartz",
+        "id" : 530
+    },
+    {
+        "name" : "minecraft:quartz_block",
+        "id" : 155
+    },
+    {
+        "name" : "minecraft:quartz_bricks",
+        "id" : -304
+    },
+    {
+        "name" : "minecraft:quartz_ore",
+        "id" : 153
+    },
+    {
+        "name" : "minecraft:quartz_stairs",
+        "id" : 156
+    },
+    {
+        "name" : "minecraft:rabbit",
+        "id" : 288
+    },
+    {
+        "name" : "minecraft:rabbit_foot",
+        "id" : 534
+    },
+    {
+        "name" : "minecraft:rabbit_hide",
+        "id" : 535
+    },
+    {
+        "name" : "minecraft:rabbit_spawn_egg",
+        "id" : 460
+    },
+    {
+        "name" : "minecraft:rabbit_stew",
+        "id" : 290
+    },
+    {
+        "name" : "minecraft:rail",
+        "id" : 66
+    },
+    {
+        "name" : "minecraft:rapid_fertilizer",
+        "id" : 603
+    },
+    {
+        "name" : "minecraft:ravager_spawn_egg",
+        "id" : 494
+    },
+    {
+        "name" : "minecraft:raw_copper",
+        "id" : 513
+    },
+    {
+        "name" : "minecraft:raw_copper_block",
+        "id" : -452
+    },
+    {
+        "name" : "minecraft:raw_gold",
+        "id" : 512
+    },
+    {
+        "name" : "minecraft:raw_gold_block",
+        "id" : -453
+    },
+    {
+        "name" : "minecraft:raw_iron",
+        "id" : 511
+    },
+    {
+        "name" : "minecraft:raw_iron_block",
+        "id" : -451
+    },
+    {
+        "name" : "minecraft:recovery_compass",
+        "id" : 652
+    },
+    {
+        "name" : "minecraft:red_candle",
+        "id" : -427
+    },
+    {
+        "name" : "minecraft:red_candle_cake",
+        "id" : -444
+    },
+    {
+        "name" : "minecraft:red_dye",
+        "id" : 397
+    },
+    {
+        "name" : "minecraft:red_flower",
+        "id" : 38
+    },
+    {
+        "name" : "minecraft:red_glazed_terracotta",
+        "id" : 234
+    },
+    {
+        "name" : "minecraft:red_mushroom",
+        "id" : 40
+    },
+    {
+        "name" : "minecraft:red_mushroom_block",
+        "id" : 100
+    },
+    {
+        "name" : "minecraft:red_nether_brick",
+        "id" : 215
+    },
+    {
+        "name" : "minecraft:red_nether_brick_stairs",
+        "id" : -184
+    },
+    {
+        "name" : "minecraft:red_sandstone",
+        "id" : 179
+    },
+    {
+        "name" : "minecraft:red_sandstone_stairs",
+        "id" : 180
+    },
+    {
+        "name" : "minecraft:red_wool",
+        "id" : -556
+    },
+    {
+        "name" : "minecraft:redstone",
+        "id" : 374
+    },
+    {
+        "name" : "minecraft:redstone_block",
+        "id" : 152
+    },
+    {
+        "name" : "minecraft:redstone_lamp",
+        "id" : 123
+    },
+    {
+        "name" : "minecraft:redstone_ore",
+        "id" : 73
+    },
+    {
+        "name" : "minecraft:redstone_torch",
+        "id" : 76
+    },
+    {
+        "name" : "minecraft:redstone_wire",
+        "id" : 55
+    },
+    {
+        "name" : "minecraft:reinforced_deepslate",
+        "id" : -466
+    },
+    {
+        "name" : "minecraft:repeater",
+        "id" : 420
+    },
+    {
+        "name" : "minecraft:repeating_command_block",
+        "id" : 188
+    },
+    {
+        "name" : "minecraft:reserved6",
+        "id" : 255
+    },
+    {
+        "name" : "minecraft:respawn_anchor",
+        "id" : -272
+    },
+    {
+        "name" : "minecraft:rotten_flesh",
+        "id" : 277
+    },
+    {
+        "name" : "minecraft:saddle",
+        "id" : 372
+    },
+    {
+        "name" : "minecraft:salmon",
+        "id" : 265
+    },
+    {
+        "name" : "minecraft:salmon_bucket",
+        "id" : 366
+    },
+    {
+        "name" : "minecraft:salmon_spawn_egg",
+        "id" : 483
+    },
+    {
+        "name" : "minecraft:sand",
+        "id" : 12
+    },
+    {
+        "name" : "minecraft:sandstone",
+        "id" : 24
+    },
+    {
+        "name" : "minecraft:sandstone_stairs",
+        "id" : 128
+    },
+    {
+        "name" : "minecraft:sapling",
+        "id" : 6
+    },
+    {
+        "name" : "minecraft:scaffolding",
+        "id" : -165
+    },
+    {
+        "name" : "minecraft:sculk",
+        "id" : -458
+    },
+    {
+        "name" : "minecraft:sculk_catalyst",
+        "id" : -460
+    },
+    {
+        "name" : "minecraft:sculk_sensor",
+        "id" : -307
+    },
+    {
+        "name" : "minecraft:sculk_shrieker",
+        "id" : -461
+    },
+    {
+        "name" : "minecraft:sculk_vein",
+        "id" : -459
+    },
+    {
+        "name" : "minecraft:scute",
+        "id" : 578
+    },
+    {
+        "name" : "minecraft:sea_lantern",
+        "id" : 169
+    },
+    {
+        "name" : "minecraft:sea_pickle",
+        "id" : -156
+    },
+    {
+        "name" : "minecraft:seagrass",
+        "id" : -130
+    },
+    {
+        "name" : "minecraft:shears",
+        "id" : 422
+    },
+    {
+        "name" : "minecraft:sheep_spawn_egg",
+        "id" : 439
+    },
+    {
+        "name" : "minecraft:shield",
+        "id" : 356
+    },
+    {
+        "name" : "minecraft:shroomlight",
+        "id" : -230
+    },
+    {
+        "name" : "minecraft:shulker_box",
+        "id" : 218
+    },
+    {
+        "name" : "minecraft:shulker_shell",
+        "id" : 572
+    },
+    {
+        "name" : "minecraft:shulker_spawn_egg",
+        "id" : 470
+    },
+    {
+        "name" : "minecraft:silver_glazed_terracotta",
+        "id" : 228
+    },
+    {
+        "name" : "minecraft:silverfish_spawn_egg",
+        "id" : 444
+    },
+    {
+        "name" : "minecraft:skeleton_horse_spawn_egg",
+        "id" : 468
+    },
+    {
+        "name" : "minecraft:skeleton_spawn_egg",
+        "id" : 445
+    },
+    {
+        "name" : "minecraft:skull",
+        "id" : 522
+    },
+    {
+        "name" : "minecraft:skull_banner_pattern",
+        "id" : 589
+    },
+    {
+        "name" : "minecraft:skull_pottery_shard",
+        "id" : 662
+    },
+    {
+        "name" : "minecraft:slime",
+        "id" : 165
+    },
+    {
+        "name" : "minecraft:slime_ball",
+        "id" : 389
+    },
+    {
+        "name" : "minecraft:slime_spawn_egg",
+        "id" : 446
+    },
+    {
+        "name" : "minecraft:small_amethyst_bud",
+        "id" : -332
+    },
+    {
+        "name" : "minecraft:small_dripleaf_block",
+        "id" : -336
+    },
+    {
+        "name" : "minecraft:smithing_table",
+        "id" : -202
+    },
+    {
+        "name" : "minecraft:smoker",
+        "id" : -198
+    },
+    {
+        "name" : "minecraft:smooth_basalt",
+        "id" : -377
+    },
+    {
+        "name" : "minecraft:smooth_quartz_stairs",
+        "id" : -185
+    },
+    {
+        "name" : "minecraft:smooth_red_sandstone_stairs",
+        "id" : -176
+    },
+    {
+        "name" : "minecraft:smooth_sandstone_stairs",
+        "id" : -177
+    },
+    {
+        "name" : "minecraft:smooth_stone",
+        "id" : -183
+    },
+    {
+        "name" : "minecraft:sniffer_spawn_egg",
+        "id" : 501
+    },
+    {
+        "name" : "minecraft:snow",
+        "id" : 80
+    },
+    {
+        "name" : "minecraft:snow_golem_spawn_egg",
+        "id" : 506
+    },
+    {
+        "name" : "minecraft:snow_layer",
+        "id" : 78
+    },
+    {
+        "name" : "minecraft:snowball",
+        "id" : 375
+    },
+    {
+        "name" : "minecraft:soul_campfire",
+        "id" : 628
+    },
+    {
+        "name" : "minecraft:soul_fire",
+        "id" : -237
+    },
+    {
+        "name" : "minecraft:soul_lantern",
+        "id" : -269
+    },
+    {
+        "name" : "minecraft:soul_sand",
+        "id" : 88
+    },
+    {
+        "name" : "minecraft:soul_soil",
+        "id" : -236
+    },
+    {
+        "name" : "minecraft:soul_torch",
+        "id" : -268
+    },
+    {
+        "name" : "minecraft:sparkler",
+        "id" : 606
+    },
+    {
+        "name" : "minecraft:spawn_egg",
+        "id" : 668
+    },
+    {
+        "name" : "minecraft:spider_eye",
+        "id" : 278
+    },
+    {
+        "name" : "minecraft:spider_spawn_egg",
+        "id" : 447
+    },
+    {
+        "name" : "minecraft:splash_potion",
+        "id" : 567
+    },
+    {
+        "name" : "minecraft:sponge",
+        "id" : 19
+    },
+    {
+        "name" : "minecraft:spore_blossom",
+        "id" : -321
+    },
+    {
+        "name" : "minecraft:spruce_boat",
+        "id" : 379
+    },
+    {
+        "name" : "minecraft:spruce_button",
+        "id" : -144
+    },
+    {
+        "name" : "minecraft:spruce_chest_boat",
+        "id" : 647
+    },
+    {
+        "name" : "minecraft:spruce_door",
+        "id" : 559
+    },
+    {
+        "name" : "minecraft:spruce_fence_gate",
+        "id" : 183
+    },
+    {
+        "name" : "minecraft:spruce_hanging_sign",
+        "id" : -501
+    },
+    {
+        "name" : "minecraft:spruce_pressure_plate",
+        "id" : -154
+    },
+    {
+        "name" : "minecraft:spruce_sign",
+        "id" : 582
+    },
+    {
+        "name" : "minecraft:spruce_stairs",
+        "id" : 134
+    },
+    {
+        "name" : "minecraft:spruce_standing_sign",
+        "id" : -181
+    },
+    {
+        "name" : "minecraft:spruce_trapdoor",
+        "id" : -149
+    },
+    {
+        "name" : "minecraft:spruce_wall_sign",
+        "id" : -182
+    },
+    {
+        "name" : "minecraft:spyglass",
+        "id" : 631
+    },
+    {
+        "name" : "minecraft:squid_spawn_egg",
+        "id" : 451
+    },
+    {
+        "name" : "minecraft:stained_glass",
+        "id" : 241
+    },
+    {
+        "name" : "minecraft:stained_glass_pane",
+        "id" : 160
+    },
+    {
+        "name" : "minecraft:stained_hardened_clay",
+        "id" : 159
+    },
+    {
+        "name" : "minecraft:standing_banner",
+        "id" : 176
+    },
+    {
+        "name" : "minecraft:standing_sign",
+        "id" : 63
+    },
+    {
+        "name" : "minecraft:stick",
+        "id" : 321
+    },
+    {
+        "name" : "minecraft:sticky_piston",
+        "id" : 29
+    },
+    {
+        "name" : "minecraft:sticky_piston_arm_collision",
+        "id" : -217
+    },
+    {
+        "name" : "minecraft:stone",
+        "id" : 1
+    },
+    {
+        "name" : "minecraft:stone_axe",
+        "id" : 316
+    },
+    {
+        "name" : "minecraft:stone_block_slab",
+        "id" : 44
+    },
+    {
+        "name" : "minecraft:stone_block_slab2",
+        "id" : 182
+    },
+    {
+        "name" : "minecraft:stone_block_slab3",
+        "id" : -162
+    },
+    {
+        "name" : "minecraft:stone_block_slab4",
+        "id" : -166
+    },
+    {
+        "name" : "minecraft:stone_brick_stairs",
+        "id" : 109
+    },
+    {
+        "name" : "minecraft:stone_button",
+        "id" : 77
+    },
+    {
+        "name" : "minecraft:stone_hoe",
+        "id" : 331
+    },
+    {
+        "name" : "minecraft:stone_pickaxe",
+        "id" : 315
+    },
+    {
+        "name" : "minecraft:stone_pressure_plate",
+        "id" : 70
+    },
+    {
+        "name" : "minecraft:stone_shovel",
+        "id" : 314
+    },
+    {
+        "name" : "minecraft:stone_stairs",
+        "id" : 67
+    },
+    {
+        "name" : "minecraft:stone_sword",
+        "id" : 313
+    },
+    {
+        "name" : "minecraft:stonebrick",
+        "id" : 98
+    },
+    {
+        "name" : "minecraft:stonecutter",
+        "id" : 245
+    },
+    {
+        "name" : "minecraft:stonecutter_block",
+        "id" : -197
+    },
+    {
+        "name" : "minecraft:stray_spawn_egg",
+        "id" : 463
+    },
+    {
+        "name" : "minecraft:strider_spawn_egg",
+        "id" : 496
+    },
+    {
+        "name" : "minecraft:string",
+        "id" : 327
+    },
+    {
+        "name" : "minecraft:stripped_acacia_log",
+        "id" : -8
+    },
+    {
+        "name" : "minecraft:stripped_bamboo_block",
+        "id" : -528
+    },
+    {
+        "name" : "minecraft:stripped_birch_log",
+        "id" : -6
+    },
+    {
+        "name" : "minecraft:stripped_crimson_hyphae",
+        "id" : -300
+    },
+    {
+        "name" : "minecraft:stripped_crimson_stem",
+        "id" : -240
+    },
+    {
+        "name" : "minecraft:stripped_dark_oak_log",
+        "id" : -9
+    },
+    {
+        "name" : "minecraft:stripped_jungle_log",
+        "id" : -7
+    },
+    {
+        "name" : "minecraft:stripped_mangrove_log",
+        "id" : -485
+    },
+    {
+        "name" : "minecraft:stripped_mangrove_wood",
+        "id" : -498
+    },
+    {
+        "name" : "minecraft:stripped_oak_log",
+        "id" : -10
+    },
+    {
+        "name" : "minecraft:stripped_spruce_log",
+        "id" : -5
+    },
+    {
+        "name" : "minecraft:stripped_warped_hyphae",
+        "id" : -301
+    },
+    {
+        "name" : "minecraft:stripped_warped_stem",
+        "id" : -241
+    },
+    {
+        "name" : "minecraft:structure_block",
+        "id" : 252
+    },
+    {
+        "name" : "minecraft:structure_void",
+        "id" : 217
+    },
+    {
+        "name" : "minecraft:sugar",
+        "id" : 417
+    },
+    {
+        "name" : "minecraft:sugar_cane",
+        "id" : 386
+    },
+    {
+        "name" : "minecraft:suspicious_sand",
+        "id" : -529
+    },
+    {
+        "name" : "minecraft:suspicious_stew",
+        "id" : 596
+    },
+    {
+        "name" : "minecraft:sweet_berries",
+        "id" : 287
+    },
+    {
+        "name" : "minecraft:sweet_berry_bush",
+        "id" : -207
+    },
+    {
+        "name" : "minecraft:tadpole_bucket",
+        "id" : 636
+    },
+    {
+        "name" : "minecraft:tadpole_spawn_egg",
+        "id" : 635
+    },
+    {
+        "name" : "minecraft:tallgrass",
+        "id" : 31
+    },
+    {
+        "name" : "minecraft:target",
+        "id" : -239
+    },
+    {
+        "name" : "minecraft:tinted_glass",
+        "id" : -334
+    },
+    {
+        "name" : "minecraft:tnt",
+        "id" : 46
+    },
+    {
+        "name" : "minecraft:tnt_minecart",
+        "id" : 531
+    },
+    {
+        "name" : "minecraft:torch",
+        "id" : 50
+    },
+    {
+        "name" : "minecraft:torchflower",
+        "id" : -568
+    },
+    {
+        "name" : "minecraft:torchflower_crop",
+        "id" : -567
+    },
+    {
+        "name" : "minecraft:torchflower_seeds",
+        "id" : 296
+    },
+    {
+        "name" : "minecraft:totem_of_undying",
+        "id" : 574
+    },
+    {
+        "name" : "minecraft:trader_llama_spawn_egg",
+        "id" : 654
+    },
+    {
+        "name" : "minecraft:trapdoor",
+        "id" : 96
+    },
+    {
+        "name" : "minecraft:trapped_chest",
+        "id" : 146
+    },
+    {
+        "name" : "minecraft:trident",
+        "id" : 552
+    },
+    {
+        "name" : "minecraft:trip_wire",
+        "id" : 132
+    },
+    {
+        "name" : "minecraft:tripwire_hook",
+        "id" : 131
+    },
+    {
+        "name" : "minecraft:tropical_fish",
+        "id" : 266
+    },
+    {
+        "name" : "minecraft:tropical_fish_bucket",
+        "id" : 367
+    },
+    {
+        "name" : "minecraft:tropical_fish_spawn_egg",
+        "id" : 480
+    },
+    {
+        "name" : "minecraft:tuff",
+        "id" : -333
+    },
+    {
+        "name" : "minecraft:turtle_egg",
+        "id" : -159
+    },
+    {
+        "name" : "minecraft:turtle_helmet",
+        "id" : 579
+    },
+    {
+        "name" : "minecraft:turtle_spawn_egg",
+        "id" : 486
+    },
+    {
+        "name" : "minecraft:twisting_vines",
+        "id" : -287
+    },
+    {
+        "name" : "minecraft:underwater_torch",
+        "id" : 239
+    },
+    {
+        "name" : "minecraft:undyed_shulker_box",
+        "id" : 205
+    },
+    {
+        "name" : "minecraft:unknown",
+        "id" : -305
+    },
+    {
+        "name" : "minecraft:unlit_redstone_torch",
+        "id" : 75
+    },
+    {
+        "name" : "minecraft:unpowered_comparator",
+        "id" : 149
+    },
+    {
+        "name" : "minecraft:unpowered_repeater",
+        "id" : 93
+    },
+    {
+        "name" : "minecraft:verdant_froglight",
+        "id" : -470
+    },
+    {
+        "name" : "minecraft:vex_spawn_egg",
+        "id" : 477
+    },
+    {
+        "name" : "minecraft:villager_spawn_egg",
+        "id" : 450
+    },
+    {
+        "name" : "minecraft:vindicator_spawn_egg",
+        "id" : 475
+    },
+    {
+        "name" : "minecraft:vine",
+        "id" : 106
+    },
+    {
+        "name" : "minecraft:wall_banner",
+        "id" : 177
+    },
+    {
+        "name" : "minecraft:wall_sign",
+        "id" : 68
+    },
+    {
+        "name" : "minecraft:wandering_trader_spawn_egg",
+        "id" : 493
+    },
+    {
+        "name" : "minecraft:warden_spawn_egg",
+        "id" : 638
+    },
+    {
+        "name" : "minecraft:warped_button",
+        "id" : -261
+    },
+    {
+        "name" : "minecraft:warped_door",
+        "id" : 623
+    },
+    {
+        "name" : "minecraft:warped_double_slab",
+        "id" : -267
+    },
+    {
+        "name" : "minecraft:warped_fence",
+        "id" : -257
+    },
+    {
+        "name" : "minecraft:warped_fence_gate",
+        "id" : -259
+    },
+    {
+        "name" : "minecraft:warped_fungus",
+        "id" : -229
+    },
+    {
+        "name" : "minecraft:warped_fungus_on_a_stick",
+        "id" : 624
+    },
+    {
+        "name" : "minecraft:warped_hanging_sign",
+        "id" : -507
+    },
+    {
+        "name" : "minecraft:warped_hyphae",
+        "id" : -298
+    },
+    {
+        "name" : "minecraft:warped_nylium",
+        "id" : -233
+    },
+    {
+        "name" : "minecraft:warped_planks",
+        "id" : -243
+    },
+    {
+        "name" : "minecraft:warped_pressure_plate",
+        "id" : -263
+    },
+    {
+        "name" : "minecraft:warped_roots",
+        "id" : -224
+    },
+    {
+        "name" : "minecraft:warped_sign",
+        "id" : 621
+    },
+    {
+        "name" : "minecraft:warped_slab",
+        "id" : -265
+    },
+    {
+        "name" : "minecraft:warped_stairs",
+        "id" : -255
+    },
+    {
+        "name" : "minecraft:warped_standing_sign",
+        "id" : -251
+    },
+    {
+        "name" : "minecraft:warped_stem",
+        "id" : -226
+    },
+    {
+        "name" : "minecraft:warped_trapdoor",
+        "id" : -247
+    },
+    {
+        "name" : "minecraft:warped_wall_sign",
+        "id" : -253
+    },
+    {
+        "name" : "minecraft:warped_wart_block",
+        "id" : -227
+    },
+    {
+        "name" : "minecraft:water",
+        "id" : 9
+    },
+    {
+        "name" : "minecraft:water_bucket",
+        "id" : 363
+    },
+    {
+        "name" : "minecraft:waterlily",
+        "id" : 111
+    },
+    {
+        "name" : "minecraft:waxed_copper",
+        "id" : -344
+    },
+    {
+        "name" : "minecraft:waxed_cut_copper",
+        "id" : -351
+    },
+    {
+        "name" : "minecraft:waxed_cut_copper_slab",
+        "id" : -365
+    },
+    {
+        "name" : "minecraft:waxed_cut_copper_stairs",
+        "id" : -358
+    },
+    {
+        "name" : "minecraft:waxed_double_cut_copper_slab",
+        "id" : -372
+    },
+    {
+        "name" : "minecraft:waxed_exposed_copper",
+        "id" : -345
+    },
+    {
+        "name" : "minecraft:waxed_exposed_cut_copper",
+        "id" : -352
+    },
+    {
+        "name" : "minecraft:waxed_exposed_cut_copper_slab",
+        "id" : -366
+    },
+    {
+        "name" : "minecraft:waxed_exposed_cut_copper_stairs",
+        "id" : -359
+    },
+    {
+        "name" : "minecraft:waxed_exposed_double_cut_copper_slab",
+        "id" : -373
+    },
+    {
+        "name" : "minecraft:waxed_oxidized_copper",
+        "id" : -446
+    },
+    {
+        "name" : "minecraft:waxed_oxidized_cut_copper",
+        "id" : -447
+    },
+    {
+        "name" : "minecraft:waxed_oxidized_cut_copper_slab",
+        "id" : -449
+    },
+    {
+        "name" : "minecraft:waxed_oxidized_cut_copper_stairs",
+        "id" : -448
+    },
+    {
+        "name" : "minecraft:waxed_oxidized_double_cut_copper_slab",
+        "id" : -450
+    },
+    {
+        "name" : "minecraft:waxed_weathered_copper",
+        "id" : -346
+    },
+    {
+        "name" : "minecraft:waxed_weathered_cut_copper",
+        "id" : -353
+    },
+    {
+        "name" : "minecraft:waxed_weathered_cut_copper_slab",
+        "id" : -367
+    },
+    {
+        "name" : "minecraft:waxed_weathered_cut_copper_stairs",
+        "id" : -360
+    },
+    {
+        "name" : "minecraft:waxed_weathered_double_cut_copper_slab",
+        "id" : -374
+    },
+    {
+        "name" : "minecraft:weathered_copper",
+        "id" : -342
+    },
+    {
+        "name" : "minecraft:weathered_cut_copper",
+        "id" : -349
+    },
+    {
+        "name" : "minecraft:weathered_cut_copper_slab",
+        "id" : -363
+    },
+    {
+        "name" : "minecraft:weathered_cut_copper_stairs",
+        "id" : -356
+    },
+    {
+        "name" : "minecraft:weathered_double_cut_copper_slab",
+        "id" : -370
+    },
+    {
+        "name" : "minecraft:web",
+        "id" : 30
+    },
+    {
+        "name" : "minecraft:weeping_vines",
+        "id" : -231
+    },
+    {
+        "name" : "minecraft:wheat",
+        "id" : 335
+    },
+    {
+        "name" : "minecraft:wheat_seeds",
+        "id" : 291
+    },
+    {
+        "name" : "minecraft:white_candle",
+        "id" : -413
+    },
+    {
+        "name" : "minecraft:white_candle_cake",
+        "id" : -430
+    },
+    {
+        "name" : "minecraft:white_dye",
+        "id" : 411
+    },
+    {
+        "name" : "minecraft:white_glazed_terracotta",
+        "id" : 220
+    },
+    {
+        "name" : "minecraft:white_wool",
+        "id" : 35
+    },
+    {
+        "name" : "minecraft:witch_spawn_egg",
+        "id" : 453
+    },
+    {
+        "name" : "minecraft:wither_rose",
+        "id" : -216
+    },
+    {
+        "name" : "minecraft:wither_skeleton_spawn_egg",
+        "id" : 465
+    },
+    {
+        "name" : "minecraft:wither_spawn_egg",
+        "id" : 508
+    },
+    {
+        "name" : "minecraft:wolf_spawn_egg",
+        "id" : 440
+    },
+    {
+        "name" : "minecraft:wood",
+        "id" : -212
+    },
+    {
+        "name" : "minecraft:wooden_axe",
+        "id" : 312
+    },
+    {
+        "name" : "minecraft:wooden_button",
+        "id" : 143
+    },
+    {
+        "name" : "minecraft:wooden_door",
+        "id" : 360
+    },
+    {
+        "name" : "minecraft:wooden_hoe",
+        "id" : 330
+    },
+    {
+        "name" : "minecraft:wooden_pickaxe",
+        "id" : 311
+    },
+    {
+        "name" : "minecraft:wooden_pressure_plate",
+        "id" : 72
+    },
+    {
+        "name" : "minecraft:wooden_shovel",
+        "id" : 310
+    },
+    {
+        "name" : "minecraft:wooden_slab",
+        "id" : 158
+    },
+    {
+        "name" : "minecraft:wooden_sword",
+        "id" : 309
+    },
+    {
+        "name" : "minecraft:wool",
+        "id" : 664
+    },
+    {
+        "name" : "minecraft:writable_book",
+        "id" : 516
+    },
+    {
+        "name" : "minecraft:written_book",
+        "id" : 517
+    },
+    {
+        "name" : "minecraft:yellow_candle",
+        "id" : -417
+    },
+    {
+        "name" : "minecraft:yellow_candle_cake",
+        "id" : -434
+    },
+    {
+        "name" : "minecraft:yellow_dye",
+        "id" : 407
+    },
+    {
+        "name" : "minecraft:yellow_flower",
+        "id" : 37
+    },
+    {
+        "name" : "minecraft:yellow_glazed_terracotta",
+        "id" : 224
+    },
+    {
+        "name" : "minecraft:yellow_wool",
+        "id" : -558
+    },
+    {
+        "name" : "minecraft:zoglin_spawn_egg",
+        "id" : 499
+    },
+    {
+        "name" : "minecraft:zombie_horse_spawn_egg",
+        "id" : 469
+    },
+    {
+        "name" : "minecraft:zombie_pigman_spawn_egg",
+        "id" : 449
+    },
+    {
+        "name" : "minecraft:zombie_spawn_egg",
+        "id" : 448
+    },
+    {
+        "name" : "minecraft:zombie_villager_spawn_egg",
+        "id" : 478
+    }
+]
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index d83aaa8f4..3fef94519 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -11,7 +11,7 @@ websocket = "1.5.1"
 protocol = "2.9.17-20230217.002312-1"
 raknet = "1.6.28-20220125.214016-6"
 mcauthlib = "d9d773e"
-mcprotocollib = "1.19.4-SNAPSHOT"
+mcprotocollib = "1.19.4-20230314.173921-2"
 adventure = "4.12.0-20220629.025215-9"
 adventure-platform = "4.1.2"
 junit = "5.9.2"

From d3e7d993965a6af52e792dac27f8d22afa1de339 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Tue, 14 Mar 2023 15:53:16 -0400
Subject: [PATCH 28/59] Remove debug print

---
 .../protocol/bedrock/BedrockInventoryTransactionTranslator.java  | 1 -
 1 file changed, 1 deletion(-)

diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java
index 9e348e704..4d21a36eb 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java
@@ -509,7 +509,6 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
         int javaSlot = session.getPlayerInventory().getOffsetForHotbar(packet.getHotbarSlot());
         int expectedItemId = ItemTranslator.getBedrockItemId(session, session.getPlayerInventory().getItem(javaSlot));
         int heldItemId = packet.getItemInHand() == null ? ItemData.AIR.getId() : packet.getItemInHand().getId();
-        System.out.println(expectedItemId + " " + heldItemId);
 
         if (expectedItemId != heldItemId) {
             session.getGeyser().getLogger().debug(session.bedrockUsername() + "'s held item has desynced! Expected: " + expectedItemId + " Received: " + heldItemId);

From 6ec73261939ff7456009eb0ddae15c500c17360e Mon Sep 17 00:00:00 2001
From: Tim203 <mctim203@gmail.com>
Date: Tue, 14 Mar 2023 21:16:38 +0100
Subject: [PATCH 29/59] Removed another debug line

---
 .../protocol/bedrock/BedrockInventoryTransactionTranslator.java  | 1 -
 1 file changed, 1 deletion(-)

diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java
index 4d21a36eb..893af01cb 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java
@@ -485,7 +485,6 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
      * @param blockPos the block position to restore
      */
     private void restoreCorrectBlock(GeyserSession session, Vector3i blockPos, InventoryTransactionPacket packet) {
-        Thread.dumpStack();
         int javaBlockState = session.getGeyser().getWorldManager().getBlockAt(session, blockPos);
         UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
         updateBlockPacket.setDataLayer(0);

From 79e989092349505d4a3c7cfc1a078b29bb3b2171 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Wed, 15 Mar 2023 11:03:29 -0400
Subject: [PATCH 30/59] Fix smithing tables not opening

---
 .../geyser/translator/inventory/InventoryTranslator.java        | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java
index e6cc010f5..8fe6597c6 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java
@@ -88,7 +88,7 @@ public abstract class InventoryTranslator {
             put(ContainerType.LOOM, new LoomInventoryTranslator());
             put(ContainerType.MERCHANT, new MerchantInventoryTranslator());
             put(ContainerType.SHULKER_BOX, new ShulkerInventoryTranslator());
-            put(ContainerType.SMITHING, new SmithingInventoryTranslator());
+            put(ContainerType.LEGACY_SMITHING, new SmithingInventoryTranslator());
             put(ContainerType.STONECUTTER, new StonecutterInventoryTranslator());
 
             /* Lectern */

From d7c68659122fd27a68081e70e1142550e115f5c2 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Wed, 15 Mar 2023 11:36:00 -0400
Subject: [PATCH 31/59] Fix #3607

---
 gradle/libs.versions.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 3fef94519..ddd3c38bf 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -11,7 +11,7 @@ websocket = "1.5.1"
 protocol = "2.9.17-20230217.002312-1"
 raknet = "1.6.28-20220125.214016-6"
 mcauthlib = "d9d773e"
-mcprotocollib = "1.19.4-20230314.173921-2"
+mcprotocollib = "1.19.4-20230315.153350-3"
 adventure = "4.12.0-20220629.025215-9"
 adventure-platform = "4.1.2"
 junit = "5.9.2"

From acb25b0c99ad5cf638dad3e168116c00d9930a9e Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Fri, 17 Mar 2023 13:41:01 -0400
Subject: [PATCH 32/59] Remove legacy 1.19.2x Bedrock code

---
 .../geysermc/geyser/network/GameProtocol.java |  4 --
 .../BedrockAdventureSettingsTranslator.java   | 42 -------------------
 .../BedrockRequestAbilityTranslator.java      | 38 +++++++----------
 .../java/JavaKeepAliveTranslator.java         |  5 +++
 .../protocol/java/JavaLoginTranslator.java    |  7 ----
 5 files changed, 19 insertions(+), 77 deletions(-)
 delete mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAdventureSettingsTranslator.java

diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
index 16f4abd04..083bc5b58 100644
--- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
+++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
@@ -96,10 +96,6 @@ public final class GameProtocol {
 
     /* Bedrock convenience methods to gatekeep features and easily remove the check on version removal */
 
-    public static boolean supports1_19_30(GeyserSession session) {
-        return session.getUpstream().getProtocolVersion() >= Bedrock_v554.V554_CODEC.getProtocolVersion();
-    }
-
     public static boolean supports1_19_50(GeyserSession session) {
         return session.getUpstream().getProtocolVersion() >= Bedrock_v560.V560_CODEC.getProtocolVersion();
     }
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAdventureSettingsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAdventureSettingsTranslator.java
deleted file mode 100644
index aabc39e12..000000000
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAdventureSettingsTranslator.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2019-2022 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.bedrock;
-
-import com.nukkitx.protocol.bedrock.data.AdventureSetting;
-import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket;
-import org.geysermc.geyser.session.GeyserSession;
-import org.geysermc.geyser.translator.protocol.PacketTranslator;
-import org.geysermc.geyser.translator.protocol.Translator;
-
-@Translator(packet = AdventureSettingsPacket.class)
-public class BedrockAdventureSettingsTranslator extends PacketTranslator<AdventureSettingsPacket> {
-
-    @Override
-    public void translate(GeyserSession session, AdventureSettingsPacket packet) {
-        boolean isFlying = packet.getSettings().contains(AdventureSetting.FLYING);
-        BedrockRequestAbilityTranslator.handle(session, isFlying);
-    }
-}
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java
index fe8150d40..bf268fd0e 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java
@@ -30,7 +30,6 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.Server
 import com.nukkitx.protocol.bedrock.data.Ability;
 import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
 import com.nukkitx.protocol.bedrock.packet.RequestAbilityPacket;
-import org.geysermc.geyser.network.GameProtocol;
 import org.geysermc.geyser.session.GeyserSession;
 import org.geysermc.geyser.translator.protocol.PacketTranslator;
 import org.geysermc.geyser.translator.protocol.Translator;
@@ -43,31 +42,22 @@ public class BedrockRequestAbilityTranslator extends PacketTranslator<RequestAbi
 
     @Override
     public void translate(GeyserSession session, RequestAbilityPacket packet) {
-        // Gatekeep to 1.19.30 so older versions don't fire twice
-        if (!GameProtocol.supports1_19_30(session)) {
-            return;
-        }
-        
         if (packet.getAbility() == Ability.FLYING) {
-            handle(session, packet.isBoolValue());
-        }
-    }
+            boolean isFlying = packet.isBoolValue();
+            if (!isFlying && session.getGameMode() == GameMode.SPECTATOR) {
+                // We should always be flying in spectator mode
+                session.sendAdventureSettings();
+                return;
+            } else if (isFlying && session.getPlayerEntity().getFlag(EntityFlag.SWIMMING) && session.getCollisionManager().isPlayerInWater()) {
+                // As of 1.18.1, Java Edition cannot fly while in water, but it can fly while crawling
+                // If this isn't present, swimming on a 1.13.2 server and then attempting to fly will put you into a flying/swimming state that is invalid on JE
+                session.sendAdventureSettings();
+                return;
+            }
 
-    //FIXME remove after pre-1.19.30 support is dropped and merge into main method
-    static void handle(GeyserSession session, boolean isFlying) {
-        if (!isFlying && session.getGameMode() == GameMode.SPECTATOR) {
-            // We should always be flying in spectator mode
-            session.sendAdventureSettings();
-            return;
-        } else if (isFlying && session.getPlayerEntity().getFlag(EntityFlag.SWIMMING) && session.getCollisionManager().isPlayerInWater()) {
-            // As of 1.18.1, Java Edition cannot fly while in water, but it can fly while crawling
-            // If this isn't present, swimming on a 1.13.2 server and then attempting to fly will put you into a flying/swimming state that is invalid on JE
-            session.sendAdventureSettings();
-            return;
+            session.setFlying(isFlying);
+            ServerboundPlayerAbilitiesPacket abilitiesPacket = new ServerboundPlayerAbilitiesPacket(isFlying);
+            session.sendDownstreamPacket(abilitiesPacket);
         }
-
-        session.setFlying(isFlying);
-        ServerboundPlayerAbilitiesPacket abilitiesPacket = new ServerboundPlayerAbilitiesPacket(isFlying);
-        session.sendDownstreamPacket(abilitiesPacket);
     }
 }
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaKeepAliveTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaKeepAliveTranslator.java
index 5a1715893..f1503e545 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaKeepAliveTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaKeepAliveTranslator.java
@@ -47,4 +47,9 @@ public class JavaKeepAliveTranslator extends PacketTranslator<ClientboundKeepAli
         latencyPacket.setTimestamp(packet.getPingId() * 1000);
         session.sendUpstreamPacket(latencyPacket);
     }
+
+    @Override
+    public boolean shouldExecuteInEventLoop() {
+        return false;
+    }
 }
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java
index 09d117087..9afa337ef 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java
@@ -30,8 +30,6 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCu
 import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
 import com.github.steveice10.opennbt.tag.builtin.IntTag;
 import com.nukkitx.protocol.bedrock.data.GameRuleData;
-import com.nukkitx.protocol.bedrock.data.PlayerPermission;
-import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket;
 import com.nukkitx.protocol.bedrock.packet.GameRulesChangedPacket;
 import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket;
 import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
@@ -107,11 +105,6 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
             session.getUpstream().sendPostStartGamePackets();
         }
 
-        AdventureSettingsPacket bedrockPacket = new AdventureSettingsPacket();
-        bedrockPacket.setUniqueEntityId(session.getPlayerEntity().getGeyserId());
-        bedrockPacket.setPlayerPermission(PlayerPermission.MEMBER);
-        session.sendUpstreamPacket(bedrockPacket);
-
         if (!needsSpawnPacket) {
             SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
             playerGameTypePacket.setGamemode(packet.getGameMode().ordinal());

From 147618d5bc8823a6ec13395ca5d4a3df7adf0e24 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Fri, 17 Mar 2023 13:41:13 -0400
Subject: [PATCH 33/59] Fix player nametags always appearing

---
 .../org/geysermc/geyser/scoreboard/Team.java    | 17 ++++++++---------
 gradle/libs.versions.toml                       |  2 +-
 2 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java
index b2e9043b5..e985ca803 100644
--- a/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java
+++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java
@@ -33,9 +33,9 @@ import lombok.Getter;
 import lombok.Setter;
 import lombok.experimental.Accessors;
 
+import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.HashSet;
-import java.util.Objects;
 import java.util.Set;
 
 @Getter
@@ -46,7 +46,7 @@ public final class Team {
 
     @Getter(AccessLevel.PACKAGE)
     private final Set<String> entities;
-    @Setter @Nullable private NameTagVisibility nameTagVisibility;
+    @Nonnull private NameTagVisibility nameTagVisibility = NameTagVisibility.ALWAYS;
     @Setter private TeamColor color;
 
     private final TeamData currentData;
@@ -189,11 +189,6 @@ public final class Team {
     }
 
     public boolean isVisibleFor(String entity) {
-        if (nameTagVisibility == null) {
-            // Null - normal behavior
-            return true;
-        }
-
         return switch (nameTagVisibility) {
             case HIDE_FOR_OTHER_TEAMS -> {
                 // Player must be in a team in order for HIDE_FOR_OTHER_TEAMS to be triggered
@@ -206,8 +201,12 @@ public final class Team {
         };
     }
 
-    public NameTagVisibility getNameTagVisibility() {
-        return Objects.requireNonNullElse(this.nameTagVisibility, NameTagVisibility.ALWAYS);
+    public Team setNameTagVisibility(@Nullable NameTagVisibility nameTagVisibility) {
+        if (nameTagVisibility != null) {
+            // Null check like this (and this.nameTagVisibility defaults to ALWAYS) as of Java 1.19.4
+            this.nameTagVisibility = nameTagVisibility;
+        }
+        return this;
     }
 
     @Override
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index ddd3c38bf..7e8ddb2ad 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -11,7 +11,7 @@ websocket = "1.5.1"
 protocol = "2.9.17-20230217.002312-1"
 raknet = "1.6.28-20220125.214016-6"
 mcauthlib = "d9d773e"
-mcprotocollib = "1.19.4-20230315.153350-3"
+mcprotocollib = "1.19.4-20230317.173631-4"
 adventure = "4.12.0-20220629.025215-9"
 adventure-platform = "4.1.2"
 junit = "5.9.2"

From 9609686eb34960937fe514d06d467ffd7fc57bcc Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Fri, 17 Mar 2023 19:07:31 -0400
Subject: [PATCH 34/59] Version out potion registry

The ID of (for example) redstone dust has shifted, meaning that our hack of re-using IDs no longer works.

Fixes #3620
---
 .../geysermc/geyser/registry/Registries.java  |   4 +-
 .../loader/PotionMixRegistryLoader.java       | 101 ++++++++++--------
 .../geyser/session/GeyserSession.java         |   2 +-
 .../java/JavaUpdateRecipesTranslator.java     |   2 +-
 4 files changed, 59 insertions(+), 50 deletions(-)

diff --git a/core/src/main/java/org/geysermc/geyser/registry/Registries.java b/core/src/main/java/org/geysermc/geyser/registry/Registries.java
index 866cbd291..b4afd7d2f 100644
--- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java
+++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java
@@ -135,7 +135,7 @@ public final class Registries {
     /**
      * A registry holding all the potion mixes.
      */
-    public static final SimpleRegistry<Set<PotionMixData>> POTION_MIXES;
+    public static final VersionedRegistry<Set<PotionMixData>> POTION_MIXES;
 
     /**
      * A registry holding all the
@@ -178,7 +178,7 @@ public final class Registries {
         RecipeRegistryPopulator.populate();
 
         // Create registries that require other registries to load first
-        POTION_MIXES = SimpleRegistry.create(PotionMixRegistryLoader::new);
+        POTION_MIXES = VersionedRegistry.create(PotionMixRegistryLoader::new);
         ENCHANTMENTS = SimpleMappedRegistry.create("mappings/enchantments.json", EnchantmentRegistryLoader::new);
 
         // Remove unneeded client generation data from NbtMapBuilder
diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java
index 8d40edac3..694aeba9c 100644
--- a/core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java
+++ b/core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java
@@ -26,17 +26,18 @@
 package org.geysermc.geyser.registry.loader;
 
 import com.nukkitx.protocol.bedrock.data.inventory.PotionMixData;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
 import org.geysermc.geyser.inventory.item.Potion;
-import org.geysermc.geyser.network.GameProtocol;
 import org.geysermc.geyser.registry.Registries;
 import org.geysermc.geyser.registry.type.ItemMapping;
+import org.geysermc.geyser.registry.type.ItemMappings;
 
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
-//TODO this needs to be versioned, but the runtime item states between 1.17 and 1.17.10 are identical except for new blocks so this works for both
 /**
  * Generates a collection of {@link PotionMixData} that enables the
  * Bedrock client to place brewing items into the brewing stand.
@@ -46,64 +47,72 @@ import java.util.Set;
  * (Ex: Bedrock cannot normally place glass bottles or fully upgraded
  * potions into the brewing stand, but Java can.)
  */
-public class PotionMixRegistryLoader implements RegistryLoader<Object, Set<PotionMixData>> {
+public class PotionMixRegistryLoader implements RegistryLoader<Object, Int2ObjectMap<Set<PotionMixData>>> {
 
     @Override
-    public Set<PotionMixData> load(Object input) {
-        List<ItemMapping> ingredients = new ArrayList<>();
-        ingredients.add(getNonNull("minecraft:nether_wart"));
-        ingredients.add(getNonNull("minecraft:redstone"));
-        ingredients.add(getNonNull("minecraft:glowstone_dust"));
-        ingredients.add(getNonNull("minecraft:fermented_spider_eye"));
-        ingredients.add(getNonNull("minecraft:gunpowder"));
-        ingredients.add(getNonNull("minecraft:dragon_breath"));
-        ingredients.add(getNonNull("minecraft:sugar"));
-        ingredients.add(getNonNull("minecraft:rabbit_foot"));
-        ingredients.add(getNonNull("minecraft:glistering_melon_slice"));
-        ingredients.add(getNonNull("minecraft:spider_eye"));
-        ingredients.add(getNonNull("minecraft:pufferfish"));
-        ingredients.add(getNonNull("minecraft:magma_cream"));
-        ingredients.add(getNonNull("minecraft:golden_carrot"));
-        ingredients.add(getNonNull("minecraft:blaze_powder"));
-        ingredients.add(getNonNull("minecraft:ghast_tear"));
-        ingredients.add(getNonNull("minecraft:turtle_helmet"));
-        ingredients.add(getNonNull("minecraft:phantom_membrane"));
+    public Int2ObjectMap<Set<PotionMixData>> load(Object input) {
+        var allPotionMixes = new Int2ObjectOpenHashMap<Set<PotionMixData>>(Registries.ITEMS.get().size());
+        for (var entry : Registries.ITEMS.get().int2ObjectEntrySet()) {
+            ItemMappings mappings = entry.getValue();
+            List<ItemMapping> ingredients = new ArrayList<>();
+            ingredients.add(getNonNull(mappings, "minecraft:nether_wart"));
+            ingredients.add(getNonNull(mappings, "minecraft:redstone"));
+            ingredients.add(getNonNull(mappings, "minecraft:glowstone_dust"));
+            ingredients.add(getNonNull(mappings, "minecraft:fermented_spider_eye"));
+            ingredients.add(getNonNull(mappings, "minecraft:gunpowder"));
+            ingredients.add(getNonNull(mappings, "minecraft:dragon_breath"));
+            ingredients.add(getNonNull(mappings, "minecraft:sugar"));
+            ingredients.add(getNonNull(mappings, "minecraft:rabbit_foot"));
+            ingredients.add(getNonNull(mappings, "minecraft:glistering_melon_slice"));
+            ingredients.add(getNonNull(mappings, "minecraft:spider_eye"));
+            ingredients.add(getNonNull(mappings, "minecraft:pufferfish"));
+            ingredients.add(getNonNull(mappings, "minecraft:magma_cream"));
+            ingredients.add(getNonNull(mappings, "minecraft:golden_carrot"));
+            ingredients.add(getNonNull(mappings, "minecraft:blaze_powder"));
+            ingredients.add(getNonNull(mappings, "minecraft:ghast_tear"));
+            ingredients.add(getNonNull(mappings, "minecraft:turtle_helmet"));
+            ingredients.add(getNonNull(mappings, "minecraft:phantom_membrane"));
 
-        List<ItemMapping> inputs = new ArrayList<>();
-        inputs.add(getNonNull("minecraft:potion"));
-        inputs.add(getNonNull("minecraft:splash_potion"));
-        inputs.add(getNonNull("minecraft:lingering_potion"));
+            List<ItemMapping> inputs = List.of(
+                    getNonNull(mappings, "minecraft:potion"),
+                    getNonNull(mappings, "minecraft:splash_potion"),
+                    getNonNull(mappings, "minecraft:lingering_potion")
+            );
 
-        ItemMapping glassBottle = getNonNull("minecraft:glass_bottle");
+            ItemMapping glassBottle = getNonNull(mappings, "minecraft:glass_bottle");
 
-        Set<PotionMixData> potionMixes = new HashSet<>();
+            Set<PotionMixData> potionMixes = new HashSet<>();
 
-        // Add all types of potions as inputs
-        ItemMapping fillerIngredient = ingredients.get(0);
-        for (ItemMapping entryInput : inputs) {
-            for (Potion potion : Potion.values()) {
+            // Add all types of potions as inputs
+            ItemMapping fillerIngredient = ingredients.get(0);
+            for (ItemMapping entryInput : inputs) {
+                for (Potion potion : Potion.VALUES) {
+                    potionMixes.add(new PotionMixData(
+                            entryInput.getBedrockId(), potion.getBedrockId(),
+                            fillerIngredient.getBedrockId(), fillerIngredient.getBedrockData(),
+                            glassBottle.getBedrockId(), glassBottle.getBedrockData())
+                    );
+                }
+            }
+
+            // Add all brewing ingredients
+            // Also adds glass bottle as input
+            for (ItemMapping ingredient : ingredients) {
                 potionMixes.add(new PotionMixData(
-                        entryInput.getBedrockId(), potion.getBedrockId(),
-                        fillerIngredient.getBedrockId(), fillerIngredient.getBedrockData(),
+                        glassBottle.getBedrockId(), glassBottle.getBedrockData(),
+                        ingredient.getBedrockId(), ingredient.getBedrockData(),
                         glassBottle.getBedrockId(), glassBottle.getBedrockData())
                 );
             }
-        }
 
-        // Add all brewing ingredients
-        // Also adds glass bottle as input
-        for (ItemMapping ingredient : ingredients) {
-            potionMixes.add(new PotionMixData(
-                    glassBottle.getBedrockId(), glassBottle.getBedrockData(),
-                    ingredient.getBedrockId(), ingredient.getBedrockData(),
-                    glassBottle.getBedrockId(), glassBottle.getBedrockData())
-            );
+            allPotionMixes.put(entry.getIntKey(), potionMixes);
         }
-        return potionMixes;
+        allPotionMixes.trim();
+        return allPotionMixes;
     }
 
-    private static ItemMapping getNonNull(String javaIdentifier) {
-        ItemMapping itemMapping = Registries.ITEMS.forVersion(GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()).getMapping(javaIdentifier);
+    private static ItemMapping getNonNull(ItemMappings mappings, String javaIdentifier) {
+        ItemMapping itemMapping = mappings.getMapping(javaIdentifier);
         if (itemMapping == null)
             throw new NullPointerException("No item entry exists for java identifier: " + javaIdentifier);
 
diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
index 9b7d334fc..fa0db15f2 100644
--- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
+++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
@@ -640,7 +640,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
         // Potion mixes are registered by default, as they are needed to be able to put ingredients into the brewing stand.
         CraftingDataPacket craftingDataPacket = new CraftingDataPacket();
         craftingDataPacket.setCleanRecipes(true);
-        craftingDataPacket.getPotionMixData().addAll(Registries.POTION_MIXES.get());
+        craftingDataPacket.getPotionMixData().addAll(Registries.POTION_MIXES.forVersion(this.upstream.getProtocolVersion()));
         upstream.sendPacket(craftingDataPacket);
 
         PlayStatusPacket playStatusPacket = new PlayStatusPacket();
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java
index 9923c0a16..e665d5424 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java
@@ -167,7 +167,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
             }
         }
         craftingDataPacket.getCraftingData().addAll(CARTOGRAPHY_RECIPES);
-        craftingDataPacket.getPotionMixData().addAll(Registries.POTION_MIXES.get());
+        craftingDataPacket.getPotionMixData().addAll(Registries.POTION_MIXES.forVersion(session.getUpstream().getProtocolVersion()));
 
         Int2ObjectMap<GeyserStonecutterData> stonecutterRecipeMap = new Int2ObjectOpenHashMap<>();
         for (Int2ObjectMap.Entry<List<StoneCuttingRecipeData>> data : unsortedStonecutterData.int2ObjectEntrySet()) {

From a330c9a5db69d12a2df3ac351ac69c8ae6367a3d Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Sat, 18 Mar 2023 17:40:51 -0400
Subject: [PATCH 35/59] Fix lecterns

Huge thanks to Dylan from PocketMine for the idea here.

Fixes #3138
---
 .../main/java/org/geysermc/geyser/session/GeyserSession.java    | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
index fa0db15f2..d76cc4b97 100644
--- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
+++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
@@ -1688,6 +1688,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
         abilities.add(Ability.MINE);
         // Needed so you can drop items
         abilities.add(Ability.DOORS_AND_SWITCHES);
+        // Required for lecterns to work (likely started around 1.19.10; confirmed on 1.19.70)
+        abilities.add(Ability.OPEN_CONTAINERS);
         if (gameMode == GameMode.CREATIVE) {
             // Needed so the client doesn't attempt to take away items
             abilities.add(Ability.INSTABUILD);

From 23294484ded4e7b7994bc36d4f00444f0d8093ae Mon Sep 17 00:00:00 2001
From: rtm516 <rtm516@users.noreply.github.com>
Date: Sun, 19 Mar 2023 15:08:51 +0000
Subject: [PATCH 36/59] Update downloads api publishing steps

---
 .github/workflows/build.yml | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 2d1c84670..0c88bf213 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -106,12 +106,16 @@ jobs:
           # Save the private key to a file
           echo "$DOWNLOADS_PRIVATE_KEY" > id_ecdsa
           chmod 600 id_ecdsa
+          # Set the project
+          project=geyser
           # Get the version from gradle.properties
           version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2)
           # Copy over artifacts
-          scp -B -o StrictHostKeyChecking=no -i id_ecdsa bootstrap/**/build/libs/Geyser-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/files/
+          rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" bootstrap/**/build/libs/Geyser-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$project/$GITHUB_RUN_NUMBER/
           # Run the build script
-          ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP ./handleBuild.sh geyser $version $GITHUB_RUN_NUMBER $GITHUB_SHA
+          # Push the metadata
+          echo "{\"project\": \"$project\", \"version\": \"$version\", \"id\": $GITHUB_RUN_NUMBER, \"commit\": \"$GITHUB_SHA\"}" > metadata.json
+          rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$project/$GITHUB_RUN_NUMBER/
 
       - name: Notify Discord
         if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }}

From b56f4016886a69c11a705b038ea0464e09d9b9a5 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Sun, 19 Mar 2023 11:24:45 -0400
Subject: [PATCH 37/59] Update MCProtocolLib to fix #3624

---
 gradle/libs.versions.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 7e8ddb2ad..a656f6b74 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -11,7 +11,7 @@ websocket = "1.5.1"
 protocol = "2.9.17-20230217.002312-1"
 raknet = "1.6.28-20220125.214016-6"
 mcauthlib = "d9d773e"
-mcprotocollib = "1.19.4-20230317.173631-4"
+mcprotocollib = "1.19.4-20230319.152208-5"
 adventure = "4.12.0-20220629.025215-9"
 adventure-platform = "4.1.2"
 junit = "5.9.2"

From 021ffe2d946e270c170ebbd34c014fd6e80ffc87 Mon Sep 17 00:00:00 2001
From: David Choo <4722249+davchoo@users.noreply.github.com>
Date: Sun, 19 Mar 2023 11:30:56 -0400
Subject: [PATCH 38/59] Update ringing bell block event logic (#3625)

Check for BellValue instead of a GenericBlockValue
Removes now unnecessary JAVA_BELL_ID from BlockStateValues
---
 .../geyser/level/block/BlockStateValues.java        |  1 -
 .../registry/populator/BlockRegistryPopulator.java  | 10 +---------
 .../java/level/JavaBlockEventTranslator.java        | 13 +++++++------
 3 files changed, 8 insertions(+), 16 deletions(-)

diff --git a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java
index 58cbce77f..c6fc60303 100644
--- a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java
+++ b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java
@@ -68,7 +68,6 @@ public final class BlockStateValues {
 
     public static final int JAVA_AIR_ID = 0;
 
-    public static int JAVA_BELL_ID;
     public static int JAVA_COBWEB_ID;
     public static int JAVA_FURNACE_ID;
     public static int JAVA_FURNACE_LIT_ID;
diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java
index b931750e1..ad1066491 100644
--- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java
+++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java
@@ -223,7 +223,6 @@ public final class BlockRegistryPopulator {
         Deque<String> cleanIdentifiers = new ArrayDeque<>();
 
         int javaRuntimeId = -1;
-        int bellBlockId = -1;
         int cobwebBlockId = -1;
         int furnaceRuntimeId = -1;
         int furnaceLitRuntimeId = -1;
@@ -300,10 +299,7 @@ public final class BlockRegistryPopulator {
             // It's possible to only have this store differences in names, but the key set of all Java names is used in sending command suggestions
             BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.register(cleanJavaIdentifier.intern(), bedrockIdentifier.intern());
 
-            if (javaId.startsWith("minecraft:bell[")) {
-                bellBlockId = uniqueJavaId;
-
-            } else if (javaId.contains("cobweb")) {
+            if (javaId.contains("cobweb")) {
                 cobwebBlockId = uniqueJavaId;
 
             } else if (javaId.startsWith("minecraft:furnace[facing=north")) {
@@ -324,10 +320,6 @@ public final class BlockRegistryPopulator {
                 slimeBlockRuntimeId = javaRuntimeId;
             }
         }
-        if (bellBlockId == -1) {
-            throw new AssertionError("Unable to find bell in palette");
-        }
-        BlockStateValues.JAVA_BELL_ID = bellBlockId;
 
         if (cobwebBlockId == -1) {
             throw new AssertionError("Unable to find cobwebs in palette");
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java
index 149e8356e..aa7c9e6e7 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java
@@ -103,7 +103,7 @@ public class JavaBlockEventTranslator extends PacketTranslator<ClientboundBlockE
         } else if (packet.getValue() instanceof EndGatewayValue) {
             blockEventPacket.setEventType(1);
             session.sendUpstreamPacket(blockEventPacket);
-        } else if (packet.getValue() instanceof GenericBlockValue bellValue && packet.getBlockId() == BlockStateValues.JAVA_BELL_ID) {
+        } else if (packet.getValue() instanceof BellValue bellValue) {
             // Bells - needed to show ring from other players
             BlockEntityDataPacket blockEntityPacket = new BlockEntityDataPacket();
             blockEntityPacket.setBlockPosition(position);
@@ -113,11 +113,12 @@ public class JavaBlockEventTranslator extends PacketTranslator<ClientboundBlockE
             builder.putInt("y", position.getY());
             builder.putInt("z", position.getZ());
             builder.putString("id", "Bell");
-            int bedrockRingDirection = switch (bellValue.getValue()) {
-                case 3 -> 0; // north
-                case 4 -> 1; // east
-                case 5 -> 3;// west
-                default -> bellValue.getValue(); // south (2) is identical
+            int bedrockRingDirection = switch (bellValue.getDirection()) {
+                case SOUTH -> 0;
+                case WEST -> 1;
+                case NORTH -> 2;
+                case EAST -> 3;
+                default -> throw new IllegalStateException("Unexpected BellValue Direction: " + bellValue.getDirection());
             };
             builder.putInt("Direction", bedrockRingDirection);
             builder.putByte("Ringing", (byte) 1);

From 775725c617acabdb8afc90b6134a2f0e128a4fcc Mon Sep 17 00:00:00 2001
From: rtm516 <rtm516@users.noreply.github.com>
Date: Sun, 19 Mar 2023 17:09:18 +0000
Subject: [PATCH 39/59] Create the build directory when pushing to the api

---
 .github/workflows/build.yml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 0c88bf213..668c9ca72 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -110,6 +110,8 @@ jobs:
           project=geyser
           # Get the version from gradle.properties
           version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2)
+          # Create the build folder
+          ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP mkdir -p "~/uploads/$project/$GITHUB_RUN_NUMBER/"
           # Copy over artifacts
           rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" bootstrap/**/build/libs/Geyser-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$project/$GITHUB_RUN_NUMBER/
           # Run the build script

From b664bb961e925d955a74ddf75ef36fe3ee16cec9 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Sun, 19 Mar 2023 14:08:48 -0400
Subject: [PATCH 40/59] Indicate 1.19.71 support

---
 README.md                                                   | 2 +-
 .../main/java/org/geysermc/geyser/network/GameProtocol.java | 6 ++++--
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index cfc99a8ba..013e87239 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t
 
 Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here!
 
-### Currently supporting Minecraft Bedrock 1.19.30 - 1.19.70 and Minecraft Java 1.19.4.
+### Currently supporting Minecraft Bedrock 1.19.30 - 1.19.71 and Minecraft Java 1.19.4.
 
 ## Setting Up
 Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser.
diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
index 083bc5b58..8ce4fd196 100644
--- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
+++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java
@@ -49,7 +49,7 @@ public final class GameProtocol {
      */
     public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v567patch.BEDROCK_V567PATCH.toBuilder()
             .protocolVersion(575)
-            .minecraftVersion("1.19.70")
+            .minecraftVersion("1.19.71")
             .build();
     /**
      * A list of all supported Bedrock versions that can join Geyser
@@ -77,7 +77,9 @@ public final class GameProtocol {
                 .protocolVersion(568)
                 .minecraftVersion("1.19.62")
                 .build());
-        SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC);
+        SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder()
+                .minecraftVersion("1.19.70/1.19.71")
+                .build());
     }
 
     /**

From b695dc075d5db6c6de3f5703a0dbfea317cd34af Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Sun, 19 Mar 2023 14:09:01 -0400
Subject: [PATCH 41/59] Fix command redirection detection

---
 .../translator/protocol/java/JavaCommandsTranslator.java   | 7 ++++---
 gradle/libs.versions.toml                                  | 2 +-
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java
index 24a52600a..5b009b81c 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java
@@ -199,9 +199,10 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
      */
     private static CommandParamData[][] getParams(GeyserSession session, CommandNode commandNode, CommandNode[] allNodes) {
         // Check if the command is an alias and redirect it
-        if (commandNode.getRedirectIndex() != -1) {
-            GeyserImpl.getInstance().getLogger().debug("Redirecting command " + commandNode.getName() + " to " + allNodes[commandNode.getRedirectIndex()].getName());
-            commandNode = allNodes[commandNode.getRedirectIndex()];
+        if (commandNode.getRedirectIndex().isPresent()) {
+            int redirectIndex = commandNode.getRedirectIndex().getAsInt();
+            GeyserImpl.getInstance().getLogger().debug("Redirecting command " + commandNode.getName() + " to " + allNodes[redirectIndex].getName());
+            commandNode = allNodes[redirectIndex];
         }
 
         if (commandNode.getChildIndices().length >= 1) {
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index a656f6b74..4f7433034 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -11,7 +11,7 @@ websocket = "1.5.1"
 protocol = "2.9.17-20230217.002312-1"
 raknet = "1.6.28-20220125.214016-6"
 mcauthlib = "d9d773e"
-mcprotocollib = "1.19.4-20230319.152208-5"
+mcprotocollib = "1.19.4-20230319.175814-6"
 adventure = "4.12.0-20220629.025215-9"
 adventure-platform = "4.1.2"
 junit = "5.9.2"

From 4a20bbad88f968bd9055b081df95c67924dead19 Mon Sep 17 00:00:00 2001
From: Redned <redned235@gmail.com>
Date: Sun, 19 Mar 2023 15:24:52 -0500
Subject: [PATCH 42/59] Update README with new download link

---
 README.md | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/README.md b/README.md
index 013e87239..77e2671f9 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,6 @@
 <img src="https://geysermc.org/img/geyser-1760-860.png" alt="Geyser" width="600"/>
 
-[![forthebadge made-with-java](https://forthebadge.com/images/badges/made-with-java.svg)](https://java.com/)
-
 [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
-[![Build Status](https://ci.opencollab.dev/job/Geyser/job/master/badge/icon)](https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/master/)
 [![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](https://discord.gg/geysermc)
 [![Crowdin](https://badges.crowdin.net/geyser/localized.svg)](https://translate.geysermc.org/)
 
@@ -27,7 +24,7 @@ Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Ge
 ## Links:
 - Website: https://geysermc.org
 - Docs: https://wiki.geysermc.org/geyser/
-- Download: https://ci.geysermc.org
+- Download: https://geysermc.org/download
 - Discord: https://discord.gg/geysermc
 - Donate: https://opencollective.com/geysermc
 - Test Server: `test.geysermc.org` port `25565` for Java and `19132` for Bedrock

From 05829eeed8daadd8e779ad50f3d89879f196f81a Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Mon, 20 Mar 2023 13:04:53 -0400
Subject: [PATCH 43/59] Upload Fabric platform to Modrinth

---
 .github/workflows/publish.yml     | 16 ++++++++++++++++
 bootstrap/fabric/build.gradle.kts | 19 +++++++++++++++++++
 2 files changed, 35 insertions(+)
 create mode 100644 .github/workflows/publish.yml

diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 000000000..2b5bea7df
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,16 @@
+name: publish
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v3
+      - uses: gradle/wrapper-validation-action@v1
+      - uses: actions/setup-java@v3
+        with:
+          distribution: 'temurin'
+          java-version: 17
+      - name: build and publish
+        env:
+          MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
+        run: ./gradlew fabric:modrinth
\ No newline at end of file
diff --git a/bootstrap/fabric/build.gradle.kts b/bootstrap/fabric/build.gradle.kts
index 743b75a26..890f5d656 100644
--- a/bootstrap/fabric/build.gradle.kts
+++ b/bootstrap/fabric/build.gradle.kts
@@ -1,5 +1,6 @@
 plugins {
     id("fabric-loom") version "1.0-SNAPSHOT"
+    id("com.modrinth.minotaur") version "2.+"
 }
 
 java {
@@ -74,4 +75,22 @@ tasks {
         archiveClassifier.set("")
         archiveVersion.set("")
     }
+}
+
+modrinth {
+    projectId.set("wKkoqHrH")
+    versionNumber.set(project.version as String + "-" + System.getenv("GITHUB_RUN_NUMBER"))
+    versionType.set("beta")
+    changelog.set("A changelog can be found at https://github.com/GeyserMC/Geyser/commits")
+
+    syncBodyFrom.set(rootProject.file("README.md").readText())
+
+    uploadFile.set(tasks.getByPath("remapJar"))
+    gameVersions.addAll("1.19", "1.19.1", "1.19.2", "1.19.3", "1.19.4")
+
+    loaders.add("fabric")
+
+    dependencies {
+        required.project("fabric-api")
+    }
 }
\ No newline at end of file

From 66005edcc6c9015b75325fba8978cd182c587bab Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Mon, 20 Mar 2023 13:08:07 -0400
Subject: [PATCH 44/59] Actually run it

---
 .github/workflows/publish.yml | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 2b5bea7df..04712681d 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -1,4 +1,17 @@
-name: publish
+name: Publish
+on:
+  workflow_dispatch:
+  push:
+    paths-ignore:
+      - '.github/ISSUE_TEMPLATE/*.yml'
+      - '.github/actions/pullrequest.yml'
+      - '.idea/copyright/*.xml'
+      - '.gitignore'
+      - 'CONTRIBUTING.md'
+      - 'LICENSE'
+      - 'Jenkinsfile '
+      - 'README.md'
+      - 'licenseheader.txt'
 
 jobs:
   build:
@@ -10,7 +23,7 @@ jobs:
         with:
           distribution: 'temurin'
           java-version: 17
-      - name: build and publish
+      - name: Publish to Modrinth
         env:
           MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
         run: ./gradlew fabric:modrinth
\ No newline at end of file

From 775e1e8921bd08b2d7f68ce67935b7d63685f3c5 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Mon, 20 Mar 2023 13:32:02 -0400
Subject: [PATCH 45/59] Modrinth: submodules exist too

---
 .github/workflows/publish.yml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 04712681d..2b002b0de 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -18,6 +18,8 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
+        with:
+          submodules: recursive
       - uses: gradle/wrapper-validation-action@v1
       - uses: actions/setup-java@v3
         with:

From 7ef005006b76875fcc7bca3c670b69bd544a4112 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Tue, 21 Mar 2023 15:07:51 -0400
Subject: [PATCH 46/59] Safety null check for dismount check code

---
 .../player/BedrockInteractTranslator.java     | 30 ++++++++++---------
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockInteractTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockInteractTranslator.java
index 22a895465..93d0c4a83 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockInteractTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockInteractTranslator.java
@@ -79,21 +79,23 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
                 session.sendDownstreamPacket(sneakPacket);
 
                 Entity currentVehicle = session.getPlayerEntity().getVehicle();
-                session.setMountVehicleScheduledFuture(session.scheduleInEventLoop(() -> {
-                    if (session.getPlayerEntity().getVehicle() == null) {
-                        return;
-                    }
+                if (currentVehicle != null) {
+                    session.setMountVehicleScheduledFuture(session.scheduleInEventLoop(() -> {
+                        if (session.getPlayerEntity().getVehicle() == null) {
+                            return;
+                        }
 
-                    long vehicleBedrockId = currentVehicle.getGeyserId();
-                    if (session.getPlayerEntity().getVehicle().getGeyserId() == vehicleBedrockId) {
-                        // The Bedrock client, as of 1.19.51, dismounts on its end. The server may not agree with this.
-                        // If the server doesn't agree with our dismount (sends a packet saying we dismounted),
-                        // then remount the player.
-                        SetEntityLinkPacket linkPacket = new SetEntityLinkPacket();
-                        linkPacket.setEntityLink(new EntityLinkData(vehicleBedrockId, session.getPlayerEntity().getGeyserId(), EntityLinkData.Type.PASSENGER, true, false));
-                        session.sendUpstreamPacket(linkPacket);
-                    }
-                }, 1, TimeUnit.SECONDS));
+                        long vehicleBedrockId = currentVehicle.getGeyserId();
+                        if (session.getPlayerEntity().getVehicle().getGeyserId() == vehicleBedrockId) {
+                            // The Bedrock client, as of 1.19.51, dismounts on its end. The server may not agree with this.
+                            // If the server doesn't agree with our dismount (sends a packet saying we dismounted),
+                            // then remount the player.
+                            SetEntityLinkPacket linkPacket = new SetEntityLinkPacket();
+                            linkPacket.setEntityLink(new EntityLinkData(vehicleBedrockId, session.getPlayerEntity().getGeyserId(), EntityLinkData.Type.PASSENGER, true, false));
+                            session.sendUpstreamPacket(linkPacket);
+                        }
+                    }, 1, TimeUnit.SECONDS));
+                }
                 break;
             case MOUSEOVER:
                 // Handle the buttons for mobile - "Mount", etc; and the suggestions for console - "ZL: Mount", etc

From 96260cc35879b7446b62303d3a4edc82a8577a3c Mon Sep 17 00:00:00 2001
From: Kas-tle <26531652+Kas-tle@users.noreply.github.com>
Date: Thu, 23 Mar 2023 21:57:40 -0700
Subject: [PATCH 47/59] Bring Rain/Thunder Behavior Inline With Java (#3637)

Closes #3611 Closes #2588 Closes #2499

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>
---
 .../java/level/JavaGameEventTranslator.java   | 67 ++++++++++---------
 1 file changed, 35 insertions(+), 32 deletions(-)

diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java
index 05e14c41b..7019838c1 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java
@@ -47,21 +47,23 @@ import org.geysermc.geyser.translator.protocol.Translator;
 
 @Translator(packet = ClientboundGameEventPacket.class)
 public class JavaGameEventTranslator extends PacketTranslator<ClientboundGameEventPacket> {
+    // Strength of rainstorms and thunderstorms is a 0-1 float on Java, while on Bedrock it is a 0-65535 int
+    private static final int MAX_STORM_STRENGTH = 65535;
 
     @Override
     public void translate(GeyserSession session, ClientboundGameEventPacket packet) {
         PlayerEntity entity = session.getPlayerEntity();
 
         switch (packet.getNotification()) {
+            // Yes, START_RAIN and STOP_RAIN are swapped in terms of what they cause the client to do.
+            // This is how the Mojang mappings name them, so we go with it
+            // It seems Mojang's intent was that START_RAIN would set the rain strength to 0 so that it can then be incremeneted on a gradient by the server
+            // The inverse is true for STOP_RAIN
+            // This is indeed the behavior of the vanilla server
+            // However, it seems most server software (at least Spigot and Paper) did not go along with this
+            // As a result many developers use these packets for the opposite of what their names implies
+            // Behavior last verified with Java 1.19.4 and Bedrock 1.19.71
             case START_RAIN:
-                LevelEventPacket startRainPacket = new LevelEventPacket();
-                startRainPacket.setType(LevelEventType.START_RAINING);
-                startRainPacket.setData(Integer.MAX_VALUE);
-                startRainPacket.setPosition(Vector3f.ZERO);
-                session.sendUpstreamPacket(startRainPacket);
-                session.setRaining(true);
-                break;
-            case STOP_RAIN:
                 LevelEventPacket stopRainPacket = new LevelEventPacket();
                 stopRainPacket.setType(LevelEventType.STOP_RAINING);
                 stopRainPacket.setData(0);
@@ -69,34 +71,35 @@ public class JavaGameEventTranslator extends PacketTranslator<ClientboundGameEve
                 session.sendUpstreamPacket(stopRainPacket);
                 session.setRaining(false);
                 break;
+            case STOP_RAIN:
+                LevelEventPacket startRainPacket = new LevelEventPacket();
+                startRainPacket.setType(LevelEventType.START_RAINING);
+                startRainPacket.setData(MAX_STORM_STRENGTH);
+                startRainPacket.setPosition(Vector3f.ZERO);
+                session.sendUpstreamPacket(startRainPacket);
+                session.setRaining(true);
+                break;
             case RAIN_STRENGTH:
-                // While the above values are used, they CANNOT BE TRUSTED on a vanilla server as they are swapped around
-                // Spigot and forks implement it correctly
-                // Rain strength is your best way for determining if there is any rain
-                RainStrengthValue value = (RainStrengthValue) packet.getValue();
-                boolean isCurrentlyRaining = value.getStrength() > 0f;
-                // Java sends the rain level. Bedrock doesn't care, so we don't care if it's already raining.
-                if (isCurrentlyRaining != session.isRaining()) {
-                    LevelEventPacket changeRainPacket = new LevelEventPacket();
-                    changeRainPacket.setType(isCurrentlyRaining ? LevelEventType.START_RAINING : LevelEventType.STOP_RAINING);
-                    changeRainPacket.setData(Integer.MAX_VALUE); // Dunno what this does; used to be implemented with ThreadLocalRandom
-                    changeRainPacket.setPosition(Vector3f.ZERO);
-                    session.sendUpstreamPacket(changeRainPacket);
-                    session.setRaining(isCurrentlyRaining);
-                }
+                float rainStrength = ((RainStrengthValue) packet.getValue()).getStrength();
+                boolean isCurrentlyRaining = rainStrength > 0f;
+                LevelEventPacket changeRainPacket = new LevelEventPacket();
+                changeRainPacket.setType(isCurrentlyRaining ? LevelEventType.START_RAINING : LevelEventType.STOP_RAINING);
+                // This is the rain strength on LevelEventType.START_RAINING, but can be any value on LevelEventType.STOP_RAINING
+                changeRainPacket.setData((int) (rainStrength * MAX_STORM_STRENGTH));
+                changeRainPacket.setPosition(Vector3f.ZERO);
+                session.sendUpstreamPacket(changeRainPacket);
+                session.setRaining(isCurrentlyRaining);
                 break;
             case THUNDER_STRENGTH:
                 // See above, same process
-                ThunderStrengthValue thunderValue = (ThunderStrengthValue) packet.getValue();
-                boolean isCurrentlyThundering = thunderValue.getStrength() > 0f;
-                if (isCurrentlyThundering != session.isThunder()) {
-                    LevelEventPacket changeThunderPacket = new LevelEventPacket();
-                    changeThunderPacket.setType(isCurrentlyThundering ? LevelEventType.START_THUNDERSTORM : LevelEventType.STOP_THUNDERSTORM);
-                    changeThunderPacket.setData(Integer.MAX_VALUE);
-                    changeThunderPacket.setPosition(Vector3f.ZERO);
-                    session.sendUpstreamPacket(changeThunderPacket);
-                    session.setThunder(isCurrentlyThundering);
-                }
+                float thunderStrength = ((ThunderStrengthValue) packet.getValue()).getStrength();
+                boolean isCurrentlyThundering = thunderStrength > 0f;
+                LevelEventPacket changeThunderPacket = new LevelEventPacket();
+                changeThunderPacket.setType(isCurrentlyThundering ? LevelEventType.START_THUNDERSTORM : LevelEventType.STOP_THUNDERSTORM);
+                changeThunderPacket.setData((int) (thunderStrength * MAX_STORM_STRENGTH));
+                changeThunderPacket.setPosition(Vector3f.ZERO);
+                session.sendUpstreamPacket(changeThunderPacket);
+                session.setThunder(isCurrentlyThundering);
                 break;
             case CHANGE_GAMEMODE:
                 GameMode gameMode = (GameMode) packet.getValue();

From 7474d2c74565823842dbc251f75736bdbd4119ef Mon Sep 17 00:00:00 2001
From: onebeastchris <github@onechris.mozmail.com>
Date: Sun, 26 Mar 2023 03:14:04 +0200
Subject: [PATCH 48/59] show sweeping edge enchantment (#3615)

---
 .../item/nbt/EnchantmentTranslator.java       | 61 +++++++++++++------
 1 file changed, 43 insertions(+), 18 deletions(-)

diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/EnchantmentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/EnchantmentTranslator.java
index 204981965..5a61b483d 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/EnchantmentTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/EnchantmentTranslator.java
@@ -25,11 +25,14 @@
 
 package org.geysermc.geyser.translator.inventory.item.nbt;
 
+import com.github.steveice10.mc.protocol.data.game.Identifier;
 import com.github.steveice10.opennbt.tag.builtin.*;
 import org.geysermc.geyser.GeyserImpl;
 import org.geysermc.geyser.inventory.item.Enchantment;
 import org.geysermc.geyser.registry.type.ItemMapping;
 import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.text.ChatColor;
+import org.geysermc.geyser.text.MinecraftLocale;
 import org.geysermc.geyser.translator.inventory.item.ItemRemapper;
 import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator;
 
@@ -43,28 +46,27 @@ public class EnchantmentTranslator extends NbtItemStackTranslator {
     @Override
     public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) {
         List<Tag> newTags = new ArrayList<>();
-        Tag enchantmentTag = itemTag.get("Enchantments");
+        Tag enchantmentTag = itemTag.remove("Enchantments");
         if (enchantmentTag instanceof ListTag listTag) {
             for (Tag tag : listTag.getValue()) {
                 if (!(tag instanceof CompoundTag)) continue;
-
-                CompoundTag bedrockTag = remapEnchantment((CompoundTag) tag);
-                newTags.add(bedrockTag);
-            }
-            itemTag.remove("Enchantments");
-        }
-        enchantmentTag = itemTag.get("StoredEnchantments");
-        if (enchantmentTag instanceof ListTag listTag) {
-            for (Tag tag : listTag.getValue()) {
-                if (!(tag instanceof CompoundTag)) continue;
-
-                CompoundTag bedrockTag = remapEnchantment((CompoundTag) tag);
+                CompoundTag bedrockTag = remapEnchantment(session, (CompoundTag) tag, itemTag);
+                if (bedrockTag != null) {
+                    newTags.add(bedrockTag);
+                }
+            }
+        }
+
+        // TODO consolidate this into EnchantedBookTranslator
+        enchantmentTag = itemTag.remove("StoredEnchantments");
+        if (enchantmentTag instanceof ListTag listTag) {
+            for (Tag tag : listTag.getValue()) {
+                if (!(tag instanceof CompoundTag)) continue;
+                CompoundTag bedrockTag = remapEnchantment(session, (CompoundTag) tag, itemTag);
                 if (bedrockTag != null) {
-                    bedrockTag.put(new ShortTag("GeyserStoredEnchantment", (short) 0));
                     newTags.add(bedrockTag);
                 }
             }
-            itemTag.remove("StoredEnchantments");
         }
 
         if (!newTags.isEmpty()) {
@@ -99,7 +101,6 @@ public class EnchantmentTranslator extends NbtItemStackTranslator {
                 javaValue.put("lvl", new IntTag("lvl", levelTag != null ? levelTag.getValue() : 1));
                 javaTag.setValue(javaValue);
 
-
                 if (geyserStoredEnchantmentTag != null) {
                     tagValue.remove("GeyserStoredEnchantment");
                     storedEnchantments.add(javaTag);
@@ -120,13 +121,20 @@ public class EnchantmentTranslator extends NbtItemStackTranslator {
     }
 
 
-    private CompoundTag remapEnchantment(CompoundTag tag) {
+    private CompoundTag remapEnchantment(GeyserSession session, CompoundTag tag, CompoundTag rootTag) {
         Tag javaEnchId = tag.get("id");
         if (!(javaEnchId instanceof StringTag))
             return null;
 
         Enchantment enchantment = Enchantment.getByJavaIdentifier(((StringTag) javaEnchId).getValue());
         if (enchantment == null) {
+            if (Identifier.formalize((String) javaEnchId.getValue()).equals("minecraft:sweeping")) {
+                Tag javaEnchLvl = tag.get("lvl");
+                int sweepingLvl = javaEnchLvl != null && javaEnchLvl.getValue() instanceof Number lvl ? lvl.intValue() : 0;
+
+                addSweeping(session, rootTag, sweepingLvl);
+                return null;
+            }
             GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment while NBT item translating: " + javaEnchId.getValue());
             return null;
         }
@@ -140,4 +148,21 @@ public class EnchantmentTranslator extends NbtItemStackTranslator {
         return bedrockTag;
     }
 
-}
+    private void addSweeping(GeyserSession session, CompoundTag itemTag, int level) {
+        CompoundTag displayTag = itemTag.get("display");
+        if (displayTag == null) {
+            displayTag = new CompoundTag("display");
+            itemTag.put(displayTag);
+        }
+        ListTag loreTag = displayTag.get("Lore");
+        if (loreTag == null) {
+            loreTag = new ListTag("Lore");
+            displayTag.put(loreTag);
+        }
+
+        String sweepingTranslation = MinecraftLocale.getLocaleString("enchantment.minecraft.sweeping", session.locale());
+        String lvlTranslation = MinecraftLocale.getLocaleString("enchantment.level." + level, session.locale());
+
+        loreTag.add(new StringTag("", ChatColor.RESET + ChatColor.GRAY + sweepingTranslation + " " + lvlTranslation));
+    }
+}
\ No newline at end of file

From 323394d2b50d6df5bab1b483a337f045e908300d Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Wed, 22 Mar 2023 11:10:04 -0400
Subject: [PATCH 49/59] Clean up jar file classes a bit

---
 bootstrap/fabric/build.gradle.kts             | 16 ++++++++++++++++
 bootstrap/spigot/build.gradle.kts             |  1 +
 .../geyser.shadow-conventions.gradle.kts      |  5 +++++
 .../geyser/session/GeyserSession.java         | 19 ++++++++++++++++---
 4 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/bootstrap/fabric/build.gradle.kts b/bootstrap/fabric/build.gradle.kts
index 890f5d656..af9c4547d 100644
--- a/bootstrap/fabric/build.gradle.kts
+++ b/bootstrap/fabric/build.gradle.kts
@@ -66,6 +66,22 @@ tasks {
         relocate("org.yaml", "org.geysermc.relocate.yaml") // https://github.com/CardboardPowered/cardboard/issues/139
         relocate("com.fasterxml.jackson", "org.geysermc.relocate.jackson")
         relocate("net.kyori", "org.geysermc.relocate.kyori")
+
+        dependencies {
+            // Exclude everything EXCEPT KQueue and some DNS stuff required for HAProxyc
+            exclude(dependency("io.netty:netty-transport-classes-epoll:.*"))
+            exclude(dependency("io.netty:netty-transport-native-epoll:.*"))
+            exclude(dependency("io.netty:netty-transport-native-unix-common:.*"))
+            exclude(dependency("io.netty:netty-transport-native-kqueue:.*"))
+            exclude(dependency("io.netty:netty-handler:.*"))
+            exclude(dependency("io.netty:netty-common:.*"))
+            exclude(dependency("io.netty:netty-buffer:.*"))
+            exclude(dependency("io.netty:netty-resolver:.*"))
+            exclude(dependency("io.netty:netty-transport:.*"))
+            exclude(dependency("io.netty:netty-codec:.*"))
+            exclude(dependency("io.netty:netty-resolver-dns:.*"))
+            exclude(dependency("io.netty:netty-resolver-dns-native-macos:.*"))
+        }
     }
 
     remapJar {
diff --git a/bootstrap/spigot/build.gradle.kts b/bootstrap/spigot/build.gradle.kts
index b5ef4e69e..da4e5af33 100644
--- a/bootstrap/spigot/build.gradle.kts
+++ b/bootstrap/spigot/build.gradle.kts
@@ -44,6 +44,7 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
 
         // We cannot shade Netty, or else native libraries will not load
         // Needed because older Spigot builds do not provide the haproxy module
+        exclude(dependency("io.netty:netty-transport-classes-epoll:.*"))
         exclude(dependency("io.netty:netty-transport-native-epoll:.*"))
         exclude(dependency("io.netty:netty-transport-native-unix-common:.*"))
         exclude(dependency("io.netty:netty-transport-native-kqueue:.*"))
diff --git a/build-logic/src/main/kotlin/geyser.shadow-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.shadow-conventions.gradle.kts
index 395beb104..dde85c33a 100644
--- a/build-logic/src/main/kotlin/geyser.shadow-conventions.gradle.kts
+++ b/build-logic/src/main/kotlin/geyser.shadow-conventions.gradle.kts
@@ -24,6 +24,11 @@ tasks {
                     exclude(dependency(string))
                 }
             }
+
+            sJar.dependencies {
+                exclude(dependency("org.checkerframework:checker-qual:.*"))
+                exclude(dependency("org.jetbrains:annotations:.*"))
+            }
         }
     }
     named("build") {
diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
index d76cc4b97..e245d0f56 100644
--- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
+++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
@@ -732,7 +732,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
                 return;
             }
 
-            connectDownstream();
+            try {
+                connectDownstream();
+            } catch (Throwable t) {
+                t.printStackTrace();
+            }
         });
     }
 
@@ -776,7 +780,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
                 return;
             }
 
-            connectDownstream();
+            try {
+                connectDownstream();
+            } catch (Throwable t) {
+                t.printStackTrace();
+            }
         });
     }
 
@@ -850,7 +858,12 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
                         selectedProfile,
                         service.getAccessToken()
                 );
-                connectDownstream();
+                try {
+                    connectDownstream();
+                } catch (Throwable t) {
+                    t.printStackTrace();
+                    return false;
+                }
 
                 // Save our refresh token for later use
                 geyser.saveRefreshToken(bedrockUsername(), service.getRefreshToken());

From a7c04d53237a1d3d6ebea8063638d4f776452585 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Sun, 26 Mar 2023 13:20:39 -0400
Subject: [PATCH 50/59] Fix #3619

---
 .../geyser/registry/populator/ItemRegistryPopulator.java         | 1 +
 1 file changed, 1 insertion(+)

diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java
index 9b4ae99a2..427ab2454 100644
--- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java
+++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java
@@ -286,6 +286,7 @@ public class ItemRegistryPopulator {
             Set<String> javaOnlyItems = new ObjectOpenHashSet<>();
             Collections.addAll(javaOnlyItems, "minecraft:spectral_arrow", "minecraft:debug_stick",
                     "minecraft:knowledge_book", "minecraft:tipped_arrow", "minecraft:bundle");
+            javaOnlyItems.add("minecraft:decorated_pot"); // TODO 1.19.80 resolve probs?
             if (!customItemsAllowed) {
                 javaOnlyItems.add("minecraft:furnace_minecart");
             }

From 2a8d8b6cdfcfbcd633262bf380fab3ca58597e86 Mon Sep 17 00:00:00 2001
From: Kas-tle <26531652+Kas-tle@users.noreply.github.com>
Date: Tue, 28 Mar 2023 08:18:21 -0700
Subject: [PATCH 51/59] Set Shulker Color by Default (#3648)

---
 .../geyser/entity/type/living/monster/ShulkerEntity.java | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ShulkerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ShulkerEntity.java
index ff1ba9ac3..e484dfc59 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ShulkerEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ShulkerEntity.java
@@ -43,6 +43,15 @@ public class ShulkerEntity extends GolemEntity {
         super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
         // Indicate that invisibility should be fixed through the resource pack
         setFlag(EntityFlag.BRIBED, true);
+
+    }
+
+    @Override
+    protected void initializeMetadata() {
+        super.initializeMetadata();
+        // As of 1.19.4, it seems Java no longer sends the shulker color if it's the default color on initial spawn
+        // We still need the special case for 16 color in setShulkerColor though as it will send it for an entity metadata update
+        dirtyMetadata.put(EntityData.VARIANT, 16);
     }
 
     public void setAttachedFace(EntityMetadata<Direction, ?> entityMetadata) {

From 45e043c6e9d229b57979b33d006a06d4e247f327 Mon Sep 17 00:00:00 2001
From: Tydium <67938521+Tydium@users.noreply.github.com>
Date: Tue, 28 Mar 2023 14:35:22 -0400
Subject: [PATCH 52/59] Fix Custom Model Data not working on Potions. (#3616)

---
 .../inventory/item/PotionTranslator.java       | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/PotionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/PotionTranslator.java
index 3e814a098..68985ae5e 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/PotionTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/PotionTranslator.java
@@ -48,15 +48,23 @@ public class PotionTranslator extends ItemTranslator {
         if (itemStack.getNbt() == null) return super.translateToBedrock(itemStack, mapping, mappings);
         Tag potionTag = itemStack.getNbt().get("Potion");
         if (potionTag instanceof StringTag) {
-            Potion potion = Potion.getByJavaIdentifier(((StringTag) potionTag).getValue());
-            if (potion != null) {
+            int customItemId = CustomItemTranslator.getCustomItem(itemStack.getNbt(), mapping);
+            if (customItemId == -1) {
+                Potion potion = Potion.getByJavaIdentifier(((StringTag) potionTag).getValue());
+                if (potion != null) {
+                    return ItemData.builder()
+                            .id(mapping.getBedrockId())
+                            .damage(potion.getBedrockId())
+                            .count(itemStack.getAmount())
+                            .tag(translateNbtToBedrock(itemStack.getNbt()));
+                }
+                GeyserImpl.getInstance().getLogger().debug("Unknown Java potion: " + potionTag.getValue());
+            } else {
                 return ItemData.builder()
-                        .id(mapping.getBedrockId())
-                        .damage(potion.getBedrockId())
+                        .id(customItemId)
                         .count(itemStack.getAmount())
                         .tag(translateNbtToBedrock(itemStack.getNbt()));
             }
-            GeyserImpl.getInstance().getLogger().debug("Unknown Java potion: " + potionTag.getValue());
         }
         return super.translateToBedrock(itemStack, mapping, mappings);
     }

From 95236b37e05b53ce1cdd7f279672c62f7c0bc9a6 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Tue, 28 Mar 2023 18:48:48 -0400
Subject: [PATCH 53/59] Add support for basic display entities

---
 .../geyser/entity/EntityDefinitions.java      | 23 ++++++++
 .../geyser/entity/type/TextDisplayEntity.java | 55 +++++++++++++++++++
 2 files changed, 78 insertions(+)
 create mode 100644 core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java

diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java
index 41a88f64f..8656be098 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java
@@ -148,6 +148,7 @@ public final class EntityDefinitions {
     public static final EntityDefinition<AbstractSkeletonEntity> STRAY;
     public static final EntityDefinition<StriderEntity> STRIDER;
     public static final EntityDefinition<TadpoleEntity> TADPOLE;
+    public static final EntityDefinition<TextDisplayEntity> TEXT_DISPLAY;
     public static final EntityDefinition<TNTEntity> TNT;
     public static final EntityDefinition<MinecartEntity> TNT_MINECART;
     public static final EntityDefinition<TraderLlamaEntity> TRADER_LLAMA;
@@ -295,6 +296,28 @@ public final class EntityDefinitions {
                     .addTranslator(MetadataType.INT, TNTEntity::setFuseLength)
                     .build();
 
+            EntityDefinition<Entity> displayBase = EntityDefinition.inherited(entityBase.factory(), entityBase)
+                    .addTranslator(null) // Interpolation start ticks
+                    .addTranslator(null) // Interpolation duration ID
+                    .addTranslator(null) // Translation
+                    .addTranslator(null) // Scale
+                    .addTranslator(null) // Left rotation
+                    .addTranslator(null) // Right rotation
+                    .addTranslator(null) // Billboard render constraints
+                    .addTranslator(null) // Brightness override
+                    .addTranslator(null) // View range
+                    .addTranslator(null) // Shadow radius
+                    .addTranslator(null) // Shadow strength
+                    .addTranslator(null) // Width
+                    .addTranslator(null) // Height
+                    .addTranslator(null) // Glow color override
+                    .build();
+            TEXT_DISPLAY = EntityDefinition.inherited(TextDisplayEntity::new, displayBase)
+                    .type(EntityType.TEXT_DISPLAY)
+                    .identifier("minecraft:armor_stand")
+                    .addTranslator(MetadataType.CHAT, TextDisplayEntity::setText)
+                    .build();
+
             EntityDefinition<FireballEntity> fireballBase = EntityDefinition.inherited(FireballEntity::new, entityBase)
                     .addTranslator(null) // Item
                     .build();
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java
new file mode 100644
index 000000000..fecca8ac0
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019-2023 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.entity.type;
+
+import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
+import com.nukkitx.math.vector.Vector3f;
+import com.nukkitx.protocol.bedrock.data.entity.EntityData;
+import net.kyori.adventure.text.Component;
+import org.geysermc.geyser.entity.EntityDefinition;
+import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.translator.text.MessageTranslator;
+
+import java.util.UUID;
+
+// Note: 1.19.4 requires that the billboard is set to something in order to show, on Java Edition
+public class TextDisplayEntity extends Entity {
+    public TextDisplayEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
+        super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
+    }
+
+    @Override
+    protected void initializeMetadata() {
+        super.initializeMetadata();
+        // Remove armor stand body
+        this.dirtyMetadata.put(EntityData.SCALE, 0f);
+        this.dirtyMetadata.put(EntityData.NAMETAG_ALWAYS_SHOW, (byte) 1);
+    }
+
+    public void setText(EntityMetadata<Component, ?> entityMetadata) {
+        this.dirtyMetadata.put(EntityData.NAMETAG, MessageTranslator.convertMessage(entityMetadata.getValue()));
+    }
+}

From ed99655ed9f1b666aa37f48c57cf6e1ed54370dc Mon Sep 17 00:00:00 2001
From: Kas-tle <26531652+Kas-tle@users.noreply.github.com>
Date: Thu, 30 Mar 2023 08:02:12 -0700
Subject: [PATCH 54/59] Do Modrinth Publish in build.yml (#3644)

* Migrate modrinth publish and edit caching

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Address review from tim

---------

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>
---
 .github/workflows/build.yml   | 29 ++++++++++++++++-------------
 .github/workflows/publish.yml | 31 -------------------------------
 2 files changed, 16 insertions(+), 44 deletions(-)
 delete mode 100644 .github/workflows/publish.yml

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 668c9ca72..ca8b63cc4 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -23,25 +23,19 @@ jobs:
         with:
           submodules: recursive
 
+      - name: Validate Gradle Wrapper
+        uses: gradle/wrapper-validation-action@v1
+
       - uses: actions/setup-java@v3
         with:
           java-version: 17
           distribution: temurin
           
-      - name: Cache Gradle Packages
-        uses: actions/cache@v3
-        with:
-          path: | 
-            ~/.m2
-            ~/.gradle/caches
-            ~/.gradle/wrapper
-          key: ${{ github.ref_name }}-gradle-${{ hashFiles('*.gradle.kts', 'gradle.properties', 'gradlew', 'gradle/*', 'gradle/**/*', 'build-logic/*', 'build-logic/**/**/**/*', '**/*.gradle.kts', '**/**/*.gradle.kts') }}
-          restore-keys: ${{ github.ref_name }}-gradle-
-
       - name: Build
         uses: gradle/gradle-build-action@v2
         with:
-          arguments: build --no-daemon
+          arguments: build
+          gradle-home-cache-cleanup: true
           
       - name: Archive artifacts (Geyser Fabric)
         uses: actions/upload-artifact@v3
@@ -87,7 +81,7 @@ jobs:
           if-no-files-found: error
 
       - name: Publish to Maven Repository
-        if: ${{ job.status == 'success' && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
+        if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
         uses: gradle/gradle-build-action@v2
         env:
           ORG_GRADLE_PROJECT_geysermcUsername: ${{ vars.DEPLOY_USER }}
@@ -96,7 +90,7 @@ jobs:
           arguments: publish
 
       - name: Publish to Downloads API
-        if: ${{ github.ref_name == 'master' && job.status == 'success' && github.repository == 'GeyserMC/Geyser' }}
+        if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
         shell: bash
         env:
           DOWNLOADS_USERNAME: ${{ vars.DOWNLOADS_USERNAME }}
@@ -119,6 +113,15 @@ jobs:
           echo "{\"project\": \"$project\", \"version\": \"$version\", \"id\": $GITHUB_RUN_NUMBER, \"commit\": \"$GITHUB_SHA\"}" > metadata.json
           rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$project/$GITHUB_RUN_NUMBER/
 
+      - name: Publish to Modrinth
+        uses: gradle/gradle-build-action@v2
+        if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
+        env:
+          MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
+        with:
+          arguments: fabric:modrinth
+          gradle-home-cache-cleanup: true
+          
       - name: Notify Discord
         if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }}
         uses: Tim203/actions-git-discord-webhook@main
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
deleted file mode 100644
index 2b002b0de..000000000
--- a/.github/workflows/publish.yml
+++ /dev/null
@@ -1,31 +0,0 @@
-name: Publish
-on:
-  workflow_dispatch:
-  push:
-    paths-ignore:
-      - '.github/ISSUE_TEMPLATE/*.yml'
-      - '.github/actions/pullrequest.yml'
-      - '.idea/copyright/*.xml'
-      - '.gitignore'
-      - 'CONTRIBUTING.md'
-      - 'LICENSE'
-      - 'Jenkinsfile '
-      - 'README.md'
-      - 'licenseheader.txt'
-
-jobs:
-  build:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v3
-        with:
-          submodules: recursive
-      - uses: gradle/wrapper-validation-action@v1
-      - uses: actions/setup-java@v3
-        with:
-          distribution: 'temurin'
-          java-version: 17
-      - name: Publish to Modrinth
-        env:
-          MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
-        run: ./gradlew fabric:modrinth
\ No newline at end of file

From cd80ee893cb8c2c5e3482971395434a2b59831f7 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Thu, 30 Mar 2023 15:27:00 -0400
Subject: [PATCH 55/59] Potentially fix Modrinth token caching

---
 bootstrap/fabric/build.gradle.kts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/bootstrap/fabric/build.gradle.kts b/bootstrap/fabric/build.gradle.kts
index af9c4547d..35270df80 100644
--- a/bootstrap/fabric/build.gradle.kts
+++ b/bootstrap/fabric/build.gradle.kts
@@ -94,6 +94,7 @@ tasks {
 }
 
 modrinth {
+    token.set(System.getenv("MODRINTH_TOKEN")) // Even though this is the default value, apparently this prevents GitHub Actions caching the token?
     projectId.set("wKkoqHrH")
     versionNumber.set(project.version as String + "-" + System.getenv("GITHUB_RUN_NUMBER"))
     versionType.set("beta")

From e2535108e6801ecf4f2a3fe276ced7e4d021d8b3 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Thu, 30 Mar 2023 15:44:55 -0400
Subject: [PATCH 56/59] Folia support and preparations for future changes

---
 .../world/GeyserFabricWorldManager.java       | 139 +++++++-----
 bootstrap/spigot/build.gradle.kts             |   7 +-
 .../spigot/GeyserPaperPingPassthrough.java    |   4 +-
 .../spigot/GeyserSpigotPingPassthrough.java   |   2 +-
 .../platform/spigot/ReflectedNames.java       |   8 +-
 .../spigot/world/GeyserPistonListener.java    |   4 +-
 .../manager/GeyserSpigotWorldManager.java     | 180 +++++++--------
 .../spigot/src/main/resources/plugin.yml      |   1 +
 core/build.gradle.kts                         |   4 +
 .../java/org/geysermc/geyser/GeyserImpl.java  |  16 ++
 .../geyser/entity/type/FishingHookEntity.java |   3 +-
 .../geyser/entity/type/ItemEntity.java        |  11 +-
 .../entity/type/living/SquidEntity.java       |  13 +-
 .../AbstractGeyserboundPacketHandler.java     |  88 ++++++++
 .../erosion/GeyserErosionPacketSender.java    |  60 +++++
 .../GeyserboundHandshakePacketHandler.java    |  72 ++++++
 .../erosion/GeyserboundPacketHandlerImpl.java | 209 ++++++++++++++++++
 .../erosion/UnixSocketClientListener.java     |  70 ++++++
 .../geyser/level/GeyserWorldManager.java      |  92 +++++++-
 .../geysermc/geyser/level/WorldManager.java   |  39 +++-
 .../level/block/BlockPositionIterator.java    |  80 -------
 .../level/physics/CollisionManager.java       |  11 +-
 .../geysermc/geyser/pack/ResourcePack.java    |  20 +-
 .../geyser/session/GeyserSession.java         |  15 +-
 .../inventory/LecternInventoryTranslator.java |  23 +-
 .../inventory/item/nbt/BannerTranslator.java  |  13 +-
 .../level/block/entity/PistonBlockEntity.java |   2 +-
 .../BedrockBlockPickRequestTranslator.java    |  32 ++-
 .../java/JavaCustomPayloadTranslator.java     | 129 ++++++-----
 .../protocol/java/JavaLoginTranslator.java    |  10 +
 .../java/level/JavaBlockEventTranslator.java  |   9 +-
 .../java/level/JavaBlockUpdateTranslator.java |   2 +-
 .../level/JavaForgetLevelChunkTranslator.java |   2 +-
 .../JavaLevelChunkWithLightTranslator.java    |  22 +-
 .../util/collection/LecternHasBookMap.java    |  17 +-
 gradle/libs.versions.toml                     |  12 +-
 36 files changed, 999 insertions(+), 422 deletions(-)
 create mode 100644 core/src/main/java/org/geysermc/geyser/erosion/AbstractGeyserboundPacketHandler.java
 create mode 100644 core/src/main/java/org/geysermc/geyser/erosion/GeyserErosionPacketSender.java
 create mode 100644 core/src/main/java/org/geysermc/geyser/erosion/GeyserboundHandshakePacketHandler.java
 create mode 100644 core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java
 create mode 100644 core/src/main/java/org/geysermc/geyser/erosion/UnixSocketClientListener.java
 delete mode 100644 core/src/main/java/org/geysermc/geyser/level/block/BlockPositionIterator.java

diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java
index b003a76ba..dc81315d2 100644
--- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java
+++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java
@@ -25,6 +25,7 @@
 
 package org.geysermc.geyser.platform.fabric.world;
 
+import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo;
 import com.nukkitx.math.vector.Vector3i;
 import com.nukkitx.nbt.NbtMap;
 import com.nukkitx.nbt.NbtMapBuilder;
@@ -40,16 +41,16 @@ import net.minecraft.world.item.WrittenBookItem;
 import net.minecraft.world.level.block.entity.BannerBlockEntity;
 import net.minecraft.world.level.block.entity.BlockEntity;
 import net.minecraft.world.level.block.entity.LecternBlockEntity;
+import net.minecraft.world.level.chunk.LevelChunk;
+import org.geysermc.erosion.util.LecternUtils;
 import org.geysermc.geyser.level.GeyserWorldManager;
 import org.geysermc.geyser.session.GeyserSession;
-import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator;
 import org.geysermc.geyser.util.BlockEntityUtils;
 
 import javax.annotation.Nonnull;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeUnit;
 
 public class GeyserFabricWorldManager extends GeyserWorldManager {
     private final MinecraftServer server;
@@ -59,69 +60,91 @@ public class GeyserFabricWorldManager extends GeyserWorldManager {
     }
 
     @Override
-    public boolean shouldExpectLecternHandled() {
+    public boolean shouldExpectLecternHandled(GeyserSession session) {
         return true;
     }
 
     @Override
-    public NbtMap getLecternDataAt(GeyserSession session, int x, int y, int z, boolean isChunkLoad) {
-        Runnable lecternGet = () -> {
-            // Mostly a reimplementation of Spigot lectern support
+    public void sendLecternData(GeyserSession session, int x, int z, List<BlockEntityInfo> blockEntityInfos) {
+        server.execute(() -> {
             ServerPlayer player = getPlayer(session);
-            if (player != null) {
-                BlockEntity blockEntity = player.level.getBlockEntity(new BlockPos(x, y, z));
-                if (!(blockEntity instanceof LecternBlockEntity lectern)) {
-                    return;
-                }
-
-                if (!lectern.hasBook()) {
-                    if (!isChunkLoad) {
-                        BlockEntityUtils.updateBlockEntity(session, LecternInventoryTranslator.getBaseLecternTag(x, y, z, 0).build(), Vector3i.from(x, y, z));
-                    }
-                    return;
-                }
-
-                ItemStack book = lectern.getBook();
-                int pageCount = WrittenBookItem.getPageCount(book);
-                boolean hasBookPages = pageCount > 0;
-                NbtMapBuilder lecternTag = LecternInventoryTranslator.getBaseLecternTag(x, y, z, hasBookPages ? pageCount : 1);
-                lecternTag.putInt("page", lectern.getPage() / 2);
-                NbtMapBuilder bookTag = NbtMap.builder()
-                        .putByte("Count", (byte) book.getCount())
-                        .putShort("Damage", (short) 0)
-                        .putString("Name", "minecraft:writable_book");
-                List<NbtMap> pages = new ArrayList<>(hasBookPages ? pageCount : 1);
-                if (hasBookPages && WritableBookItem.makeSureTagIsValid(book.getTag())) {
-                    ListTag listTag = book.getTag().getList("pages", 8);
-
-                    for (int i = 0; i < listTag.size(); i++) {
-                        String page = listTag.getString(i);
-                        NbtMapBuilder pageBuilder = NbtMap.builder()
-                                .putString("photoname", "")
-                                .putString("text", page);
-                        pages.add(pageBuilder.build());
-                    }
-                } else {
-                    // Empty page
-                    NbtMapBuilder pageBuilder = NbtMap.builder()
-                            .putString("photoname", "")
-                            .putString("text", "");
-                    pages.add(pageBuilder.build());
-                }
-
-                bookTag.putCompound("tag", NbtMap.builder().putList("pages", NbtType.COMPOUND, pages).build());
-                lecternTag.putCompound("book", bookTag.build());
-                NbtMap blockEntityTag = lecternTag.build();
-                BlockEntityUtils.updateBlockEntity(session, blockEntityTag, Vector3i.from(x, y, z));
+            if (player == null) {
+                return;
             }
-        };
-        if (isChunkLoad) {
-            // Hacky hacks to allow lectern loading to be delayed
-            session.scheduleInEventLoop(() -> server.execute(lecternGet), 1, TimeUnit.SECONDS);
-        } else {
-            server.execute(lecternGet);
+
+            LevelChunk chunk = player.getLevel().getChunk(x, z);
+            final int chunkBlockX = x << 4;
+            final int chunkBlockZ = z << 4;
+            for (int i = 0; i < blockEntityInfos.size(); i++) {
+                BlockEntityInfo blockEntityInfo = blockEntityInfos.get(i);
+                BlockEntity blockEntity = chunk.getBlockEntity(new BlockPos(chunkBlockX + blockEntityInfo.getX(),
+                        blockEntityInfo.getY(), chunkBlockZ + blockEntityInfo.getZ()));
+                sendLecternData(session, blockEntity, true);
+            }
+        });
+    }
+
+    @Override
+    public void sendLecternData(GeyserSession session, int x, int y, int z) {
+        server.execute(() -> {
+            ServerPlayer player = getPlayer(session);
+            if (player == null) {
+                return;
+            }
+
+            BlockEntity blockEntity = player.level.getBlockEntity(new BlockPos(x, y, z));
+            sendLecternData(session, blockEntity, false);
+        });
+    }
+
+    private void sendLecternData(GeyserSession session, BlockEntity blockEntity, boolean isChunkLoad) {
+        if (!(blockEntity instanceof LecternBlockEntity lectern)) {
+            return;
         }
-        return LecternInventoryTranslator.getBaseLecternTag(x, y, z, 0).build();
+
+        int x = blockEntity.getBlockPos().getX();
+        int y = blockEntity.getBlockPos().getY();
+        int z = blockEntity.getBlockPos().getZ();
+
+        if (!lectern.hasBook()) {
+            if (!isChunkLoad) {
+                BlockEntityUtils.updateBlockEntity(session, LecternUtils.getBaseLecternTag(x, y, z, 0).build(), Vector3i.from(x, y, z));
+            }
+            return;
+        }
+
+        ItemStack book = lectern.getBook();
+        int pageCount = WrittenBookItem.getPageCount(book);
+        boolean hasBookPages = pageCount > 0;
+        NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(x, y, z, hasBookPages ? pageCount : 1);
+        lecternTag.putInt("page", lectern.getPage() / 2);
+        NbtMapBuilder bookTag = NbtMap.builder()
+                .putByte("Count", (byte) book.getCount())
+                .putShort("Damage", (short) 0)
+                .putString("Name", "minecraft:writable_book");
+        List<NbtMap> pages = new ArrayList<>(hasBookPages ? pageCount : 1);
+        if (hasBookPages && WritableBookItem.makeSureTagIsValid(book.getTag())) {
+            ListTag listTag = book.getTag().getList("pages", 8);
+
+            for (int i = 0; i < listTag.size(); i++) {
+                String page = listTag.getString(i);
+                NbtMapBuilder pageBuilder = NbtMap.builder()
+                        .putString("photoname", "")
+                        .putString("text", page);
+                pages.add(pageBuilder.build());
+            }
+        } else {
+            // Empty page
+            NbtMapBuilder pageBuilder = NbtMap.builder()
+                    .putString("photoname", "")
+                    .putString("text", "");
+            pages.add(pageBuilder.build());
+        }
+
+        bookTag.putCompound("tag", NbtMap.builder().putList("pages", NbtType.COMPOUND, pages).build());
+        lecternTag.putCompound("book", bookTag.build());
+        NbtMap blockEntityTag = lecternTag.build();
+        BlockEntityUtils.updateBlockEntity(session, blockEntityTag, Vector3i.from(x, y, z));
     }
 
     @Override
diff --git a/bootstrap/spigot/build.gradle.kts b/bootstrap/spigot/build.gradle.kts
index da4e5af33..aa7958732 100644
--- a/bootstrap/spigot/build.gradle.kts
+++ b/bootstrap/spigot/build.gradle.kts
@@ -1,5 +1,8 @@
 dependencies {
     api(projects.core)
+    api(libs.erosion.bukkit.common) {
+        isTransitive = false
+    }
 
     implementation(libs.adapters.spigot)
 
@@ -7,8 +10,8 @@ dependencies {
 
     implementation(libs.adventure.text.serializer.bungeecord)
     
-    // Both paper-api and paper-mojangapi only provide Java 17 versions for 1.19
-    compileOnly(libs.paper.api) {
+    // Both folia-api and paper-mojangapi only provide Java 17 versions for 1.19
+    compileOnly(libs.folia.api) {
         attributes {
             attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17)
         }
diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperPingPassthrough.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperPingPassthrough.java
index 36dd81d44..bb0f30e70 100644
--- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperPingPassthrough.java
+++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperPingPassthrough.java
@@ -59,13 +59,13 @@ public final class GeyserPaperPingPassthrough implements IGeyserPingPassthrough
             // runtime because we still have to shade in our own Adventure class. For now.
             PaperServerListPingEvent event;
             if (OLD_CONSTRUCTOR != null) {
-                // Approximately pre-1.19
+                // 1.19, removed in 1.19.4
                 event = OLD_CONSTRUCTOR.newInstance(new GeyserStatusClient(inetSocketAddress),
                         Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(),
                         Bukkit.getMaxPlayers(), Bukkit.getVersion(), GameProtocol.getJavaProtocolVersion(), null);
             } else {
                 event = new PaperServerListPingEvent(new GeyserStatusClient(inetSocketAddress),
-                        Bukkit.getMotd(), Bukkit.shouldSendChatPreviews(), Bukkit.getOnlinePlayers().size(),
+                        Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(),
                         Bukkit.getMaxPlayers(), Bukkit.getVersion(), GameProtocol.getJavaProtocolVersion(), null);
             }
             Bukkit.getPluginManager().callEvent(event);
diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPingPassthrough.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPingPassthrough.java
index 634d1f8a8..1e6a0ad6c 100644
--- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPingPassthrough.java
+++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPingPassthrough.java
@@ -66,7 +66,7 @@ public class GeyserSpigotPingPassthrough implements IGeyserPingPassthrough {
     private static class GeyserPingEvent extends ServerListPingEvent {
 
         public GeyserPingEvent(InetAddress address, String motd, int numPlayers, int maxPlayers) {
-            super(address, motd, Bukkit.shouldSendChatPreviews(), numPlayers, maxPlayers);
+            super("", address, motd, numPlayers, maxPlayers);
         }
 
         @Override
diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/ReflectedNames.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/ReflectedNames.java
index 3185f2d30..67e31fea2 100644
--- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/ReflectedNames.java
+++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/ReflectedNames.java
@@ -60,16 +60,16 @@ public final class ReflectedNames {
     }
 
     static Constructor<PaperServerListPingEvent> getOldPaperPingConstructor() {
-        if (getConstructor(PaperServerListPingEvent.class, StatusClient.class, String.class, boolean.class, int.class,
+        if (getConstructor(PaperServerListPingEvent.class, StatusClient.class, String.class, int.class,
                 int.class, String.class, int.class, CachedServerIcon.class) != null) {
-            // @NotNull StatusClient client, @NotNull String motd, boolean shouldSendChatPreviews, int numPlayers, int maxPlayers,
+            // @NotNull StatusClient client, @NotNull String motd, int numPlayers, int maxPlayers,
             //            @NotNull String version, int protocolVersion, @Nullable CachedServerIcon favicon
             // New constructor is present
             return null;
         }
-        // @NotNull StatusClient client, @NotNull String motd, int numPlayers, int maxPlayers,
+        // @NotNull StatusClient client, @NotNull String motd, boolean shouldSendChatPreviews, int numPlayers, int maxPlayers,
         //            @NotNull String version, int protocolVersion, @Nullable CachedServerIcon favicon
-        return getConstructor(PaperServerListPingEvent.class, StatusClient.class, String.class, int.class, int.class,
+        return getConstructor(PaperServerListPingEvent.class, StatusClient.class, String.class, boolean.class, int.class, int.class,
                 String.class, int.class, CachedServerIcon.class);
     }
 
diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java
index 5eb99e10c..d7f34c4b3 100644
--- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java
+++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java
@@ -27,8 +27,8 @@ package org.geysermc.geyser.platform.spigot.world;
 
 import com.github.steveice10.mc.protocol.data.game.level.block.value.PistonValueType;
 import com.nukkitx.math.vector.Vector3i;
+import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
 import it.unimi.dsi.fastutil.objects.Object2IntMap;
-import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
 import org.bukkit.Bukkit;
 import org.bukkit.Location;
 import org.bukkit.World;
@@ -85,7 +85,7 @@ public class GeyserPistonListener implements Listener {
         PistonValueType type = isExtend ? PistonValueType.PUSHING : PistonValueType.PULLING;
         boolean sticky = event.isSticky();
 
-        Object2IntMap<Vector3i> attachedBlocks = new Object2IntOpenHashMap<>();
+        Object2IntMap<Vector3i> attachedBlocks = new Object2IntArrayMap<>();
         boolean blocksFilled = false;
 
         for (Map.Entry<UUID, GeyserSession> entry : geyser.getSessionManager().getSessions().entrySet()) {
diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java
index cca982cbb..481953747 100644
--- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java
+++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java
@@ -25,33 +25,28 @@
 
 package org.geysermc.geyser.platform.spigot.world.manager;
 
+import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo;
 import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
-import com.github.steveice10.opennbt.tag.builtin.ListTag;
-import com.github.steveice10.opennbt.tag.builtin.Tag;
-import com.nukkitx.math.vector.Vector3i;
 import com.nukkitx.nbt.NbtMap;
-import com.nukkitx.nbt.NbtMapBuilder;
-import com.nukkitx.nbt.NbtType;
 import org.bukkit.Bukkit;
+import org.bukkit.Chunk;
 import org.bukkit.World;
-import org.bukkit.block.*;
-import org.bukkit.block.banner.Pattern;
+import org.bukkit.block.Block;
 import org.bukkit.entity.Player;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.BookMeta;
 import org.bukkit.plugin.Plugin;
+import org.geysermc.erosion.bukkit.BukkitLecterns;
+import org.geysermc.erosion.bukkit.BukkitUtils;
+import org.geysermc.erosion.bukkit.PickBlockUtils;
+import org.geysermc.erosion.bukkit.SchedulerUtils;
 import org.geysermc.geyser.level.GameRule;
 import org.geysermc.geyser.level.WorldManager;
 import org.geysermc.geyser.level.block.BlockStateValues;
 import org.geysermc.geyser.registry.BlockRegistries;
 import org.geysermc.geyser.session.GeyserSession;
-import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator;
-import org.geysermc.geyser.translator.inventory.item.nbt.BannerTranslator;
 import org.geysermc.geyser.util.BlockEntityUtils;
 import org.jetbrains.annotations.Nullable;
 
 import javax.annotation.Nonnull;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
 
@@ -60,9 +55,11 @@ import java.util.concurrent.CompletableFuture;
  */
 public class GeyserSpigotWorldManager extends WorldManager {
     private final Plugin plugin;
+    private final BukkitLecterns lecterns;
 
     public GeyserSpigotWorldManager(Plugin plugin) {
         this.plugin = plugin;
+        this.lecterns = new BukkitLecterns(plugin);
     }
 
     @Override
@@ -81,6 +78,12 @@ public class GeyserSpigotWorldManager extends WorldManager {
     }
 
     public int getBlockNetworkId(Block block) {
+        if (SchedulerUtils.FOLIA && !Bukkit.isOwnedByCurrentRegion(block)) {
+            // Terrible behavior, but this is basically what's always been happening behind the scenes anyway.
+            CompletableFuture<String> blockData = new CompletableFuture<>();
+            Bukkit.getRegionScheduler().execute(this.plugin, block.getLocation(), () -> blockData.complete(block.getBlockData().getAsString()));
+            return BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(blockData.join(), BlockStateValues.JAVA_AIR_ID);
+        }
         return BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(block.getBlockData().getAsString(), BlockStateValues.JAVA_AIR_ID);
     }
 
@@ -90,71 +93,64 @@ public class GeyserSpigotWorldManager extends WorldManager {
     }
 
     @Override
-    public NbtMap getLecternDataAt(GeyserSession session, int x, int y, int z, boolean isChunkLoad) {
-        // Run as a task to prevent async issues
-        Runnable lecternInfoGet = () -> {
-            Player bukkitPlayer;
-            if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
-                return;
-            }
-
-            Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z);
-            if (!(block.getState() instanceof Lectern lectern)) {
-                session.getGeyser().getLogger().error("Lectern expected at: " + Vector3i.from(x, y, z).toString() + " but was not! " + block.toString());
-                return;
-            }
-
-            ItemStack itemStack = lectern.getInventory().getItem(0);
-            if (itemStack == null || !(itemStack.getItemMeta() instanceof BookMeta bookMeta)) {
-                if (!isChunkLoad) {
-                    // We need to update the lectern since it's not going to be updated otherwise
-                    BlockEntityUtils.updateBlockEntity(session, LecternInventoryTranslator.getBaseLecternTag(x, y, z, 0).build(), Vector3i.from(x, y, z));
-                }
-                // We don't care; return
-                return;
-            }
-
-            // On the count: allow the book to show/open even there are no pages. We know there is a book here, after all, and this matches Java behavior
-            boolean hasBookPages = bookMeta.getPageCount() > 0;
-            NbtMapBuilder lecternTag = LecternInventoryTranslator.getBaseLecternTag(x, y, z, hasBookPages ? bookMeta.getPageCount() : 1);
-            lecternTag.putInt("page", lectern.getPage() / 2);
-            NbtMapBuilder bookTag = NbtMap.builder()
-                    .putByte("Count", (byte) itemStack.getAmount())
-                    .putShort("Damage", (short) 0)
-                    .putString("Name", "minecraft:writable_book");
-            List<NbtMap> pages = new ArrayList<>(bookMeta.getPageCount());
-            if (hasBookPages) {
-                for (String page : bookMeta.getPages()) {
-                    NbtMapBuilder pageBuilder = NbtMap.builder()
-                            .putString("photoname", "")
-                            .putString("text", page);
-                    pages.add(pageBuilder.build());
-                }
-            } else {
-                // Empty page
-                NbtMapBuilder pageBuilder = NbtMap.builder()
-                        .putString("photoname", "")
-                        .putString("text", "");
-                pages.add(pageBuilder.build());
-            }
-            
-            bookTag.putCompound("tag", NbtMap.builder().putList("pages", NbtType.COMPOUND, pages).build());
-            lecternTag.putCompound("book", bookTag.build());
-            NbtMap blockEntityTag = lecternTag.build();
-            BlockEntityUtils.updateBlockEntity(session, blockEntityTag, Vector3i.from(x, y, z));
-        };
-
-        if (isChunkLoad) {
-            // Delay to ensure the chunk is sent first, and then the lectern data
-            Bukkit.getScheduler().runTaskLater(this.plugin, lecternInfoGet, 5);
-        } else {
-            Bukkit.getScheduler().runTask(this.plugin, lecternInfoGet);
+    public void sendLecternData(GeyserSession session, int x, int y, int z) {
+        Player bukkitPlayer;
+        if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
+            return;
+        }
+
+        Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z);
+        // Run as a task to prevent async issues
+        SchedulerUtils.runTask(this.plugin, () -> sendLecternData(session, block, false), block);
+    }
+
+    public void sendLecternData(GeyserSession session, int x, int z, List<BlockEntityInfo> blockEntityInfos) {
+        Player bukkitPlayer;
+        if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
+            return;
+        }
+        if (SchedulerUtils.FOLIA) {
+            Chunk chunk = getChunk(bukkitPlayer.getWorld(), x, z);
+            if (chunk == null) {
+                return;
+            }
+            Bukkit.getRegionScheduler().execute(this.plugin, bukkitPlayer.getWorld(), x, z, () ->
+                sendLecternData(session, chunk, blockEntityInfos));
+        } else {
+            Bukkit.getScheduler().runTask(this.plugin, () -> {
+                Chunk chunk = getChunk(bukkitPlayer.getWorld(), x, z);
+                if (chunk == null) {
+                    return;
+                }
+                sendLecternData(session, chunk, blockEntityInfos);
+            });
+        }
+    }
+
+    private Chunk getChunk(World world, int x, int z) {
+        if (!world.isChunkLoaded(x, z)) {
+            return null;
+        }
+        return world.getChunkAt(x, z);
+    }
+
+    private void sendLecternData(GeyserSession session, Chunk chunk, List<BlockEntityInfo> blockEntityInfos) {
+        for (int i = 0; i < blockEntityInfos.size(); i++) {
+            BlockEntityInfo info = blockEntityInfos.get(i);
+            Block block = chunk.getBlock(info.getX(), info.getY(), info.getZ());
+            sendLecternData(session, block, true);
+        }
+    }
+
+    private void sendLecternData(GeyserSession session, Block block, boolean isChunkLoad) {
+        NbtMap blockEntityTag = this.lecterns.getLecternData(block, isChunkLoad);
+        if (blockEntityTag != null) {
+            BlockEntityUtils.updateBlockEntity(session, blockEntityTag, BukkitUtils.getVector(block.getLocation()));
         }
-        return LecternInventoryTranslator.getBaseLecternTag(x, y, z, 0).build(); // Will be updated later
     }
 
     @Override
-    public boolean shouldExpectLecternHandled() {
+    public boolean shouldExpectLecternHandled(GeyserSession session) {
         return true;
     }
 
@@ -184,42 +180,18 @@ public class GeyserSpigotWorldManager extends WorldManager {
     @Override
     public CompletableFuture<@Nullable CompoundTag> getPickItemNbt(GeyserSession session, int x, int y, int z, boolean addNbtData) {
         CompletableFuture<@Nullable CompoundTag> future = new CompletableFuture<>();
+        Player bukkitPlayer;
+        if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == null) {
+            future.complete(null);
+            return future;
+        }
+        Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z);
         // Paper 1.19.3 complains about async access otherwise.
         // java.lang.IllegalStateException: Tile is null, asynchronous access?
-        Bukkit.getScheduler().runTask(this.plugin, () -> {
-            Player bukkitPlayer;
-            if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == null) {
-                future.complete(null);
-                return;
-            }
-
-            Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z);
-            BlockState state = block.getState();
-            if (state instanceof Banner banner) {
-                ListTag list = new ListTag("Patterns");
-                for (int i = 0; i < banner.numberOfPatterns(); i++) {
-                    Pattern pattern = banner.getPattern(i);
-                    list.add(BannerTranslator.getJavaPatternTag(pattern.getPattern().getIdentifier(), pattern.getColor().ordinal()));
-                }
-
-                CompoundTag root = addToBlockEntityTag(list);
-
-                future.complete(root);
-                return;
-            }
-            future.complete(null);
-        });
+        SchedulerUtils.runTask(this.plugin, () -> future.complete(PickBlockUtils.pickBlock(block)), block);
         return future;
     }
 
-    private CompoundTag addToBlockEntityTag(Tag tag) {
-        CompoundTag compoundTag = new CompoundTag("");
-        CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag");
-        blockEntityTag.put(tag);
-        compoundTag.put(blockEntityTag);
-        return compoundTag;
-    }
-
     /**
      * This should be set to true if we are post-1.13 but before the latest version, and we should convert the old block state id
      * to the current one.
diff --git a/bootstrap/spigot/src/main/resources/plugin.yml b/bootstrap/spigot/src/main/resources/plugin.yml
index d8bc264a9..6e81ccdb6 100644
--- a/bootstrap/spigot/src/main/resources/plugin.yml
+++ b/bootstrap/spigot/src/main/resources/plugin.yml
@@ -5,6 +5,7 @@ website: ${url}
 version: ${version}
 softdepend: ["ViaVersion", "floodgate"]
 api-version: 1.13
+folia-supported: true
 commands:
   geyser:
     description: The main command for Geyser.
diff --git a/core/build.gradle.kts b/core/build.gradle.kts
index 9ba399674..39fa0bb43 100644
--- a/core/build.gradle.kts
+++ b/core/build.gradle.kts
@@ -49,6 +49,10 @@ dependencies {
     // Adventure text serialization
     api(libs.bundles.adventure)
 
+    api(libs.erosion.common) {
+        isTransitive = false
+    }
+
     // Test
     testImplementation(libs.junit)
 
diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java
index c1b21e943..fbad1ab02 100644
--- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java
+++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java
@@ -50,6 +50,7 @@ import org.geysermc.api.Geyser;
 import org.geysermc.common.PlatformType;
 import org.geysermc.cumulus.form.Form;
 import org.geysermc.cumulus.form.util.FormBuilder;
+import org.geysermc.erosion.packet.Packets;
 import org.geysermc.floodgate.crypto.AesCipher;
 import org.geysermc.floodgate.crypto.AesKeyProducer;
 import org.geysermc.floodgate.crypto.Base64Topping;
@@ -67,6 +68,7 @@ import org.geysermc.geyser.api.network.RemoteServer;
 import org.geysermc.geyser.command.GeyserCommandManager;
 import org.geysermc.geyser.configuration.GeyserConfiguration;
 import org.geysermc.geyser.entity.EntityDefinitions;
+import org.geysermc.geyser.erosion.UnixSocketClientListener;
 import org.geysermc.geyser.event.GeyserEventBus;
 import org.geysermc.geyser.extension.GeyserExtensionManager;
 import org.geysermc.geyser.level.WorldManager;
@@ -140,6 +142,8 @@ public class GeyserImpl implements GeyserApi {
     private FloodgateSkinUploader skinUploader;
     private NewsHandler newsHandler;
 
+    private UnixSocketClientListener erosionUnixListener;
+
     private volatile boolean shuttingDown = false;
 
     private ScheduledExecutorService scheduledThread;
@@ -293,6 +297,14 @@ public class GeyserImpl implements GeyserApi {
 
         this.newsHandler = new NewsHandler(BRANCH, this.buildNumber());
 
+        Packets.initGeyser();
+
+        if (Epoll.isAvailable()) {
+            this.erosionUnixListener = new UnixSocketClientListener();
+        } else {
+            logger.debug("Epoll is not available; Erosion's Unix socket handling will not work.");
+        }
+
         CooldownUtils.setDefaultShowCooldown(config.getShowCooldown());
         DimensionUtils.changeBedrockNetherId(config.isAboveBedrockNetherBuilding()); // Apply End dimension ID workaround to Nether
 
@@ -570,6 +582,10 @@ public class GeyserImpl implements GeyserApi {
         newsHandler.shutdown();
         this.commandManager().getCommands().clear();
 
+        if (this.erosionUnixListener != null) {
+            this.erosionUnixListener.close();
+        }
+
         ResourcePack.PACKS.clear();
 
         this.eventBus.fire(new GeyserShutdownEvent(this.extensionManager, this.eventBus));
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java
index 65662bbe4..deaca789a 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java
@@ -30,12 +30,11 @@ import com.nukkitx.math.vector.Vector3f;
 import com.nukkitx.protocol.bedrock.data.entity.EntityData;
 import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket;
 import lombok.Getter;
+import org.geysermc.erosion.util.BlockPositionIterator;
 import org.geysermc.geyser.entity.EntityDefinitions;
 import org.geysermc.geyser.entity.type.player.PlayerEntity;
-import org.geysermc.geyser.level.block.BlockPositionIterator;
 import org.geysermc.geyser.level.block.BlockStateValues;
 import org.geysermc.geyser.level.physics.BoundingBox;
-import org.geysermc.geyser.registry.BlockRegistries;
 import org.geysermc.geyser.session.GeyserSession;
 import org.geysermc.geyser.translator.collision.BlockCollision;
 import org.geysermc.geyser.util.BlockUtils;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java
index 89db9b0c8..e804099d8 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java
@@ -40,11 +40,12 @@ import org.geysermc.geyser.session.GeyserSession;
 import org.geysermc.geyser.translator.inventory.item.ItemTranslator;
 
 import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
 
 public class ItemEntity extends ThrowableEntity {
     protected ItemData item;
 
-    private int waterLevel = -1;
+    private CompletableFuture<Integer> waterLevel = CompletableFuture.completedFuture(-1);
 
     public ItemEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
         super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
@@ -111,15 +112,15 @@ public class ItemEntity extends ThrowableEntity {
     @Override
     protected void moveAbsoluteImmediate(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
         float offset = definition.offset();
-        if (waterLevel == 0) { // Item is in a full block of water
+        if (waterLevel.join() == 0) { // Item is in a full block of water
             // Move the item entity down so it doesn't float above the water
             offset = -definition.offset();
         }
         super.moveAbsoluteImmediate(position.add(0, offset, 0), 0, 0, 0, isOnGround, teleported);
         this.position = position;
 
-        int block = session.getGeyser().getWorldManager().getBlockAt(session, position.toInt());
-        waterLevel = BlockStateValues.getWaterLevel(block);
+        waterLevel = session.getGeyser().getWorldManager().getBlockAtAsync(session, position.getFloorX(), position.getFloorY(), position.getFloorZ())
+                .thenApply(BlockStateValues::getWaterLevel);
     }
 
     @Override
@@ -144,6 +145,6 @@ public class ItemEntity extends ThrowableEntity {
 
     @Override
     protected boolean isInWater() {
-        return waterLevel != -1;
+        return waterLevel.join() != -1;
     }
 }
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/SquidEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/SquidEntity.java
index 6b235a8e5..453d70bf6 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/SquidEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/SquidEntity.java
@@ -34,12 +34,13 @@ import org.geysermc.geyser.level.block.BlockStateValues;
 import org.geysermc.geyser.session.GeyserSession;
 
 import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
 
 public class SquidEntity extends WaterEntity implements Tickable {
     private float targetPitch;
     private float targetYaw;
 
-    private boolean inWater;
+    private CompletableFuture<Boolean> inWater = CompletableFuture.completedFuture(Boolean.FALSE);
 
     public SquidEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
         super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
@@ -50,7 +51,7 @@ public class SquidEntity extends WaterEntity implements Tickable {
         boolean pitchChanged;
         boolean yawChanged;
         float oldPitch = pitch;
-        if (inWater) {
+        if (inWater.join()) {
             float oldYaw = yaw;
             pitch += (targetPitch - pitch) * 0.1f;
             yaw += (targetYaw - yaw) * 0.1f;
@@ -93,7 +94,7 @@ public class SquidEntity extends WaterEntity implements Tickable {
     @Override
     public void setYaw(float yaw) {
         // Let the Java server control yaw when the squid is out of water
-        if (!inWater) {
+        if (!inWater.join()) {
             this.yaw = yaw;
         }
     }
@@ -127,10 +128,10 @@ public class SquidEntity extends WaterEntity implements Tickable {
 
     private void checkInWater() {
         if (getFlag(EntityFlag.RIDING)) {
-            inWater = false;
+            inWater = CompletableFuture.completedFuture(false);
         } else {
-            int block = session.getGeyser().getWorldManager().getBlockAt(session, position.toInt());
-            inWater = BlockStateValues.getWaterLevel(block) != -1;
+            inWater = session.getGeyser().getWorldManager().getBlockAtAsync(session, position.toInt())
+                    .thenApply(block -> BlockStateValues.getWaterLevel(block) != -1);
         }
     }
 }
diff --git a/core/src/main/java/org/geysermc/geyser/erosion/AbstractGeyserboundPacketHandler.java b/core/src/main/java/org/geysermc/geyser/erosion/AbstractGeyserboundPacketHandler.java
new file mode 100644
index 000000000..eabed8f7b
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/erosion/AbstractGeyserboundPacketHandler.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2019-2023 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.erosion;
+
+import org.geysermc.erosion.packet.geyserbound.*;
+import org.geysermc.geyser.session.GeyserSession;
+import org.jetbrains.annotations.Nullable;
+
+public abstract class AbstractGeyserboundPacketHandler implements GeyserboundPacketHandler {
+    protected final GeyserSession session;
+
+    public AbstractGeyserboundPacketHandler(GeyserSession session) {
+        this.session = session;
+    }
+
+    @Override
+    public void handleBatchBlockId(GeyserboundBatchBlockIdPacket packet) {
+        illegalPacket(packet);
+    }
+
+    @Override
+    public void handleBlockEntity(GeyserboundBlockEntityPacket packet) {
+        illegalPacket(packet);
+    }
+
+    @Override
+    public void handleBlockId(GeyserboundBlockIdPacket packet) {
+        illegalPacket(packet);
+    }
+
+    @Override
+    public void handleBlockLookupFail(GeyserboundBlockLookupFailPacket packet) {
+        illegalPacket(packet);
+    }
+
+    @Override
+    public void handleBlockPlace(GeyserboundBlockPlacePacket packet) {
+        illegalPacket(packet);
+    }
+
+    @Override
+    public void handlePistonEvent(GeyserboundPistonEventPacket packet) {
+        illegalPacket(packet);
+    }
+
+    @Override
+    public void handlePickBlock(GeyserboundPickBlockPacket packet) {
+        illegalPacket(packet);
+    }
+
+    /**
+     * Is this handler actually listening to any packets?
+     */
+    public abstract boolean isActive();
+
+    @Nullable
+    public abstract GeyserboundPacketHandlerImpl getAsActive();
+
+    public void close() {
+    }
+
+    protected final void illegalPacket(GeyserboundPacket packet) {
+        session.getGeyser().getLogger().warning("Illegal packet sent from backend server! " + packet);
+    }
+}
diff --git a/core/src/main/java/org/geysermc/geyser/erosion/GeyserErosionPacketSender.java b/core/src/main/java/org/geysermc/geyser/erosion/GeyserErosionPacketSender.java
new file mode 100644
index 000000000..610917adc
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/erosion/GeyserErosionPacketSender.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2019-2023 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.erosion;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
+import org.geysermc.erosion.Constants;
+import org.geysermc.erosion.packet.ErosionPacketSender;
+import org.geysermc.erosion.packet.Packets;
+import org.geysermc.erosion.packet.backendbound.BackendboundPacket;
+import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.util.PluginMessageUtils;
+
+import java.io.IOException;
+
+public record GeyserErosionPacketSender(GeyserSession session) implements ErosionPacketSender<BackendboundPacket> {
+
+    @Override
+    public void sendPacket(BackendboundPacket packet) {
+        ByteBuf buf = Unpooled.buffer();
+        try {
+            Packets.encode(buf, packet);
+            byte[] bytes = new byte[buf.readableBytes()];
+            buf.readBytes(bytes);
+            PluginMessageUtils.sendMessage(session, Constants.PLUGIN_MESSAGE, bytes);
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            buf.release();
+        }
+    }
+
+    @Override
+    public void setChannel(Channel channel) {
+    }
+}
diff --git a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundHandshakePacketHandler.java b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundHandshakePacketHandler.java
new file mode 100644
index 000000000..196595383
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundHandshakePacketHandler.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2019-2023 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.erosion;
+
+import io.netty.channel.Channel;
+import org.geysermc.erosion.netty.NettyPacketSender;
+import org.geysermc.erosion.packet.ErosionPacketHandler;
+import org.geysermc.erosion.packet.geyserbound.GeyserboundHandshakePacket;
+import org.geysermc.geyser.session.GeyserSession;
+import org.jetbrains.annotations.Nullable;
+
+public final class GeyserboundHandshakePacketHandler extends AbstractGeyserboundPacketHandler {
+
+    public GeyserboundHandshakePacketHandler(GeyserSession session) {
+        super(session);
+    }
+
+    @Override
+    public void handleHandshake(GeyserboundHandshakePacket packet) {
+        boolean useTcp = packet.getTransportType().getSocketAddress() == null;
+        GeyserboundPacketHandlerImpl handler = new GeyserboundPacketHandlerImpl(session, useTcp ? new GeyserErosionPacketSender(session) : new NettyPacketSender<>());
+        session.setErosionHandler(handler);
+        if (!useTcp) {
+            if (session.getGeyser().getErosionUnixListener() == null) {
+                session.disconnect("Erosion configurations using Unix socket handling are not supported on this hardware!");
+                return;
+            }
+            session.getGeyser().getErosionUnixListener().createClient(handler, packet.getTransportType().getSocketAddress());
+        } else {
+            handler.onConnect();
+        }
+        session.ensureInEventLoop(() -> session.getChunkCache().clear());
+    }
+
+    @Override
+    public boolean isActive() {
+        return false;
+    }
+
+    @Override
+    public @Nullable GeyserboundPacketHandlerImpl getAsActive() {
+        return null;
+    }
+
+    @Override
+    public ErosionPacketHandler setChannel(Channel channel) {
+        return null;
+    }
+}
diff --git a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java
new file mode 100644
index 000000000..af3098edb
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2019-2023 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.erosion;
+
+import com.github.steveice10.mc.protocol.data.game.level.block.value.PistonValueType;
+import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
+import com.nukkitx.math.vector.Vector3i;
+import com.nukkitx.nbt.NbtMap;
+import com.nukkitx.protocol.bedrock.data.SoundEvent;
+import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket;
+import io.netty.channel.Channel;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.ints.IntArrays;
+import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
+import it.unimi.dsi.fastutil.objects.Object2IntMap;
+import lombok.Getter;
+import lombok.Setter;
+import org.geysermc.erosion.packet.ErosionPacketHandler;
+import org.geysermc.erosion.packet.ErosionPacketSender;
+import org.geysermc.erosion.packet.backendbound.BackendboundInitializePacket;
+import org.geysermc.erosion.packet.backendbound.BackendboundPacket;
+import org.geysermc.erosion.packet.geyserbound.*;
+import org.geysermc.geyser.level.block.BlockStateValues;
+import org.geysermc.geyser.level.physics.Direction;
+import org.geysermc.geyser.network.GameProtocol;
+import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.PistonCache;
+import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity;
+import org.geysermc.geyser.util.BlockEntityUtils;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacketHandler {
+    private final ErosionPacketSender<BackendboundPacket> packetSender;
+    @Setter
+    private CompletableFuture<Integer> pendingLookup = null;
+    @Getter
+    private final Int2ObjectMap<CompletableFuture<Integer>> asyncPendingLookups = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>(4));
+    @Setter
+    private CompletableFuture<int[]> pendingBatchLookup = null;
+    @Setter
+    private CompletableFuture<CompoundTag> pickBlockLookup = null;
+
+    private final AtomicInteger nextTransactionId = new AtomicInteger(1);
+
+    public GeyserboundPacketHandlerImpl(GeyserSession session, ErosionPacketSender<BackendboundPacket> packetSender) {
+        super(session);
+        this.packetSender = packetSender;
+    }
+
+    @Override
+    public void handleBatchBlockId(GeyserboundBatchBlockIdPacket packet) {
+        if (this.pendingBatchLookup != null) {
+            this.pendingBatchLookup.complete(packet.getBlocks());
+        } else {
+            session.getGeyser().getLogger().warning("Batch block ID packet received with no future to complete.");
+        }
+    }
+
+    @Override
+    public void handleBlockEntity(GeyserboundBlockEntityPacket packet) {
+        NbtMap nbt = packet.getNbt();
+        BlockEntityUtils.updateBlockEntity(session, nbt, Vector3i.from(nbt.getInt("x"), nbt.getInt("y"), nbt.getInt("z")));
+    }
+
+    @Override
+    public void handleBlockId(GeyserboundBlockIdPacket packet) {
+        if (packet.getTransactionId() == 0) {
+            if (this.pendingLookup != null) {
+                this.pendingLookup.complete(packet.getBlockId());
+                return;
+            }
+        }
+        CompletableFuture<Integer> future = this.asyncPendingLookups.remove(packet.getTransactionId());
+        if (future != null) {
+            future.complete(packet.getBlockId());
+            return;
+        }
+        session.getGeyser().getLogger().warning("Block ID packet received with no future to complete.");
+    }
+
+    @Override
+    public void handleBlockLookupFail(GeyserboundBlockLookupFailPacket packet) {
+        if (packet.getTransactionId() == 0) {
+            if (this.pendingBatchLookup != null) {
+                this.pendingBatchLookup.complete(null);
+                return;
+            }
+        }
+        int transactionId = packet.getTransactionId() - 1;
+        if (transactionId == 0) {
+            if (this.pendingLookup != null) {
+                this.pendingLookup.complete(0);
+            }
+        }
+        CompletableFuture<Integer> future = this.asyncPendingLookups.remove(transactionId);
+        if (future != null) {
+            future.complete(BlockStateValues.JAVA_AIR_ID);
+        }
+    }
+
+    @Override
+    public void handleBlockPlace(GeyserboundBlockPlacePacket packet) {
+        LevelSoundEventPacket placeBlockSoundPacket = new LevelSoundEventPacket();
+        placeBlockSoundPacket.setSound(SoundEvent.PLACE);
+        placeBlockSoundPacket.setPosition(packet.getPos().toFloat());
+        placeBlockSoundPacket.setBabySound(false);
+        placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(packet.getBlockId()));
+        placeBlockSoundPacket.setIdentifier(":");
+        session.sendUpstreamPacket(placeBlockSoundPacket);
+        session.setLastBlockPlacePosition(null);
+        session.setLastBlockPlacedId(null);
+    }
+
+    @Override
+    public void handlePickBlock(GeyserboundPickBlockPacket packet) {
+        if (this.pickBlockLookup != null) {
+            this.pickBlockLookup.complete(packet.getTag());
+        }
+    }
+
+    @Override
+    public void handlePistonEvent(GeyserboundPistonEventPacket packet) {
+        Direction orientation = BlockStateValues.getPistonOrientation(packet.getBlockId());
+        Vector3i position = packet.getPos();
+        boolean isExtend = packet.isExtend();
+
+        var stream = packet.getAttachedBlocks()
+                .object2IntEntrySet()
+                .stream()
+                .filter(entry -> BlockStateValues.canPistonMoveBlock(entry.getIntValue(), isExtend));
+        Object2IntMap<Vector3i> attachedBlocks = new Object2IntArrayMap<>();
+        stream.forEach(entry -> attachedBlocks.put(entry.getKey(), entry.getIntValue()));
+
+        session.executeInEventLoop(() -> {
+            PistonCache pistonCache = session.getPistonCache();
+            PistonBlockEntity blockEntity = pistonCache.getPistons().computeIfAbsent(position, pos ->
+                    new PistonBlockEntity(session, position, orientation, packet.isSticky(), !isExtend));
+            blockEntity.setAction(isExtend ? PistonValueType.PUSHING : PistonValueType.PULLING, attachedBlocks);
+        });
+    }
+
+    @Override
+    public void handleHandshake(GeyserboundHandshakePacket packet) {
+        this.close();
+        var handler = new GeyserboundHandshakePacketHandler(this.session);
+        session.setErosionHandler(handler);
+        handler.handleHandshake(packet);
+    }
+
+    @Override
+    public boolean isActive() {
+        return true;
+    }
+
+    @Override
+    public GeyserboundPacketHandlerImpl getAsActive() {
+        return this;
+    }
+
+    @Override
+    public void onConnect() {
+        sendPacket(new BackendboundInitializePacket(session.getPlayerEntity().getUuid(), GameProtocol.getJavaProtocolVersion()));
+    }
+
+    public void sendPacket(BackendboundPacket packet) {
+        this.packetSender.sendPacket(packet);
+    }
+
+    public void close() {
+        this.packetSender.close();
+    }
+
+    public int getNextTransactionId() {
+        return nextTransactionId.getAndIncrement();
+    }
+
+    @Override
+    public ErosionPacketHandler setChannel(Channel channel) {
+        this.packetSender.setChannel(channel);
+        return this;
+    }
+}
diff --git a/core/src/main/java/org/geysermc/geyser/erosion/UnixSocketClientListener.java b/core/src/main/java/org/geysermc/geyser/erosion/UnixSocketClientListener.java
new file mode 100644
index 000000000..a236099df
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/erosion/UnixSocketClientListener.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2019-2023 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.erosion;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.epoll.EpollDomainSocketChannel;
+import io.netty.channel.epoll.EpollEventLoopGroup;
+import org.geysermc.erosion.netty.impl.AbstractUnixSocketListener;
+import org.geysermc.erosion.packet.geyserbound.GeyserboundPacketHandler;
+
+import java.net.SocketAddress;
+
+public final class UnixSocketClientListener extends AbstractUnixSocketListener {
+    private EventLoopGroup eventLoopGroup;
+
+    public void initializeEventLoopGroup() {
+        if (this.eventLoopGroup == null) {
+            this.eventLoopGroup = new EpollEventLoopGroup();
+        }
+    }
+
+    public void createClient(GeyserboundPacketHandler handler, SocketAddress address) {
+        initializeEventLoopGroup();
+        (new Bootstrap()
+                .channel(EpollDomainSocketChannel.class)
+                .handler(new ChannelInitializer<Channel>() {
+                    @Override
+                    protected void initChannel(Channel ch) {
+                        initPipeline(ch, handler);
+                    }
+                })
+                .group(this.eventLoopGroup.next())
+                .connect(address))
+                .syncUninterruptibly()
+                .channel();
+    }
+
+    @Override
+    public void close() {
+        if (this.eventLoopGroup != null) {
+            this.eventLoopGroup.shutdownGracefully();
+        }
+    }
+}
diff --git a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java
index 5df97e8d7..43ba452a0 100644
--- a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java
+++ b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java
@@ -25,19 +25,63 @@
 
 package org.geysermc.geyser.level;
 
+import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo;
+import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
+import com.nukkitx.math.vector.Vector3i;
 import com.nukkitx.nbt.NbtMap;
 import com.nukkitx.nbt.NbtMapBuilder;
 import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
 import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+import org.geysermc.erosion.packet.backendbound.*;
+import org.geysermc.erosion.util.BlockPositionIterator;
+import org.geysermc.erosion.util.LecternUtils;
 import org.geysermc.geyser.session.GeyserSession;
-import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator;
+import org.geysermc.geyser.util.BlockEntityUtils;
+import org.jetbrains.annotations.Nullable;
+
+import javax.annotation.Nonnull;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
 
 public class GeyserWorldManager extends WorldManager {
     private final Object2ObjectMap<String, String> gameruleCache = new Object2ObjectOpenHashMap<>();
 
     @Override
     public int getBlockAt(GeyserSession session, int x, int y, int z) {
-        return session.getChunkCache().getBlockAt(x, y, z);
+        var erosionHandler = session.getErosionHandler().getAsActive();
+        if (erosionHandler == null) {
+            return session.getChunkCache().getBlockAt(x, y, z);
+        }
+        CompletableFuture<Integer> future = new CompletableFuture<>(); // Boxes
+        erosionHandler.setPendingLookup(future);
+        erosionHandler.sendPacket(new BackendboundBlockRequestPacket(0, Vector3i.from(x, y, z)));
+        return future.join();
+    }
+
+    @Override
+    public CompletableFuture<Integer> getBlockAtAsync(GeyserSession session, int x, int y, int z) {
+        var erosionHandler = session.getErosionHandler().getAsActive();
+        if (erosionHandler == null) {
+            return super.getBlockAtAsync(session, x, y, z);
+        }
+        CompletableFuture<Integer> future = new CompletableFuture<>(); // Boxes
+        int transactionId = erosionHandler.getNextTransactionId();
+        erosionHandler.getAsyncPendingLookups().put(transactionId, future);
+        erosionHandler.sendPacket(new BackendboundBlockRequestPacket(transactionId, Vector3i.from(x, y, z)));
+        return future;
+    }
+
+    @Override
+    public int[] getBlocksAt(GeyserSession session, BlockPositionIterator iter) {
+        var erosionHandler = session.getErosionHandler().getAsActive();
+        if (erosionHandler == null) {
+            return super.getBlocksAt(session, iter);
+        }
+        CompletableFuture<int[]> future = new CompletableFuture<>();
+        erosionHandler.setPendingBatchLookup(future);
+        erosionHandler.sendPacket(new BackendboundBatchBlockRequestPacket(iter));
+        return future.join();
     }
 
     @Override
@@ -47,10 +91,31 @@ public class GeyserWorldManager extends WorldManager {
     }
 
     @Override
-    public NbtMap getLecternDataAt(GeyserSession session, int x, int y, int z, boolean isChunkLoad) {
+    public void sendLecternData(GeyserSession session, int x, int z, List<BlockEntityInfo> blockEntityInfos) {
+        var erosionHandler = session.getErosionHandler().getAsActive();
+        if (erosionHandler == null) {
+            // No-op - don't send any additional information other than what the chunk has already sent
+            return;
+        }
+        List<Vector3i> vectors = new ObjectArrayList<>(blockEntityInfos.size());
+        for (int i = 0; i < blockEntityInfos.size(); i++) {
+            BlockEntityInfo info = blockEntityInfos.get(i);
+            vectors.add(Vector3i.from(info.getX(), info.getY(), info.getZ()));
+        }
+        erosionHandler.sendPacket(new BackendboundBatchBlockEntityPacket(x, z, vectors));
+    }
+
+    @Override
+    public void sendLecternData(GeyserSession session, int x, int y, int z) {
+        var erosionHandler = session.getErosionHandler().getAsActive();
+        if (erosionHandler != null) {
+            erosionHandler.sendPacket(new BackendboundBlockEntityPacket(Vector3i.from(x, y, z)));
+            return;
+        }
+
         // Without direct server access, we can't get lectern information on-the-fly.
         // I should have set this up so it's only called when there is a book in the block state. - Camotoy
-        NbtMapBuilder lecternTag = LecternInventoryTranslator.getBaseLecternTag(x, y, z, 1);
+        NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(x, y, z, 1);
         lecternTag.putCompound("book", NbtMap.builder()
                 .putByte("Count", (byte) 1)
                 .putShort("Damage", (short) 0)
@@ -61,12 +126,12 @@ public class GeyserWorldManager extends WorldManager {
                         .build())
                 .build());
         lecternTag.putInt("page", -1); // I'm surprisingly glad this exists - it forces Bedrock to stop reading immediately. Usually.
-        return lecternTag.build();
+        BlockEntityUtils.updateBlockEntity(session, lecternTag.build(), Vector3i.from(x, y, z));
     }
 
     @Override
-    public boolean shouldExpectLecternHandled() {
-        return false;
+    public boolean shouldExpectLecternHandled(GeyserSession session) {
+        return session.getErosionHandler().isActive();
     }
 
     @Override
@@ -99,4 +164,17 @@ public class GeyserWorldManager extends WorldManager {
     public boolean hasPermission(GeyserSession session, String permission) {
         return false;
     }
+
+    @Nonnull
+    @Override
+    public CompletableFuture<@Nullable CompoundTag> getPickItemNbt(GeyserSession session, int x, int y, int z, boolean addNbtData) {
+        var erosionHandler = session.getErosionHandler().getAsActive();
+        if (erosionHandler == null) {
+            return super.getPickItemNbt(session, x, y, z, addNbtData);
+        }
+        CompletableFuture<CompoundTag> future = new CompletableFuture<>();
+        erosionHandler.setPickBlockLookup(future);
+        erosionHandler.sendPacket(new BackendboundPickBlockPacket(Vector3i.from(x, y, z)));
+        return future;
+    }
 }
diff --git a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java
index 1909915db..84a03022f 100644
--- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java
+++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java
@@ -26,14 +26,16 @@
 package org.geysermc.geyser.level;
 
 import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
+import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo;
 import com.github.steveice10.mc.protocol.data.game.setting.Difficulty;
 import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
 import com.nukkitx.math.vector.Vector3i;
-import com.nukkitx.nbt.NbtMap;
+import org.geysermc.erosion.util.BlockPositionIterator;
 import org.geysermc.geyser.session.GeyserSession;
 import org.jetbrains.annotations.Nullable;
 
 import javax.annotation.Nonnull;
+import java.util.List;
 import java.util.Locale;
 import java.util.concurrent.CompletableFuture;
 
@@ -68,6 +70,23 @@ public abstract class WorldManager {
      */
     public abstract int getBlockAt(GeyserSession session, int x, int y, int z);
 
+    public final CompletableFuture<Integer> getBlockAtAsync(GeyserSession session, Vector3i vector) {
+        return this.getBlockAtAsync(session, vector.getX(), vector.getY(), vector.getZ());
+    }
+
+    public CompletableFuture<Integer> getBlockAtAsync(GeyserSession session, int x, int y, int z) {
+        return CompletableFuture.completedFuture(this.getBlockAt(session, x, y, z));
+    }
+
+    public int[] getBlocksAt(GeyserSession session, BlockPositionIterator iter) {
+        int[] blocks = new int[iter.getMaxIterations()];
+        for (; iter.hasNext(); iter.next()) {
+            int networkId = this.getBlockAt(session, iter.getX(), iter.getY(), iter.getZ());
+            blocks[iter.getIteration()] = networkId;
+        }
+        return blocks;
+    }
+
     /**
      * Checks whether or not this world manager requires a separate chunk cache/has access to more block data than the chunk cache.
      * <p>
@@ -89,20 +108,28 @@ public abstract class WorldManager {
      * We solve this problem by querying all loaded lecterns, where possible, and sending their information in a block entity
      * tag.
      *
+     * Note that the lectern data may be sent asynchronously.
+     *
      * @param session the session of the player
      * @param x the x coordinate of the lectern
      * @param y the y coordinate of the lectern
      * @param z the z coordinate of the lectern
-     * @param isChunkLoad if this is called during a chunk load or not. Changes behavior in certain instances.
-     * @return the Bedrock lectern block entity tag. This may not be the exact block entity tag - for example, Spigot's
-     * block handled must be done on the server thread, so we send the tag manually there.
      */
-    public abstract NbtMap getLecternDataAt(GeyserSession session, int x, int y, int z, boolean isChunkLoad);
+    public abstract void sendLecternData(GeyserSession session, int x, int y, int z);
+
+    /**
+     * {@link #sendLecternData(GeyserSession, int, int, int)} but batched for chunks.
+     *
+     * @param x chunk x
+     * @param z chunk z
+     * @param blockEntityInfos a list of coordinates (chunk local) to grab lecterns from.
+     */
+    public abstract void sendLecternData(GeyserSession session, int x, int z, List<BlockEntityInfo> blockEntityInfos);
 
     /**
      * @return whether we should expect lectern data to update, or if we have to fall back on a workaround.
      */
-    public abstract boolean shouldExpectLecternHandled();
+    public abstract boolean shouldExpectLecternHandled(GeyserSession session);
 
     /**
      * Updates a gamerule value on the Java server
diff --git a/core/src/main/java/org/geysermc/geyser/level/block/BlockPositionIterator.java b/core/src/main/java/org/geysermc/geyser/level/block/BlockPositionIterator.java
deleted file mode 100644
index d22150ccf..000000000
--- a/core/src/main/java/org/geysermc/geyser/level/block/BlockPositionIterator.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (c) 2019-2022 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.level.block;
-
-import com.nukkitx.network.util.Preconditions;
-
-public class BlockPositionIterator {
-    private final int minX;
-    private final int minY;
-    private final int minZ;
-
-    private final int sizeX;
-    private final int sizeZ;
-
-    private int i = 0;
-    private final int maxI;
-
-    public BlockPositionIterator(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
-        Preconditions.checkArgument(maxX >= minX, "maxX is not greater than or equal to minX");
-        Preconditions.checkArgument(maxY >= minY, "maxY is not greater than or equal to minY");
-        Preconditions.checkArgument(maxZ >= minZ, "maxZ is not greater than or equal to minZ");
-
-        this.minX = minX;
-        this.minY = minY;
-        this.minZ = minZ;
-
-        this.sizeX = maxX - minX + 1;
-        int sizeY = maxY - minY + 1;
-        this.sizeZ = maxZ - minZ + 1;
-        this.maxI = sizeX * sizeY * sizeZ;
-    }
-
-    public boolean hasNext() {
-        return i < maxI;
-    }
-
-    public void next() {
-        // Iterate in zxy order
-        i++;
-    }
-
-    public void reset() {
-        i = 0;
-    }
-
-    public int getX() {
-        return ((i / sizeZ) % sizeX) + minX;
-    }
-
-    public int getY() {
-        return (i / sizeZ / sizeX) + minY;
-    }
-
-    public int getZ() {
-        return (i % sizeZ) + minZ;
-    }
-}
\ No newline at end of file
diff --git a/core/src/main/java/org/geysermc/geyser/level/physics/CollisionManager.java b/core/src/main/java/org/geysermc/geyser/level/physics/CollisionManager.java
index 2a830cd70..666e1191d 100644
--- a/core/src/main/java/org/geysermc/geyser/level/physics/CollisionManager.java
+++ b/core/src/main/java/org/geysermc/geyser/level/physics/CollisionManager.java
@@ -33,10 +33,10 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
 import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
 import lombok.Getter;
 import lombok.Setter;
+import org.geysermc.erosion.util.BlockPositionIterator;
 import org.geysermc.geyser.entity.EntityDefinitions;
 import org.geysermc.geyser.entity.type.Entity;
 import org.geysermc.geyser.entity.type.player.PlayerEntity;
-import org.geysermc.geyser.level.block.BlockPositionIterator;
 import org.geysermc.geyser.level.block.BlockStateValues;
 import org.geysermc.geyser.session.GeyserSession;
 import org.geysermc.geyser.session.cache.PistonCache;
@@ -215,7 +215,7 @@ public class CollisionManager {
         int minCollisionZ = (int) Math.floor(position.getZ() - ((box.getSizeZ() / 2) + COLLISION_TOLERANCE + pistonExpand));
         int maxCollisionZ = (int) Math.floor(position.getZ() + (box.getSizeZ() / 2) + COLLISION_TOLERANCE + pistonExpand);
 
-        return new BlockPositionIterator(minCollisionX, minCollisionY, minCollisionZ, maxCollisionX, maxCollisionY, maxCollisionZ);
+        return BlockPositionIterator.fromMinMax(minCollisionX, minCollisionY, minCollisionZ, maxCollisionX, maxCollisionY, maxCollisionZ);
     }
 
     public BlockPositionIterator playerCollidableBlocksIterator() {
@@ -235,8 +235,9 @@ public class CollisionManager {
 
         // Used when correction code needs to be run before the main correction
         BlockPositionIterator iter = session.getCollisionManager().playerCollidableBlocksIterator();
-        for (; iter.hasNext(); iter.next()) {
-            BlockCollision blockCollision = BlockUtils.getCollisionAt(session, iter.getX(), iter.getY(), iter.getZ());
+        int[] blocks = session.getGeyser().getWorldManager().getBlocksAt(session, iter);
+        for (iter.reset(); iter.hasNext(); iter.next()) {
+            BlockCollision blockCollision = BlockUtils.getCollision(blocks[iter.getIteration()]);
             if (blockCollision != null) {
                 blockCollision.beforeCorrectPosition(iter.getX(), iter.getY(), iter.getZ(), playerBoundingBox);
             }
@@ -244,7 +245,7 @@ public class CollisionManager {
 
         // Main correction code
         for (iter.reset(); iter.hasNext(); iter.next()) {
-            BlockCollision blockCollision = BlockUtils.getCollisionAt(session, iter.getX(), iter.getY(), iter.getZ());
+            BlockCollision blockCollision = BlockUtils.getCollision(blocks[iter.getIteration()]);
             if (blockCollision != null) {
                 if (!blockCollision.correctPosition(session, iter.getX(), iter.getY(), iter.getZ(), playerBoundingBox)) {
                     return false;
diff --git a/core/src/main/java/org/geysermc/geyser/pack/ResourcePack.java b/core/src/main/java/org/geysermc/geyser/pack/ResourcePack.java
index 6df1a0c0e..07d56194a 100644
--- a/core/src/main/java/org/geysermc/geyser/pack/ResourcePack.java
+++ b/core/src/main/java/org/geysermc/geyser/pack/ResourcePack.java
@@ -102,13 +102,17 @@ public class ResourcePack {
 
                 pack.sha256 = FileUtils.calculateSHA256(file);
 
-                Stream<? extends ZipEntry> stream = null;
-                try {
-                    ZipFile zip = new ZipFile(file);
-
-                    stream = zip.stream();
+                try (ZipFile zip = new ZipFile(file);
+                     Stream<? extends ZipEntry> stream = zip.stream()) {
                     stream.forEach((x) -> {
-                        if (x.getName().contains("manifest.json")) {
+                        String name = x.getName();
+                        if (name.length() >= 80) {
+                            GeyserImpl.getInstance().getLogger().warning("The resource pack " + file.getName()
+                                    + " has a file in it that meets or exceeds 80 characters in its path (" + name
+                                    + ", " + name.length() + " characters long). This will cause problems on some Bedrock platforms." +
+                                    " Please rename it to be shorter, or reduce the amount of folders needed to get to the file.");
+                        }
+                        if (name.contains("manifest.json")) {
                             try {
                                 ResourcePackManifest manifest = FileUtils.loadJson(zip.getInputStream(x), ResourcePackManifest.class);
                                 // Sometimes a pack_manifest file is present and not in a valid format,
@@ -133,10 +137,6 @@ public class ResourcePack {
                 } catch (Exception e) {
                     GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.resource_pack.broken", file.getName()));
                     e.printStackTrace();
-                } finally {
-                    if (stream != null) {
-                        stream.close();
-                    }
                 }
             }
         }
diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
index e245d0f56..2d36e2813 100644
--- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
+++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
@@ -112,6 +112,8 @@ import org.geysermc.geyser.entity.type.Entity;
 import org.geysermc.geyser.entity.type.ItemFrameEntity;
 import org.geysermc.geyser.entity.type.Tickable;
 import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
+import org.geysermc.geyser.erosion.AbstractGeyserboundPacketHandler;
+import org.geysermc.geyser.erosion.GeyserboundHandshakePacketHandler;
 import org.geysermc.geyser.inventory.Inventory;
 import org.geysermc.geyser.inventory.PlayerInventory;
 import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
@@ -136,6 +138,7 @@ import org.geysermc.geyser.translator.text.MessageTranslator;
 import org.geysermc.geyser.util.ChunkUtils;
 import org.geysermc.geyser.util.DimensionUtils;
 import org.geysermc.geyser.util.LoginEncryptionUtils;
+import org.jetbrains.annotations.NotNull;
 
 import java.net.ConnectException;
 import java.net.InetSocketAddress;
@@ -168,6 +171,10 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
     @Setter
     private JsonNode certChainData;
 
+    @NotNull
+    @Setter
+    private AbstractGeyserboundPacketHandler erosionHandler;
+
     @Accessors(fluent = true)
     @Setter
     private RemoteServer remoteServer;
@@ -255,7 +262,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
 
     /**
      * Stores a list of all lectern locations and their block entity tags.
-     * See {@link WorldManager#getLecternDataAt(GeyserSession, int, int, int, boolean)}
+     * See {@link WorldManager#sendLecternData(GeyserSession, int, int, int)}
      * for more information.
      */
     private final Set<Vector3i> lecternCache;
@@ -551,6 +558,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
         this.upstream = new UpstreamSession(bedrockServerSession);
         this.eventLoop = eventLoop;
 
+        this.erosionHandler = new GeyserboundHandshakePacketHandler(this);
+
         this.advancementsCache = new AdvancementsCache(this);
         this.bookEditCache = new BookEditCache(this);
         this.chunkCache = new ChunkCache(this);
@@ -579,7 +588,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
         this.spawned = false;
         this.loggedIn = false;
 
-        if (geyser.getWorldManager().shouldExpectLecternHandled()) {
+        if (geyser.getWorldManager().shouldExpectLecternHandled(this)) {
             // Unneeded on these platforms
             this.lecternCache = null;
         } else {
@@ -1088,6 +1097,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
             tickThread.cancel(false);
         }
 
+        erosionHandler.close();
+
         closed = true;
     }
 
diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java
index 59fe81751..117f4e851 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java
@@ -35,6 +35,7 @@ import com.nukkitx.nbt.NbtMap;
 import com.nukkitx.nbt.NbtMapBuilder;
 import com.nukkitx.nbt.NbtType;
 import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
+import org.geysermc.erosion.util.LecternUtils;
 import org.geysermc.geyser.inventory.GeyserItemStack;
 import org.geysermc.geyser.inventory.Inventory;
 import org.geysermc.geyser.inventory.LecternContainer;
@@ -110,13 +111,13 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator {
             Vector3i position = session.getLastInteractionBlockPosition();
             // If shouldExpectLecternHandled returns true, this is already handled for us
             // shouldRefresh means that we should boot out the client on our side because their lectern GUI isn't updated yet
-            boolean shouldRefresh = !session.getGeyser().getWorldManager().shouldExpectLecternHandled() && !session.getLecternCache().contains(position);
+            boolean shouldRefresh = !session.getGeyser().getWorldManager().shouldExpectLecternHandled(session) && !session.getLecternCache().contains(position);
 
             NbtMap blockEntityTag;
             if (tag != null) {
                 int pagesSize = ((ListTag) tag.get("pages")).size();
                 ItemData itemData = book.getItemData(session);
-                NbtMapBuilder lecternTag = getBaseLecternTag(position.getX(), position.getY(), position.getZ(), pagesSize);
+                NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(position.getX(), position.getY(), position.getZ(), pagesSize);
                 lecternTag.putCompound("book", NbtMap.builder()
                         .putByte("Count", (byte) itemData.getCount())
                         .putShort("Damage", (short) 0)
@@ -127,7 +128,7 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator {
                 blockEntityTag = lecternTag.build();
             } else {
                 // There is *a* book here, but... no NBT.
-                NbtMapBuilder lecternTag = getBaseLecternTag(position.getX(), position.getY(), position.getZ(), 1);
+                NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(position.getX(), position.getY(), position.getZ(), 1);
                 NbtMapBuilder bookTag = NbtMap.builder()
                         .putByte("Count", (byte) 1)
                         .putShort("Damage", (short) 0)
@@ -162,20 +163,4 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator {
     public Inventory createInventory(String name, int windowId, ContainerType containerType, PlayerInventory playerInventory) {
         return new LecternContainer(name, windowId, this.size, containerType, playerInventory);
     }
-
-    public static NbtMapBuilder getBaseLecternTag(int x, int y, int z, int totalPages) {
-        NbtMapBuilder builder = NbtMap.builder()
-                .putInt("x", x)
-                .putInt("y", y)
-                .putInt("z", z)
-                .putString("id", "Lectern");
-        if (totalPages != 0) {
-            builder.putByte("hasBook", (byte) 1);
-            builder.putInt("totalPages", totalPages);
-        } else {
-            // Not usually needed, but helps with kicking out Bedrock players from reading the UI
-            builder.putByte("hasBook", (byte) 0);
-        }
-        return builder;
-    }
 }
diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BannerTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BannerTranslator.java
index a69a2cfe9..c0af434c5 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BannerTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BannerTranslator.java
@@ -40,6 +40,8 @@ import javax.annotation.Nonnull;
 import java.util.*;
 import java.util.stream.Collectors;
 
+import static org.geysermc.erosion.util.BannerUtils.getJavaPatternTag;
+
 @ItemRemapper
 public class BannerTranslator extends NbtItemStackTranslator {
     /**
@@ -66,15 +68,6 @@ public class BannerTranslator extends NbtItemStackTranslator {
         OMINOUS_BANNER_PATTERN.add(getJavaPatternTag("bo", 15));
     }
 
-    public static CompoundTag getJavaPatternTag(String pattern, int color) {
-        StringTag patternType = new StringTag("Pattern", pattern);
-        IntTag colorTag = new IntTag("Color", color);
-        CompoundTag tag = new CompoundTag("");
-        tag.put(patternType);
-        tag.put(colorTag);
-        return tag;
-    }
-
     public BannerTranslator() {
         appliedItems = Arrays.stream(Registries.ITEMS.forVersion(GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()).getItems())
                 .filter(entry -> entry.getJavaIdentifier().endsWith("banner"))
@@ -117,7 +110,7 @@ public class BannerTranslator extends NbtItemStackTranslator {
      * @return The Java edition format pattern nbt
      */
     public static CompoundTag getJavaBannerPattern(NbtMap pattern) {
-        return BannerTranslator.getJavaPatternTag(pattern.getString("Pattern"), 15 - pattern.getInt("Color"));
+        return getJavaPatternTag(pattern.getString("Pattern"), 15 - pattern.getInt("Color"));
     }
 
     /**
diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java
index c52689014..0974af0e4 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java
@@ -224,7 +224,7 @@ public class PistonBlockEntity {
         int blockId = session.getGeyser().getWorldManager().getBlockAt(session, blockInFront);
         if (BlockStateValues.isPistonHead(blockId)) {
             ChunkUtils.updateBlock(session, BlockStateValues.JAVA_AIR_ID, blockInFront);
-        } else if (session.getGeyser().getPlatformType() == PlatformType.SPIGOT && blockId == BlockStateValues.JAVA_AIR_ID) {
+        } else if ((session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) && blockId == BlockStateValues.JAVA_AIR_ID) {
             // Spigot removes the piston head from the cache, but we need to send the block update ourselves
             ChunkUtils.updateBlock(session, BlockStateValues.JAVA_AIR_ID, blockInFront);
         }
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java
index 90316a8bd..5090de11f 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java
@@ -71,30 +71,28 @@ public class BedrockBlockPickRequestTranslator extends PacketTranslator<BlockPic
         boolean addNbtData = packet.isAddUserData() && blockMapping.isBlockEntity(); // Holding down CTRL
         if (BlockStateValues.getBannerColor(blockToPick) != -1 || addNbtData) {
             session.getGeyser().getWorldManager().getPickItemNbt(session, vector.getX(), vector.getY(), vector.getZ(), addNbtData)
-                    .whenComplete((tag, ex) -> {
+                    .whenComplete((tag, ex) -> session.ensureInEventLoop(() -> {
                         if (tag == null) {
                             pickItem(session, blockMapping);
                             return;
                         }
 
-                        session.ensureInEventLoop(() -> {
-                            if (addNbtData) {
-                                ListTag lore = new ListTag("Lore");
-                                lore.add(new StringTag("", "\"(+NBT)\""));
-                                CompoundTag display = tag.get("display");
-                                if (display == null) {
-                                    display = new CompoundTag("display");
-                                    tag.put(display);
-                                }
-                                display.put(lore);
+                        if (addNbtData) {
+                            ListTag lore = new ListTag("Lore");
+                            lore.add(new StringTag("", "\"(+NBT)\""));
+                            CompoundTag display = tag.get("display");
+                            if (display == null) {
+                                display = new CompoundTag("display");
+                                tag.put(display);
                             }
-                            // I don't really like this... I'd rather get an ID from the block mapping I think
-                            ItemMapping mapping = session.getItemMappings().getMapping(blockMapping.getPickItem());
+                            display.put(lore);
+                        }
+                        // I don't really like this... I'd rather get an ID from the block mapping I think
+                        ItemMapping mapping = session.getItemMappings().getMapping(blockMapping.getPickItem());
 
-                            ItemStack itemStack = new ItemStack(mapping.getJavaId(), 1, tag);
-                            InventoryUtils.findOrCreateItem(session, itemStack);
-                        });
-                    });
+                        ItemStack itemStack = new ItemStack(mapping.getJavaId(), 1, tag);
+                        InventoryUtils.findOrCreateItem(session, itemStack);
+                    }));
             return;
         }
 
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java
index aaedfa443..142ed6e88 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java
@@ -35,10 +35,13 @@ import io.netty.buffer.Unpooled;
 import org.geysermc.cumulus.Forms;
 import org.geysermc.cumulus.form.Form;
 import org.geysermc.cumulus.form.util.FormType;
+import org.geysermc.erosion.Constants;
+import org.geysermc.erosion.packet.ErosionPacket;
+import org.geysermc.erosion.packet.Packets;
+import org.geysermc.erosion.packet.geyserbound.GeyserboundPacket;
 import org.geysermc.floodgate.pluginmessage.PluginMessageChannels;
 import org.geysermc.geyser.GeyserImpl;
 import org.geysermc.geyser.GeyserLogger;
-import org.geysermc.geyser.api.network.AuthType;
 import org.geysermc.geyser.session.GeyserSession;
 import org.geysermc.geyser.translator.protocol.PacketTranslator;
 import org.geysermc.geyser.translator.protocol.Translator;
@@ -51,82 +54,96 @@ public class JavaCustomPayloadTranslator extends PacketTranslator<ClientboundCus
 
     @Override
     public void translate(GeyserSession session, ClientboundCustomPayloadPacket packet) {
-        // The only plugin messages it has to listen for are Floodgate plugin messages
-        if (session.remoteServer().authType() != AuthType.FLOODGATE) {
+        String channel = packet.getChannel();
+
+        if (channel.equals(Constants.PLUGIN_MESSAGE)) {
+            ByteBuf buf = Unpooled.wrappedBuffer(packet.getData());
+            ErosionPacket<?> erosionPacket = Packets.decode(buf);
+            ((GeyserboundPacket) erosionPacket).handle(session.getErosionHandler());
             return;
         }
 
-        String channel = packet.getChannel();
-
         if (channel.equals(PluginMessageChannels.FORM)) {
-            byte[] data = packet.getData();
+            session.ensureInEventLoop(() -> {
+                byte[] data = packet.getData();
 
-            // receive: first byte is form type, second and third are the id, remaining is the form data
-            // respond: first and second byte id, remaining is form response data
+                // receive: first byte is form type, second and third are the id, remaining is the form data
+                // respond: first and second byte id, remaining is form response data
 
-            FormType type = FormType.fromOrdinal(data[0]);
-            if (type == null) {
-                throw new NullPointerException("Got type " + data[0] + " which isn't a valid form type!");
-            }
-
-            String dataString = new String(data, 3, data.length - 3, Charsets.UTF_8);
-
-            Form form = Forms.fromJson(dataString, type, (ignored, response) -> {
-                byte[] finalData;
-                if (response == null) {
-                    // Response data can be null as of 1.19.20 (same behaviour as empty response data)
-                    // Only need to send the form id
-                    finalData = new byte[]{data[1], data[2]};
-                } else {
-                    byte[] raw = response.getBytes(StandardCharsets.UTF_8);
-                    finalData = new byte[raw.length + 2];
-
-                    finalData[0] = data[1];
-                    finalData[1] = data[2];
-                    System.arraycopy(raw, 0, finalData, 2, raw.length);
+                FormType type = FormType.fromOrdinal(data[0]);
+                if (type == null) {
+                    throw new NullPointerException("Got type " + data[0] + " which isn't a valid form type!");
                 }
 
-                session.sendDownstreamPacket(new ServerboundCustomPayloadPacket(channel, finalData));
+                String dataString = new String(data, 3, data.length - 3, Charsets.UTF_8);
+
+                Form form = Forms.fromJson(dataString, type, (ignored, response) -> {
+                    byte[] finalData;
+                    if (response == null) {
+                        // Response data can be null as of 1.19.20 (same behaviour as empty response data)
+                        // Only need to send the form id
+                        finalData = new byte[]{data[1], data[2]};
+                    } else {
+                        byte[] raw = response.getBytes(StandardCharsets.UTF_8);
+                        finalData = new byte[raw.length + 2];
+
+                        finalData[0] = data[1];
+                        finalData[1] = data[2];
+                        System.arraycopy(raw, 0, finalData, 2, raw.length);
+                    }
+
+                    session.sendDownstreamPacket(new ServerboundCustomPayloadPacket(channel, finalData));
+                });
+                session.sendForm(form);
             });
-            session.sendForm(form);
 
         } else if (channel.equals(PluginMessageChannels.TRANSFER)) {
-            byte[] data = packet.getData();
+            session.ensureInEventLoop(() -> {
+                byte[] data = packet.getData();
 
-            // port (4 bytes), address (remaining data)
-            if (data.length < 5) {
-                throw new NullPointerException("Transfer data should be at least 5 bytes long");
-            }
+                // port (4 bytes), address (remaining data)
+                if (data.length < 5) {
+                    throw new NullPointerException("Transfer data should be at least 5 bytes long");
+                }
 
-            int port = data[0] << 24 | (data[1] & 0xFF) << 16 | (data[2] & 0xFF) << 8 | data[3] & 0xFF;
-            String address = new String(data, 4, data.length - 4);
+                int port = data[0] << 24 | (data[1] & 0xFF) << 16 | (data[2] & 0xFF) << 8 | data[3] & 0xFF;
+                String address = new String(data, 4, data.length - 4);
 
-            if (logger.isDebug()) {
-                logger.info("Transferring client to: " + address + ":" + port);
-            }
+                if (logger.isDebug()) {
+                    logger.info("Transferring client to: " + address + ":" + port);
+                }
 
-            TransferPacket transferPacket = new TransferPacket();
-            transferPacket.setAddress(address);
-            transferPacket.setPort(port);
-            session.sendUpstreamPacket(transferPacket);
+                TransferPacket transferPacket = new TransferPacket();
+                transferPacket.setAddress(address);
+                transferPacket.setPort(port);
+                session.sendUpstreamPacket(transferPacket);
+            });
 
         } else if (channel.equals(PluginMessageChannels.PACKET)) {
-            logger.debug("A packet has been sent using the Floodgate api");
-            byte[] data = packet.getData();
+            session.ensureInEventLoop(() -> {
+                logger.debug("A packet has been sent using the Floodgate api");
+                byte[] data = packet.getData();
 
-            // packet id, packet data
-            if (data.length < 2) {
-                throw new IllegalStateException("Packet data should be at least 2 bytes long");
-            }
+                // packet id, packet data
+                if (data.length < 2) {
+                    throw new IllegalStateException("Packet data should be at least 2 bytes long");
+                }
 
-            int packetId = data[0] & 0xFF;
-            ByteBuf packetData = Unpooled.wrappedBuffer(data, 1, data.length - 1);
+                int packetId = data[0] & 0xFF;
+                ByteBuf packetData = Unpooled.wrappedBuffer(data, 1, data.length - 1);
 
-            var toSend = new UnknownPacket();
-            toSend.setPacketId(packetId);
-            toSend.setPayload(packetData);
+                var toSend = new UnknownPacket();
+                toSend.setPacketId(packetId);
+                toSend.setPayload(packetData);
 
-            session.sendUpstreamPacket(toSend);
+                session.sendUpstreamPacket(toSend);
+            });
         }
     }
+
+    @Override
+    public boolean shouldExecuteInEventLoop() {
+        // For Erosion packets
+        return false;
+    }
 }
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java
index 9afa337ef..7839a8102 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java
@@ -36,6 +36,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
 import org.geysermc.floodgate.pluginmessage.PluginMessageChannels;
 import org.geysermc.geyser.api.network.AuthType;
 import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
+import org.geysermc.geyser.erosion.GeyserboundHandshakePacketHandler;
 import org.geysermc.geyser.level.JavaDimension;
 import org.geysermc.geyser.session.GeyserSession;
 import org.geysermc.geyser.text.TextDecoration;
@@ -57,6 +58,11 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
         SessionPlayerEntity entity = session.getPlayerEntity();
         entity.setEntityId(packet.getEntityId());
 
+        if (session.getErosionHandler().isActive()) {
+            session.getErosionHandler().close();
+            session.setErosionHandler(new GeyserboundHandshakePacketHandler(session));
+        }
+
         Map<String, JavaDimension> dimensions = session.getDimensions();
         dimensions.clear();
 
@@ -129,6 +135,10 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
 
         session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:brand", PluginMessageUtils.getGeyserBrandData()));
 
+        // TODO don't send two packets
+//        if (true) {
+//            session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:register", Constants.PLUGIN_MESSAGE.getBytes(StandardCharsets.UTF_8)));
+//        }
         // register the plugin messaging channels used in Floodgate
         if (session.remoteServer().authType() == AuthType.FLOODGATE) {
             session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:register", PluginMessageChannels.getFloodgateRegisterData()));
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java
index aa7c9e6e7..1f03c3d36 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java
@@ -58,15 +58,16 @@ public class JavaBlockEventTranslator extends PacketTranslator<ClientboundBlockE
             blockEventPacket.setEventType(1);
             session.sendUpstreamPacket(blockEventPacket);
         } else if (packet.getValue() instanceof NoteBlockValue) {
-            int blockState = session.getGeyser().getWorldManager().getBlockAt(session, position);
-            blockEventPacket.setEventData(BlockStateValues.getNoteblockPitch(blockState));
-            session.sendUpstreamPacket(blockEventPacket);
+            session.getGeyser().getWorldManager().getBlockAtAsync(session, position).thenAccept(blockState -> {
+                blockEventPacket.setEventData(BlockStateValues.getNoteblockPitch(blockState));
+                session.sendUpstreamPacket(blockEventPacket);
+            });
         } else if (packet.getValue() instanceof PistonValue pistonValue) {
             PistonValueType action = (PistonValueType) packet.getType();
             Direction direction = Direction.fromPistonValue(pistonValue.getDirection());
             PistonCache pistonCache = session.getPistonCache();
 
-            if (session.getGeyser().getPlatformType() == PlatformType.SPIGOT) {
+            if (session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) {
                 // Mostly handled in the GeyserPistonEvents class
                 // Retracting sticky pistons is an exception, since the event is not called on Spigot from 1.13.2 - 1.17.1
                 // See https://github.com/PaperMC/Paper/blob/6fa1983e9ce177a4a412d5b950fd978620174777/patches/server/0304-Fire-BlockPistonRetractEvent-for-all-empty-pistons.patch
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java
index cd965e128..aab921aa8 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java
@@ -43,7 +43,7 @@ public class JavaBlockUpdateTranslator extends PacketTranslator<ClientboundBlock
     public void translate(GeyserSession session, ClientboundBlockUpdatePacket packet) {
         Vector3i pos = packet.getEntry().getPosition();
         boolean updatePlacement = session.getGeyser().getPlatformType() != PlatformType.SPIGOT && // Spigot simply listens for the block place event
-                session.getGeyser().getWorldManager().getBlockAt(session, pos) != packet.getEntry().getBlock();
+                !session.getErosionHandler().isActive() && session.getGeyser().getWorldManager().getBlockAt(session, pos) != packet.getEntry().getBlock();
         session.getWorldCache().updateServerCorrectBlockState(pos, packet.getEntry().getBlock());
         if (updatePlacement) {
             this.checkPlace(session, packet);
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaForgetLevelChunkTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaForgetLevelChunkTranslator.java
index e1c33b986..6baa0348f 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaForgetLevelChunkTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaForgetLevelChunkTranslator.java
@@ -52,7 +52,7 @@ public class JavaForgetLevelChunkTranslator extends PacketTranslator<Clientbound
         }
         removedSkulls.forEach(session.getSkullCache()::removeSkull);
 
-        if (!session.getGeyser().getWorldManager().shouldExpectLecternHandled()) {
+        if (!session.getGeyser().getWorldManager().shouldExpectLecternHandled(session)) {
             // Do the same thing with lecterns
             Iterator<Vector3i> iterator = session.getLecternCache().iterator();
             while (iterator.hasNext()) {
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java
index 081251447..4d6464643 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java
@@ -38,6 +38,7 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
 import com.nukkitx.math.vector.Vector3i;
 import com.nukkitx.nbt.NBTOutputStream;
 import com.nukkitx.nbt.NbtMap;
+import com.nukkitx.nbt.NbtMapBuilder;
 import com.nukkitx.nbt.NbtUtils;
 import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket;
 import io.netty.buffer.ByteBuf;
@@ -48,6 +49,7 @@ import it.unimi.dsi.fastutil.ints.IntArrayList;
 import it.unimi.dsi.fastutil.ints.IntList;
 import it.unimi.dsi.fastutil.ints.IntLists;
 import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+import org.geysermc.erosion.util.LecternUtils;
 import org.geysermc.geyser.entity.type.ItemFrameEntity;
 import org.geysermc.geyser.level.BedrockDimension;
 import org.geysermc.geyser.level.block.BlockStateValues;
@@ -94,6 +96,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
 
         final BlockEntityInfo[] blockEntities = packet.getBlockEntities();
         final List<NbtMap> bedrockBlockEntities = new ObjectArrayList<>(blockEntities.length);
+        final List<BlockEntityInfo> lecterns = new ObjectArrayList<>();
 
         BitSet waterloggedPaletteIds = new BitSet();
         BitSet bedrockOnlyBlockEntityIds = new BitSet();
@@ -240,7 +243,9 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
                 sections[bedrockSectionY] = new GeyserChunkSection(layers);
             }
 
-            session.getChunkCache().addToCache(packet.getX(), packet.getZ(), javaChunks);
+            if (!session.getErosionHandler().isActive()) {
+                session.getChunkCache().addToCache(packet.getX(), packet.getZ(), javaChunks);
+            }
 
             final int chunkBlockX = packet.getX() << 4;
             final int chunkBlockZ = packet.getZ() << 4;
@@ -262,8 +267,15 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
 
                 if (type == BlockEntityType.LECTERN && BlockStateValues.getLecternBookStates().get(blockState)) {
                     // If getLecternBookStates is false, let's just treat it like a normal block entity
-                    bedrockBlockEntities.add(session.getGeyser().getWorldManager().getLecternDataAt(
-                            session, x + chunkBlockX, y, z + chunkBlockZ, true));
+                    // Fill in tag with a default value
+                    NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(x + chunkBlockX, y, z + chunkBlockZ, 1);
+                    lecternTag.putCompound("book", NbtMap.builder()
+                                    .putByte("Count", (byte) 1)
+                                    .putShort("Damage", (short) 0)
+                                    .putString("Name", "minecraft:written_book").build());
+                    lecternTag.putInt("page", -1);
+                    bedrockBlockEntities.add(lecternTag.build());
+                    lecterns.add(blockEntity);
                     continue;
                 }
 
@@ -356,6 +368,10 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
         levelChunkPacket.setData(payload);
         session.sendUpstreamPacket(levelChunkPacket);
 
+        if (!lecterns.isEmpty()) {
+            session.getGeyser().getWorldManager().sendLecternData(session, packet.getX(), packet.getZ(), lecterns);
+        }
+
         for (Map.Entry<Vector3i, ItemFrameEntity> entry : session.getItemFrameCache().entrySet()) {
             Vector3i position = entry.getKey();
             if ((position.getX() >> 4) == packet.getX() && (position.getZ() >> 4) == packet.getZ()) {
diff --git a/core/src/main/java/org/geysermc/geyser/util/collection/LecternHasBookMap.java b/core/src/main/java/org/geysermc/geyser/util/collection/LecternHasBookMap.java
index 913ea44d5..91cd56f8e 100644
--- a/core/src/main/java/org/geysermc/geyser/util/collection/LecternHasBookMap.java
+++ b/core/src/main/java/org/geysermc/geyser/util/collection/LecternHasBookMap.java
@@ -27,9 +27,9 @@ package org.geysermc.geyser.util.collection;
 
 import com.nukkitx.math.vector.Vector3i;
 import com.nukkitx.nbt.NbtMap;
+import org.geysermc.erosion.util.LecternUtils;
 import org.geysermc.geyser.level.WorldManager;
 import org.geysermc.geyser.session.GeyserSession;
-import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator;
 import org.geysermc.geyser.util.BlockEntityUtils;
 
 /**
@@ -47,27 +47,24 @@ public class LecternHasBookMap extends FixedInt2BooleanMap {
         int offset = blockState - this.start;
         if (offset < 0 || offset >= this.value.length) {
             // Block state is out of bounds of this map - lectern has been destroyed, if it existed
-            if (!worldManager.shouldExpectLecternHandled()) {
+            if (!worldManager.shouldExpectLecternHandled(session)) {
                 session.getLecternCache().remove(position);
             }
             return;
         }
 
         boolean newLecternHasBook;
-        if (worldManager.shouldExpectLecternHandled()) {
-            // As of right now, no tag can be added asynchronously
-            worldManager.getLecternDataAt(session, position.getX(), position.getY(), position.getZ(), false);
+        if (worldManager.shouldExpectLecternHandled(session)) {
+            worldManager.sendLecternData(session, position.getX(), position.getY(), position.getZ());
         } else if ((newLecternHasBook = this.value[offset]) != this.get(worldManager.getBlockAt(session, position))) {
-            // If the lectern block was updated, or it previously had a book
-            NbtMap newLecternTag;
             // newLecternHasBook = the new lectern block state's "has book" toggle.
             if (newLecternHasBook) {
-                newLecternTag = worldManager.getLecternDataAt(session, position.getX(), position.getY(), position.getZ(), false);
+                worldManager.sendLecternData(session, position.getX(), position.getY(), position.getZ());
             } else {
                 session.getLecternCache().remove(position);
-                newLecternTag = LecternInventoryTranslator.getBaseLecternTag(position.getX(), position.getY(), position.getZ(), 0).build();
+                NbtMap newLecternTag = LecternUtils.getBaseLecternTag(position.getX(), position.getY(), position.getZ(), 0).build();
+                BlockEntityUtils.updateBlockEntity(session, newLecternTag, position);
             }
-            BlockEntityUtils.updateBlockEntity(session, newLecternTag, position);
         }
     }
 }
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 4f7433034..dfa459f01 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,6 +1,7 @@
 [versions]
 base-api = "1.0.0-SNAPSHOT"
 cumulus = "1.1.1"
+erosion = "1.0-20230330.170602-3"
 events = "1.0-SNAPSHOT"
 jackson = "2.14.0"
 fastutil = "8.5.2"
@@ -19,9 +20,9 @@ checkerframework = "3.19.0"
 log4j = "2.17.1"
 jline = "3.21.0"
 terminalconsoleappender = "1.2.0"
-paper = "1.19-R0.1-SNAPSHOT"
+folia = "1.19.4-R0.1-SNAPSHOT"
 viaversion = "4.0.0"
-adapters = "1.6-SNAPSHOT"
+adapters = "1.7-SNAPSHOT"
 commodore = "2.2"
 bungeecord = "a7c6ede"
 velocity = "3.0.0"
@@ -35,6 +36,9 @@ base-api = { group = "org.geysermc.api", name = "base-api", version.ref = "base-
 cumulus = { group = "org.geysermc.cumulus", name = "cumulus", version.ref = "cumulus" }
 events = { group = "org.geysermc.event", name = "events", version.ref = "events" }
 
+erosion-bukkit-common = { group = "org.geysermc.erosion", name = "bukkit-common", version.ref = "erosion" }
+erosion-common = { group = "org.geysermc.erosion", name = "common", version.ref = "erosion" }
+
 jackson-annotations = { group = "com.fasterxml.jackson.core", name = "jackson-annotations", version.ref = "jackson" }
 jackson-core = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jackson" }
 jackson-dataformat-yaml = { group = "com.fasterxml.jackson.dataformat", name = "jackson-dataformat-yaml", version.ref = "jackson" }
@@ -66,8 +70,8 @@ jline-terminal = { group = "org.jline", name = "jline-terminal", version.ref = "
 jline-terminal-jna = { group = "org.jline", name = "jline-terminal-jna", version.ref = "jline" }
 jline-reader = { group = "org.jline", name = "jline-reader", version.ref = "jline" }
 
-paper-api = { group = "io.papermc.paper", name = "paper-api", version.ref = "paper" }
-paper-mojangapi = { group = "io.papermc.paper", name = "paper-mojangapi", version.ref = "paper" }
+folia-api = { group = "dev.folia", name = "folia-api", version.ref = "folia" }
+paper-mojangapi = { group = "io.papermc.paper", name = "paper-mojangapi", version.ref = "folia" }
 
 # check these on https://modmuss50.me/fabric.html
 fabric-minecraft = { group = "com.mojang", name = "minecraft", version.ref = "fabric-minecraft" }

From a004fe9a3143df2d4b3d7ba9ba0c5f510fac0f9d Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Sat, 1 Apr 2023 01:32:06 -0400
Subject: [PATCH 57/59] Update Adapters to fix #3654

---
 gradle/libs.versions.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index dfa459f01..71b243430 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -22,7 +22,7 @@ jline = "3.21.0"
 terminalconsoleappender = "1.2.0"
 folia = "1.19.4-R0.1-SNAPSHOT"
 viaversion = "4.0.0"
-adapters = "1.7-SNAPSHOT"
+adapters = "1.8-SNAPSHOT"
 commodore = "2.2"
 bungeecord = "a7c6ede"
 velocity = "3.0.0"

From 5871ca3f22a2a45f0be5247ffce563427818079a Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Sat, 1 Apr 2023 15:25:37 -0400
Subject: [PATCH 58/59] Fix up boat types after 1.19.4

Fixes #3649
---
 .../java/org/geysermc/geyser/entity/type/BoatEntity.java    | 6 +++++-
 .../bedrock/BedrockEntityPickRequestTranslator.java         | 6 ++++--
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java
index 9fd96f46b..07c7e7643 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java
@@ -124,7 +124,11 @@ public class BoatEntity extends Entity {
 
     public void setVariant(IntEntityMetadata entityMetadata) {
         variant = entityMetadata.getPrimitiveValue();
-        dirtyMetadata.put(EntityData.VARIANT, variant);
+        dirtyMetadata.put(EntityData.VARIANT, switch (variant) {
+            case 6, 7 -> variant - 1; // Dark oak and mangrove
+            case 5, 8 -> 0; // TODO temp until 1.20. Cherry and bamboo
+            default -> variant;
+        });
     }
 
     public void setPaddlingLeft(BooleanEntityMetadata entityMetadata) {
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockEntityPickRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockEntityPickRequestTranslator.java
index 482d153bb..b20bc9ad9 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockEntityPickRequestTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockEntityPickRequestTranslator.java
@@ -62,8 +62,10 @@ public class BedrockEntityPickRequestTranslator extends PacketTranslator<EntityP
                     case 2 -> "birch";
                     case 3 -> "jungle";
                     case 4 -> "acacia";
-                    case 5 -> "dark_oak";
-                    case 6 -> "mangrove";
+                    //case 5 -> "cherry"; TODO
+                    case 6 -> "dark_oak";
+                    case 7 -> "mangrove";
+                    //case 8 -> "bamboo";
                     default -> "oak";
                 };
                 itemName = typeOfBoat + "_" + entity.getDefinition().entityType().name().toLowerCase(Locale.ROOT);

From 0f99abc3a44a7beaef221f174456bbb7ef7c6227 Mon Sep 17 00:00:00 2001
From: Camotoy <20743703+Camotoy@users.noreply.github.com>
Date: Sun, 2 Apr 2023 16:42:44 -0400
Subject: [PATCH 59/59] Fix #3549

---
 .../java/JavaUpdateRecipesTranslator.java        | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java
index e665d5424..2fe25bcb1 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java
@@ -70,7 +70,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
     /**
      * Required to use the specified cartography table recipes
      */
-    private static final List<CraftingData> CARTOGRAPHY_RECIPES = Arrays.asList(
+    private static final List<CraftingData> CARTOGRAPHY_RECIPES = List.of(
             CraftingData.fromMulti(UUID.fromString("8b36268c-1829-483c-a0f1-993b7156a8f2"), ++LAST_RECIPE_NET_ID), // Map extending
             CraftingData.fromMulti(UUID.fromString("442d85ed-8272-4543-a6f1-418f90ded05d"), ++LAST_RECIPE_NET_ID), // Map cloning
             CraftingData.fromMulti(UUID.fromString("98c84b38-1085-46bd-b1ce-dd38c159e6cc"), ++LAST_RECIPE_NET_ID), // Map upgrading
@@ -99,6 +99,10 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
                     // Strip NBT - tools won't appear in the recipe book otherwise
                     output = output.toBuilder().tag(null).build();
                     ItemDescriptorWithCount[][] inputCombinations = combinations(session, shapelessRecipeData.getIngredients());
+                    if (inputCombinations == null) {
+                        continue;
+                    }
+
                     for (ItemDescriptorWithCount[] inputs : inputCombinations) {
                         UUID uuid = UUID.randomUUID();
                         craftingDataPacket.getCraftingData().add(CraftingData.fromShapeless(uuid.toString(),
@@ -116,6 +120,9 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
                     // See above
                     output = output.toBuilder().tag(null).build();
                     ItemDescriptorWithCount[][] inputCombinations = combinations(session, shapedRecipeData.getIngredients());
+                    if (inputCombinations == null) {
+                        continue;
+                    }
                     for (ItemDescriptorWithCount[] inputs : inputCombinations) {
                         UUID uuid = UUID.randomUUID();
                         craftingDataPacket.getCraftingData().add(CraftingData.fromShaped(uuid.toString(),
@@ -216,12 +223,14 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
      * @return the Java ingredient list as an array that Bedrock can understand
      */
     private ItemDescriptorWithCount[][] combinations(GeyserSession session, Ingredient[] ingredients) {
+        boolean empty = true;
         Map<Set<ItemDescriptorWithCount>, IntSet> squashedOptions = new HashMap<>();
         for (int i = 0; i < ingredients.length; i++) {
             if (ingredients[i].getOptions().length == 0) {
                 squashedOptions.computeIfAbsent(Collections.singleton(ItemDescriptorWithCount.EMPTY), k -> new IntOpenHashSet()).add(i);
                 continue;
             }
+            empty = false;
             Ingredient ingredient = ingredients[i];
             Map<GroupedItem, List<ItemDescriptorWithCount>> groupedByIds = Arrays.stream(ingredient.getOptions())
                     .map(item -> ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, item)))
@@ -249,6 +258,11 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
             }
             squashedOptions.computeIfAbsent(optionSet, k -> new IntOpenHashSet()).add(i);
         }
+        if (empty) {
+            // Crashes Bedrock 1.19.70 otherwise
+            // Fixes https://github.com/GeyserMC/Geyser/issues/3549
+            return null;
+        }
         int totalCombinations = 1;
         for (Set<ItemDescriptorWithCount> optionSet : squashedOptions.keySet()) {
             totalCombinations *= optionSet.size();