diff --git a/README.md b/README.md index 11d7e835d..9da7caf5d 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,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.17 - 1.17.2 and Minecraft Java 1.17.1. +### Currently supporting Minecraft Bedrock 1.17.0 - 1.17.10 and Minecraft Java 1.17.1. ## Setting Up Take a look [here](https://github.com/GeyserMC/Geyser/wiki/Setup) for how to set up Geyser. diff --git a/bootstrap/bungeecord/pom.xml b/bootstrap/bungeecord/pom.xml index 710c8176e..0f13390d5 100644 --- a/bootstrap/bungeecord/pom.xml +++ b/bootstrap/bungeecord/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 1.4.0-SNAPSHOT + 1.4.1-SNAPSHOT bootstrap-bungeecord @@ -14,7 +14,7 @@ org.geysermc connector - 1.4.0-SNAPSHOT + 1.4.1-SNAPSHOT compile diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml index bf31f3fea..98a08ee31 100644 --- a/bootstrap/pom.xml +++ b/bootstrap/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 1.4.0-SNAPSHOT + 1.4.1-SNAPSHOT bootstrap-parent pom diff --git a/bootstrap/spigot/pom.xml b/bootstrap/spigot/pom.xml index 4d295b66d..133ea7779 100644 --- a/bootstrap/spigot/pom.xml +++ b/bootstrap/spigot/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 1.4.0-SNAPSHOT + 1.4.1-SNAPSHOT bootstrap-spigot @@ -21,7 +21,7 @@ org.geysermc connector - 1.4.0-SNAPSHOT + 1.4.1-SNAPSHOT compile diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigot1_11CraftingListener.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigot1_11CraftingListener.java index eff79c7cc..4f24af19c 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigot1_11CraftingListener.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigot1_11CraftingListener.java @@ -50,7 +50,7 @@ import org.bukkit.inventory.ShapelessRecipe; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.item.ItemTranslator; -import org.geysermc.connector.network.translators.item.RecipeRegistry; +import org.geysermc.connector.utils.InventoryUtils; import java.util.*; @@ -94,7 +94,7 @@ public class GeyserSpigot1_11CraftingListener implements Listener { } public void sendServerRecipes(GeyserSession session) { - int netId = RecipeRegistry.LAST_RECIPE_NET_ID; + int netId = InventoryUtils.LAST_RECIPE_NET_ID; CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); craftingDataPacket.setCleanRecipes(true); @@ -106,7 +106,7 @@ public class GeyserSpigot1_11CraftingListener implements Listener { Pair outputs = translateToBedrock(session, recipe.getResult()); ItemStack javaOutput = outputs.getKey(); ItemData output = outputs.getValue(); - if (output.getId() == 0) continue; // If items make air we don't want that + if (output == null || output.getId() == 0) continue; // If items make air we don't want that boolean isNotAllAir = false; // Check for all-air recipes if (recipe instanceof ShapedRecipe) { diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigotBlockPlaceListener.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigotBlockPlaceListener.java index 51e68a263..8111c7e56 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigotBlockPlaceListener.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigotBlockPlaceListener.java @@ -35,7 +35,8 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPlaceEvent; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.world.block.BlockStateValues; +import org.geysermc.connector.registry.BlockRegistries; import org.geysermc.platform.spigot.world.manager.GeyserSpigotWorldManager; @AllArgsConstructor @@ -53,11 +54,11 @@ public class GeyserSpigotBlockPlaceListener implements Listener { placeBlockSoundPacket.setPosition(Vector3f.from(event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ())); placeBlockSoundPacket.setBabySound(false); if (worldManager.isLegacy()) { - placeBlockSoundPacket.setExtraData(session.getBlockTranslator().getBedrockBlockId(worldManager.getBlockAt(session, + placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(worldManager.getBlockAt(session, event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ()))); } else { String javaBlockId = event.getBlockPlaced().getBlockData().getAsString(); - placeBlockSoundPacket.setExtraData(session.getBlockTranslator().getBedrockBlockId(BlockTranslator.getJavaIdBlockMap().getOrDefault(javaBlockId, BlockTranslator.JAVA_AIR_ID))); + placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIERS.get().getOrDefault(javaBlockId, BlockStateValues.JAVA_AIR_ID))); } placeBlockSoundPacket.setIdentifier(":"); session.sendUpstreamPacket(placeBlockSoundPacket); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java index c59cb0d77..1875d3451 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java @@ -31,7 +31,7 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.world.block.BlockStateValues; import org.geysermc.geyser.adapters.spigot.SpigotAdapters; import org.geysermc.geyser.adapters.spigot.SpigotWorldAdapter; @@ -51,7 +51,7 @@ public class GeyserSpigot1_12NativeWorldManager extends GeyserSpigot1_12WorldMan public int getBlockAt(GeyserSession session, int x, int y, int z) { Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername()); if (player == null) { - return BlockTranslator.JAVA_AIR_ID; + return BlockStateValues.JAVA_AIR_ID; } // Get block entity storage BlockStorage storage = Via.getManager().getConnectionManager().getConnectedClient(player.getUniqueId()).get(BlockStorage.class); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java index b50aefee7..e32b52f24 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java @@ -37,7 +37,7 @@ import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.world.block.BlockStateValues; import java.util.List; @@ -70,11 +70,11 @@ public class GeyserSpigot1_12WorldManager extends GeyserSpigotWorldManager { public int getBlockAt(GeyserSession session, int x, int y, int z) { Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername()); if (player == null) { - return BlockTranslator.JAVA_AIR_ID; + return BlockStateValues.JAVA_AIR_ID; } if (!player.getWorld().isChunkLoaded(x >> 4, z >> 4)) { // Prevent nasty async errors if a player is loading in - return BlockTranslator.JAVA_AIR_ID; + return BlockStateValues.JAVA_AIR_ID; } // Get block entity storage BlockStorage storage = Via.getManager().getConnectionManager().getConnectedClient(player.getUniqueId()).get(BlockStorage.class); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotFallbackWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotFallbackWorldManager.java index 8bd2c6628..88721b8b1 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotFallbackWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotFallbackWorldManager.java @@ -27,7 +27,7 @@ package org.geysermc.platform.spigot.world.manager; import org.bukkit.plugin.Plugin; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.world.block.BlockStateValues; /** * Should only be used when we know {@link GeyserSpigotWorldManager#getBlockAt(GeyserSession, int, int, int)} @@ -41,7 +41,7 @@ public class GeyserSpigotFallbackWorldManager extends GeyserSpigotWorldManager { @Override public int getBlockAt(GeyserSession session, int x, int y, int z) { - return BlockTranslator.JAVA_AIR_ID; + return BlockStateValues.JAVA_AIR_ID; } @Override diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java index 7e0b9267b..91a589da1 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java @@ -29,7 +29,7 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.world.block.BlockStateValues; import org.geysermc.geyser.adapters.spigot.SpigotAdapters; import org.geysermc.geyser.adapters.spigot.SpigotWorldAdapter; @@ -45,7 +45,7 @@ public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager { public int getBlockAt(GeyserSession session, int x, int y, int z) { Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername()); if (player == null) { - return BlockTranslator.JAVA_AIR_ID; + return BlockStateValues.JAVA_AIR_ID; } return adapter.getBlockAt(player.getWorld(), x, y, z); } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotWorldManager.java index 6746a8d1a..be6342172 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -42,7 +42,8 @@ import org.bukkit.plugin.Plugin; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.translators.LecternInventoryTranslator; import org.geysermc.connector.network.translators.world.GeyserWorldManager; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.world.block.BlockStateValues; +import org.geysermc.connector.registry.BlockRegistries; import org.geysermc.connector.utils.BlockEntityUtils; import org.geysermc.connector.utils.GameRule; @@ -68,15 +69,15 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager { public int getBlockAt(GeyserSession session, int x, int y, int z) { Player bukkitPlayer; if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) { - return BlockTranslator.JAVA_AIR_ID; + return BlockStateValues.JAVA_AIR_ID; } World world = bukkitPlayer.getWorld(); if (!world.isChunkLoaded(x >> 4, z >> 4)) { // If the chunk isn't loaded, how could we even be here? - return BlockTranslator.JAVA_AIR_ID; + return BlockStateValues.JAVA_AIR_ID; } - return BlockTranslator.getJavaIdBlockMap().getOrDefault(world.getBlockAt(x, y, z).getBlockData().getAsString(), BlockTranslator.JAVA_AIR_ID); + return BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(world.getBlockAt(x, y, z).getBlockData().getAsString(), BlockStateValues.JAVA_AIR_ID); } @Override diff --git a/bootstrap/sponge/pom.xml b/bootstrap/sponge/pom.xml index 72733a311..e0f019152 100644 --- a/bootstrap/sponge/pom.xml +++ b/bootstrap/sponge/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 1.4.0-SNAPSHOT + 1.4.1-SNAPSHOT bootstrap-sponge @@ -14,7 +14,7 @@ org.geysermc connector - 1.4.0-SNAPSHOT + 1.4.1-SNAPSHOT compile diff --git a/bootstrap/standalone/pom.xml b/bootstrap/standalone/pom.xml index 2d28a7535..64aa54745 100644 --- a/bootstrap/standalone/pom.xml +++ b/bootstrap/standalone/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 1.4.0-SNAPSHOT + 1.4.1-SNAPSHOT bootstrap-standalone @@ -14,7 +14,7 @@ org.geysermc connector - 1.4.0-SNAPSHOT + 1.4.1-SNAPSHOT compile diff --git a/bootstrap/velocity/pom.xml b/bootstrap/velocity/pom.xml index e44d7b48f..c67f5a628 100644 --- a/bootstrap/velocity/pom.xml +++ b/bootstrap/velocity/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 1.4.0-SNAPSHOT + 1.4.1-SNAPSHOT bootstrap-velocity @@ -14,7 +14,7 @@ org.geysermc connector - 1.4.0-SNAPSHOT + 1.4.1-SNAPSHOT compile diff --git a/common/pom.xml b/common/pom.xml index 8ddcfd981..2dfa63a42 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 1.4.0-SNAPSHOT + 1.4.1-SNAPSHOT common diff --git a/connector/pom.xml b/connector/pom.xml index b05a969b9..4c8391766 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 1.4.0-SNAPSHOT + 1.4.1-SNAPSHOT connector @@ -21,7 +21,7 @@ org.geysermc common - 1.4.0-SNAPSHOT + 1.4.1-SNAPSHOT compile @@ -57,8 +57,8 @@ com.github.CloudburstMC.Protocol - bedrock-v440 - 1656151 + bedrock-v448 + ddfa38b compile diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java index 9c3386e38..291f2d7e5 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java @@ -44,20 +44,11 @@ import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.metrics.Metrics; import org.geysermc.connector.network.ConnectorServerEventHandler; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.BiomeTranslator; -import org.geysermc.connector.network.translators.EntityIdentifierRegistry; +import org.geysermc.connector.registry.BlockRegistries; +import org.geysermc.connector.registry.Registries; import org.geysermc.connector.network.translators.PacketTranslatorRegistry; -import org.geysermc.connector.network.translators.collision.CollisionTranslator; -import org.geysermc.connector.network.translators.effect.EffectRegistry; -import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemTranslator; -import org.geysermc.connector.network.translators.item.PotionMixRegistry; -import org.geysermc.connector.network.translators.item.RecipeRegistry; -import org.geysermc.connector.network.translators.sound.SoundHandlerRegistry; -import org.geysermc.connector.network.translators.sound.SoundRegistry; import org.geysermc.connector.network.translators.world.WorldManager; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; -import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator; import org.geysermc.connector.network.translators.world.block.entity.SkullBlockEntityTranslator; import org.geysermc.connector.skin.FloodgateSkinUploader; import org.geysermc.connector.utils.*; @@ -158,19 +149,11 @@ public class GeyserConnector { PacketTranslatorRegistry.init(); /* Initialize translators and registries */ - BiomeTranslator.init(); - BlockTranslator.init(); - BlockEntityTranslator.init(); - EffectRegistry.init(); - EntityIdentifierRegistry.init(); - ItemRegistry.init(); + BlockRegistries.init(); + Registries.init(); + ItemTranslator.init(); - CollisionTranslator.init(); LocaleUtils.init(); - PotionMixRegistry.init(); - RecipeRegistry.init(); - SoundRegistry.init(); - SoundHandlerRegistry.init(); ResourcePack.loadPacks(); diff --git a/connector/src/main/java/org/geysermc/connector/entity/AreaEffectCloudEntity.java b/connector/src/main/java/org/geysermc/connector/entity/AreaEffectCloudEntity.java index 5a33bc98c..218275ae8 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/AreaEffectCloudEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/AreaEffectCloudEntity.java @@ -32,7 +32,7 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.effect.EffectRegistry; +import org.geysermc.connector.utils.EffectUtils; public class AreaEffectCloudEntity extends Entity { @@ -59,7 +59,7 @@ public class AreaEffectCloudEntity extends Entity { metadata.put(EntityData.EFFECT_COLOR, entityMetadata.getValue()); } else if (entityMetadata.getId() == 11) { Particle particle = (Particle) entityMetadata.getValue(); - int particleId = EffectRegistry.getParticleId(session, particle.getType()); + int particleId = EffectUtils.getParticleId(session, particle.getType()); if (particleId != -1) { metadata.put(EntityData.AREA_EFFECT_CLOUD_PARTICLE_ID, particleId); } diff --git a/connector/src/main/java/org/geysermc/connector/entity/CommandBlockMinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/CommandBlockMinecartEntity.java index bda4e7972..c04e9f0b7 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/CommandBlockMinecartEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/CommandBlockMinecartEntity.java @@ -60,7 +60,7 @@ public class CommandBlockMinecartEntity extends DefaultBlockMinecartEntity { */ @Override public void updateDefaultBlockMetadata(GeyserSession session) { - metadata.put(EntityData.DISPLAY_ITEM, session.getBlockTranslator().getBedrockRuntimeCommandBlockId()); + metadata.put(EntityData.DISPLAY_ITEM, session.getBlockMappings().getCommandBlockRuntimeId()); metadata.put(EntityData.DISPLAY_OFFSET, 6); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/DefaultBlockMinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/DefaultBlockMinecartEntity.java index 24e5bb259..5df7ae440 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/DefaultBlockMinecartEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/DefaultBlockMinecartEntity.java @@ -60,7 +60,7 @@ public class DefaultBlockMinecartEntity extends MinecartEntity { customBlock = (int) entityMetadata.getValue(); if (showCustomBlock) { - metadata.put(EntityData.DISPLAY_ITEM, session.getBlockTranslator().getBedrockBlockId(customBlock)); + metadata.put(EntityData.DISPLAY_ITEM, session.getBlockMappings().getBedrockBlockId(customBlock)); } } @@ -77,7 +77,7 @@ public class DefaultBlockMinecartEntity extends MinecartEntity { if (entityMetadata.getId() == 13) { if ((boolean) entityMetadata.getValue()) { showCustomBlock = true; - metadata.put(EntityData.DISPLAY_ITEM, session.getBlockTranslator().getBedrockBlockId(customBlock)); + metadata.put(EntityData.DISPLAY_ITEM, session.getBlockMappings().getBedrockBlockId(customBlock)); metadata.put(EntityData.DISPLAY_OFFSET, customBlockOffset); } else { showCustomBlock = false; diff --git a/connector/src/main/java/org/geysermc/connector/entity/FallingBlockEntity.java b/connector/src/main/java/org/geysermc/connector/entity/FallingBlockEntity.java index bd0fe9b80..a82118c21 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/FallingBlockEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/FallingBlockEntity.java @@ -42,7 +42,7 @@ public class FallingBlockEntity extends Entity { @Override public void spawnEntity(GeyserSession session) { - this.metadata.put(EntityData.VARIANT, session.getBlockTranslator().getBedrockBlockId(javaId)); + this.metadata.put(EntityData.VARIANT, session.getBlockMappings().getBedrockBlockId(javaId)); super.spawnEntity(session); } diff --git a/connector/src/main/java/org/geysermc/connector/entity/FishingHookEntity.java b/connector/src/main/java/org/geysermc/connector/entity/FishingHookEntity.java index db44a0767..66cfe386d 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/FishingHookEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/FishingHookEntity.java @@ -36,10 +36,10 @@ import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.collision.BoundingBox; import org.geysermc.connector.network.translators.collision.CollisionManager; -import org.geysermc.connector.network.translators.collision.CollisionTranslator; import org.geysermc.connector.network.translators.collision.translators.BlockCollision; import org.geysermc.connector.network.translators.world.block.BlockStateValues; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.registry.BlockRegistries; +import org.geysermc.connector.utils.BlockUtils; import java.util.List; import java.util.concurrent.ThreadLocalRandom; @@ -97,14 +97,14 @@ public class FishingHookEntity extends ThrowableEntity { boolean collided = false; for (Vector3i blockPos : collidableBlocks) { int blockID = session.getConnector().getWorldManager().getBlockAt(session, blockPos); - BlockCollision blockCollision = CollisionTranslator.getCollision(blockID, blockPos.getX(), blockPos.getY(), blockPos.getZ()); + BlockCollision blockCollision = BlockUtils.getCollision(blockID, blockPos.getX(), blockPos.getY(), blockPos.getZ()); if (blockCollision != null && blockCollision.checkIntersection(boundingBox)) { // TODO Push bounding box out of collision to improve movement collided = true; } int waterLevel = BlockStateValues.getWaterLevel(blockID); - if (BlockTranslator.isWaterlogged(blockID)) { + if (BlockRegistries.WATERLOGGED.get().contains(blockID)) { waterLevel = 0; } if (waterLevel >= 0) { @@ -175,7 +175,7 @@ public class FishingHookEntity extends ThrowableEntity { */ protected boolean isInAir(GeyserSession session) { int block = session.getConnector().getWorldManager().getBlockAt(session, position.toInt()); - return block == BlockTranslator.JAVA_AIR_ID; + return block == BlockStateValues.JAVA_AIR_ID; } @Override diff --git a/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java index 2eb083883..fea1e62bd 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java @@ -30,7 +30,7 @@ import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.world.block.BlockStateValues; public class FurnaceMinecartEntity extends DefaultBlockMinecartEntity { @@ -52,7 +52,7 @@ public class FurnaceMinecartEntity extends DefaultBlockMinecartEntity { @Override public void updateDefaultBlockMetadata(GeyserSession session) { - metadata.put(EntityData.DISPLAY_ITEM, session.getBlockTranslator().getBedrockBlockId(hasFuel ? BlockTranslator.JAVA_RUNTIME_FURNACE_LIT_ID : BlockTranslator.JAVA_RUNTIME_FURNACE_ID)); + metadata.put(EntityData.DISPLAY_ITEM, session.getBlockMappings().getBedrockBlockId(hasFuel ? BlockStateValues.JAVA_FURNACE_LIT_ID : BlockStateValues.JAVA_FURNACE_ID)); metadata.put(EntityData.DISPLAY_OFFSET, 6); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java index f2f36e606..dfa989c1d 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java @@ -38,9 +38,8 @@ import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import lombok.Getter; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemTranslator; +import org.geysermc.connector.registry.type.ItemMapping; import java.util.concurrent.TimeUnit; @@ -85,12 +84,12 @@ public class ItemFrameEntity extends Entity { public void spawnEntity(GeyserSession session) { NbtMapBuilder blockBuilder = NbtMap.builder() .putString("name", this.entityType == EntityType.GLOW_ITEM_FRAME ? "minecraft:glow_frame" : "minecraft:frame") - .putInt("version", session.getBlockTranslator().getBlockStateVersion()); + .putInt("version", session.getBlockMappings().getBlockStateVersion()); blockBuilder.put("states", NbtMap.builder() .putInt("facing_direction", direction.ordinal()) .putByte("item_frame_map_bit", (byte) 0) .build()); - bedrockRuntimeId = session.getBlockTranslator().getItemFrame(blockBuilder.build()); + bedrockRuntimeId = session.getBlockMappings().getItemFrame(blockBuilder.build()); bedrockPosition = Vector3i.from(position.getFloorX(), position.getFloorY(), position.getFloorZ()); session.getItemFrameCache().put(bedrockPosition, this); @@ -108,7 +107,7 @@ public class ItemFrameEntity extends Entity { if (entityMetadata.getId() == 8 && entityMetadata.getValue() != null) { this.heldItem = (ItemStack) entityMetadata.getValue(); ItemData itemData = ItemTranslator.translateToBedrock(session, heldItem); - ItemEntry itemEntry = ItemRegistry.getItem((ItemStack) entityMetadata.getValue()); + ItemMapping mapping = session.getItemMappings().getMapping((ItemStack) entityMetadata.getValue()); NbtMapBuilder builder = NbtMap.builder(); builder.putByte("Count", (byte) itemData.getCount()); @@ -116,7 +115,7 @@ public class ItemFrameEntity extends Entity { builder.put("tag", itemData.getTag()); } builder.putShort("Damage", (short) itemData.getDamage()); - builder.putString("Name", itemEntry.getBedrockIdentifier()); + builder.putString("Name", mapping.getBedrockIdentifier()); NbtMapBuilder tag = getDefaultTag().toBuilder(); tag.put("Item", builder.build()); tag.putFloat("ItemDropChance", 1.0f); @@ -149,7 +148,7 @@ public class ItemFrameEntity extends Entity { UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); updateBlockPacket.setDataLayer(0); updateBlockPacket.setBlockPosition(bedrockPosition); - updateBlockPacket.setRuntimeId(session.getBlockTranslator().getBedrockAirId()); + updateBlockPacket.setRuntimeId(session.getBlockMappings().getBedrockAirId()); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); diff --git a/connector/src/main/java/org/geysermc/connector/entity/LivingEntity.java b/connector/src/main/java/org/geysermc/connector/entity/LivingEntity.java index e1c85fc08..5ba66f71a 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/LivingEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/LivingEntity.java @@ -45,7 +45,7 @@ import lombok.Setter; import org.geysermc.connector.entity.attribute.GeyserAttributeType; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemRegistry; +import org.geysermc.connector.registry.type.ItemMapping; import org.geysermc.connector.utils.AttributeUtils; import org.geysermc.connector.utils.ChunkUtils; @@ -89,8 +89,9 @@ public class LivingEntity extends Entity { //blocking gets triggered when using a bow, but if we set USING_ITEM for all items, it may look like //you're "mining" with ex. a shield. - boolean isUsingShield = (getHand().getId() == ItemRegistry.SHIELD.getBedrockId() || - getHand().equals(ItemData.AIR) && getOffHand().getId() == ItemRegistry.SHIELD.getBedrockId()); + ItemMapping shield = session.getItemMappings().getStoredItems().shield(); + boolean isUsingShield = (getHand().getId() == shield.getBedrockId() || + getHand().equals(ItemData.AIR) && getOffHand().getId() == shield.getBedrockId()); metadata.getFlags().setFlag(EntityFlag.USING_ITEM, (xd & 0x01) == 0x01 && !isUsingShield); metadata.getFlags().setFlag(EntityFlag.BLOCKING, (xd & 0x01) == 0x01); @@ -171,10 +172,11 @@ public class LivingEntity extends Entity { ItemData chestplate = this.chestplate; // If an entity has a banner on them, it will be in the helmet slot in Java but the chestplate spot in Bedrock // But don't overwrite the chestplate if it isn't empty - if (chestplate.getId() == ItemData.AIR.getId() && helmet.getId() == ItemRegistry.BANNER.getBedrockId()) { + ItemMapping banner = session.getItemMappings().getStoredItems().banner(); + if (chestplate.getId() == ItemData.AIR.getId() && helmet.getId() == banner.getBedrockId()) { chestplate = this.helmet; helmet = ItemData.AIR; - } else if (chestplate.getId() == ItemRegistry.BANNER.getBedrockId()) { + } else if (chestplate.getId() == banner.getBedrockId()) { // Prevent chestplate banners from showing erroneously chestplate = ItemData.AIR; } diff --git a/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java index 18d1d92a1..6ab9a1b22 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java @@ -57,7 +57,7 @@ public class MinecartEntity extends Entity { if (!(this instanceof DefaultBlockMinecartEntity)) { // Handled in the DefaultBlockMinecartEntity class // Custom block if (entityMetadata.getId() == 11) { - metadata.put(EntityData.DISPLAY_ITEM, session.getBlockTranslator().getBedrockBlockId((int) entityMetadata.getValue())); + metadata.put(EntityData.DISPLAY_ITEM, session.getBlockMappings().getBedrockBlockId((int) entityMetadata.getValue())); } // Custom block offset diff --git a/connector/src/main/java/org/geysermc/connector/entity/SpawnerMinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/SpawnerMinecartEntity.java index 2f7af73eb..c6d4c3aa5 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/SpawnerMinecartEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/SpawnerMinecartEntity.java @@ -29,7 +29,7 @@ import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.world.block.BlockStateValues; public class SpawnerMinecartEntity extends DefaultBlockMinecartEntity { @@ -39,7 +39,7 @@ public class SpawnerMinecartEntity extends DefaultBlockMinecartEntity { @Override public void updateDefaultBlockMetadata(GeyserSession session) { - metadata.put(EntityData.DISPLAY_ITEM, session.getBlockTranslator().getBedrockBlockId(BlockTranslator.JAVA_RUNTIME_SPAWNER_ID)); + metadata.put(EntityData.DISPLAY_ITEM, session.getBlockMappings().getBedrockBlockId(BlockStateValues.JAVA_SPAWNER_ID)); metadata.put(EntityData.DISPLAY_OFFSET, 6); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/ThrownPotionEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ThrownPotionEntity.java index 9ce218a81..735bf274c 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/ThrownPotionEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/ThrownPotionEntity.java @@ -36,9 +36,8 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.Potion; +import org.geysermc.connector.registry.type.ItemMapping; import java.util.EnumSet; @@ -53,8 +52,8 @@ public class ThrownPotionEntity extends ThrowableEntity { public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { if (entityMetadata.getId() == 8 && entityMetadata.getType() == MetadataType.ITEM) { ItemStack itemStack = (ItemStack) entityMetadata.getValue(); - ItemEntry itemEntry = ItemRegistry.getItem(itemStack); - if (itemEntry.getJavaIdentifier().endsWith("potion") && itemStack.getNbt() != null) { + ItemMapping mapping = session.getItemMappings().getMapping(itemStack); + if (mapping.getJavaIdentifier().endsWith("potion") && itemStack.getNbt() != null) { Tag potionTag = itemStack.getNbt().get("Potion"); if (potionTag instanceof StringTag) { Potion potion = Potion.getByJavaIdentifier(((StringTag) potionTag).getValue()); @@ -67,7 +66,7 @@ public class ThrownPotionEntity extends ThrowableEntity { } } - boolean isLingering = itemEntry.getJavaIdentifier().equals("minecraft:lingering_potion"); + boolean isLingering = mapping.getJavaIdentifier().equals("minecraft:lingering_potion"); metadata.getFlags().setFlag(EntityFlag.LINGERING, isLingering); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/AnimalEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/AnimalEntity.java index efded1f6f..2495eab0a 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/AnimalEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/AnimalEntity.java @@ -29,7 +29,7 @@ import com.nukkitx.math.vector.Vector3f; import org.geysermc.connector.entity.living.AgeableEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; public class AnimalEntity extends AgeableEntity { @@ -42,7 +42,7 @@ public class AnimalEntity extends AgeableEntity { * wheat. * @return true if this is a valid item to breed with for this animal. */ - public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) { + public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemMapping mapping) { // This is what it defaults to. OK. return javaIdentifierStripped.equals("wheat"); } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/AxolotlEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/AxolotlEntity.java index 7c6c81ba2..f3d634140 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/AxolotlEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/AxolotlEntity.java @@ -31,7 +31,7 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; public class AxolotlEntity extends AnimalEntity { public AxolotlEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { @@ -59,7 +59,7 @@ public class AxolotlEntity extends AnimalEntity { } @Override - public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) { + public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemMapping mapping) { return javaIdentifierStripped.equals("tropical_fish_bucket"); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/BeeEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/BeeEntity.java index 59035bb85..07136252a 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/BeeEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/BeeEntity.java @@ -33,7 +33,7 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.packet.EntityEventPacket; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; public class BeeEntity extends AnimalEntity { @@ -66,7 +66,7 @@ public class BeeEntity extends AnimalEntity { } @Override - public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) { - return session.getTagCache().isFlower(itemEntry); + public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemMapping mapping) { + return session.getTagCache().isFlower(mapping); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/ChickenEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/ChickenEntity.java index b5f0395d4..c7eb62c6e 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/ChickenEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/ChickenEntity.java @@ -28,7 +28,7 @@ package org.geysermc.connector.entity.living.animal; import com.nukkitx.math.vector.Vector3f; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; public class ChickenEntity extends AnimalEntity { @@ -37,7 +37,7 @@ public class ChickenEntity extends AnimalEntity { } @Override - public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) { + public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemMapping mapping) { return javaIdentifierStripped.contains("seeds"); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/FoxEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/FoxEntity.java index 2c1934139..26da89612 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/FoxEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/FoxEntity.java @@ -31,7 +31,7 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; public class FoxEntity extends AnimalEntity { @@ -55,7 +55,7 @@ public class FoxEntity extends AnimalEntity { } @Override - public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) { - return session.getTagCache().isFoxFood(itemEntry); + public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemMapping mapping) { + return session.getTagCache().isFoxFood(mapping); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/HoglinEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/HoglinEntity.java index 492ff68a8..d782dc53e 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/HoglinEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/HoglinEntity.java @@ -30,7 +30,7 @@ import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; import org.geysermc.connector.utils.DimensionUtils; public class HoglinEntity extends AnimalEntity { @@ -57,7 +57,7 @@ public class HoglinEntity extends AnimalEntity { } @Override - public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) { + public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemMapping mapping) { return javaIdentifierStripped.equals("crimson_fungus"); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/OcelotEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/OcelotEntity.java index 48a5e08bf..98e7140cd 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/OcelotEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/OcelotEntity.java @@ -30,7 +30,7 @@ import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; public class OcelotEntity extends AnimalEntity { @@ -47,7 +47,7 @@ public class OcelotEntity extends AnimalEntity { } @Override - public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) { + public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemMapping mapping) { return javaIdentifierStripped.equals("cod") || javaIdentifierStripped.equals("salmon"); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/PandaEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/PandaEntity.java index 83f0ed8d9..39049d91a 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/PandaEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/PandaEntity.java @@ -33,8 +33,7 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.packet.EntityEventPacket; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; +import org.geysermc.connector.registry.type.ItemMapping; public class PandaEntity extends AnimalEntity { @@ -55,7 +54,7 @@ public class PandaEntity extends AnimalEntity { EntityEventPacket packet = new EntityEventPacket(); packet.setRuntimeEntityId(geyserId); packet.setType(EntityEventType.EATING_ITEM); - packet.setData(ItemRegistry.BAMBOO.getBedrockId() << 16); + packet.setData(session.getItemMappings().getStoredItems().bamboo().getBedrockId() << 16); session.sendUpstreamPacket(packet); } } @@ -81,7 +80,7 @@ public class PandaEntity extends AnimalEntity { } @Override - public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) { + public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemMapping mapping) { return javaIdentifierStripped.equals("bamboo"); } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/PigEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/PigEntity.java index bc07472ea..ba6bfd553 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/PigEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/PigEntity.java @@ -30,7 +30,7 @@ import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; public class PigEntity extends AnimalEntity { @@ -47,7 +47,7 @@ public class PigEntity extends AnimalEntity { } @Override - public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) { + public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemMapping mapping) { return javaIdentifierStripped.equals("carrot") || javaIdentifierStripped.equals("potato") || javaIdentifierStripped.equals("beetroot"); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/PolarBearEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/PolarBearEntity.java index 8f292411d..893def315 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/PolarBearEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/PolarBearEntity.java @@ -30,7 +30,7 @@ import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; public class PolarBearEntity extends AnimalEntity { @@ -47,7 +47,7 @@ public class PolarBearEntity extends AnimalEntity { } @Override - public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) { + public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemMapping mapping) { return false; } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/RabbitEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/RabbitEntity.java index 41579d6a6..0f0e1fb3e 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/RabbitEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/RabbitEntity.java @@ -31,7 +31,7 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; public class RabbitEntity extends AnimalEntity { @@ -65,7 +65,7 @@ public class RabbitEntity extends AnimalEntity { } @Override - public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) { + public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemMapping mapping) { return javaIdentifierStripped.equals("dandelion") || javaIdentifierStripped.equals("carrot") || javaIdentifierStripped.equals("golden_carrot"); } } \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/StriderEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/StriderEntity.java index 437f60cb4..83c1e3674 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/StriderEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/StriderEntity.java @@ -31,7 +31,7 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; public class StriderEntity extends AnimalEntity { @@ -93,7 +93,7 @@ public class StriderEntity extends AnimalEntity { } @Override - public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) { + public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemMapping mapping) { return javaIdentifierStripped.equals("warped_fungus"); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/TurtleEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/TurtleEntity.java index 7e9e3260d..b26b21ee2 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/TurtleEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/TurtleEntity.java @@ -30,7 +30,7 @@ import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; public class TurtleEntity extends AnimalEntity { @@ -49,7 +49,7 @@ public class TurtleEntity extends AnimalEntity { } @Override - public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) { + public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemMapping mapping) { return javaIdentifierStripped.equals("seagrass"); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/AbstractHorseEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/AbstractHorseEntity.java index d4aed4196..e255d2856 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/AbstractHorseEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/AbstractHorseEntity.java @@ -38,8 +38,7 @@ import org.geysermc.connector.entity.attribute.GeyserAttributeType; import org.geysermc.connector.entity.living.animal.AnimalEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; +import org.geysermc.connector.registry.type.ItemMapping; import java.util.Set; @@ -105,7 +104,7 @@ public class AbstractHorseEntity extends AnimalEntity { EntityEventPacket entityEventPacket = new EntityEventPacket(); entityEventPacket.setRuntimeEntityId(geyserId); entityEventPacket.setType(EntityEventType.EATING_ITEM); - entityEventPacket.setData(ItemRegistry.WHEAT.getBedrockId() << 16); + entityEventPacket.setData(session.getItemMappings().getStoredItems().wheat().getBedrockId() << 16); session.sendUpstreamPacket(entityEventPacket); } @@ -120,7 +119,7 @@ public class AbstractHorseEntity extends AnimalEntity { } @Override - public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) { + public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemMapping mapping) { return DONKEY_AND_HORSE_FOODS.contains(javaIdentifierStripped); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/LlamaEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/LlamaEntity.java index 67e3304d3..14e625c81 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/LlamaEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/LlamaEntity.java @@ -32,8 +32,7 @@ import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.MobArmorEquipmentPacket; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; +import org.geysermc.connector.registry.type.ItemMapping; public class LlamaEntity extends ChestedHorseEntity { @@ -59,7 +58,7 @@ public class LlamaEntity extends ChestedHorseEntity { if (carpetIndex > -1 && carpetIndex <= 15) { // The damage value is the dye color that Java sends us, for pre-1.16.220 // The item is always going to be a carpet - equipmentPacket.setChestplate(ItemRegistry.CARPETS.get(carpetIndex)); + equipmentPacket.setChestplate(session.getItemMappings().getCarpets().get(carpetIndex)); } else { equipmentPacket.setChestplate(ItemData.AIR); } @@ -78,7 +77,7 @@ public class LlamaEntity extends ChestedHorseEntity { } @Override - public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) { + public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemMapping mapping) { return javaIdentifierStripped.equals("wheat") || javaIdentifierStripped.equals("hay_block"); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/CatEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/CatEntity.java index ac4142988..904f563f9 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/CatEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/CatEntity.java @@ -31,7 +31,7 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; public class CatEntity extends TameableEntity { @@ -91,7 +91,7 @@ public class CatEntity extends TameableEntity { } @Override - public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) { + public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemMapping mapping) { return javaIdentifierStripped.equals("cod") || javaIdentifierStripped.equals("salmon"); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/ParrotEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/ParrotEntity.java index dcc9d6f78..1bb75931e 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/ParrotEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/ParrotEntity.java @@ -30,7 +30,7 @@ import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; public class ParrotEntity extends TameableEntity { @@ -48,7 +48,7 @@ public class ParrotEntity extends TameableEntity { } @Override - public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) { + public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemMapping mapping) { return javaIdentifierStripped.contains("seeds") || javaIdentifierStripped.equals("cookie"); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/WolfEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/WolfEntity.java index 0a5d2a58c..183719dbb 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/WolfEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/WolfEntity.java @@ -32,7 +32,7 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; import java.util.Set; @@ -88,7 +88,7 @@ public class WolfEntity extends TameableEntity { } @Override - public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) { + public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemMapping mapping) { // Cannot be a baby to eat these foods return WOLF_FOODS.contains(javaIdentifierStripped) && !metadata.getFlags().getFlag(EntityFlag.BABY); } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/merchant/VillagerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/merchant/VillagerEntity.java index 1ba8b595b..3c94f9de2 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/merchant/VillagerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/merchant/VillagerEntity.java @@ -36,7 +36,7 @@ import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.registry.BlockRegistries; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -114,7 +114,7 @@ public class VillagerEntity extends AbstractMerchantEntity { if (bedPosition != null) { bedId = session.getConnector().getWorldManager().getBlockAt(session, bedPosition); } - String bedRotationZ = BlockTranslator.getJavaIdBlockMap().inverse().get(bedId); + String bedRotationZ = BlockRegistries.JAVA_IDENTIFIERS.get().inverse().get(bedId); setRotation(rotation); setOnGround(isOnGround); this.position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ); diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/EnderDragonEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/EnderDragonEntity.java index 8e9dca997..d3d6e30d5 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/EnderDragonEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/EnderDragonEntity.java @@ -27,7 +27,6 @@ package org.geysermc.connector.entity.living.monster; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.AttributeData; import com.nukkitx.protocol.bedrock.data.LevelEventType; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityEventType; @@ -35,7 +34,6 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.packet.*; import lombok.Data; import org.geysermc.connector.entity.Tickable; -import org.geysermc.connector.entity.attribute.GeyserAttributeType; import org.geysermc.connector.entity.living.InsentientEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/EndermanEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/EndermanEntity.java index f11e57a8f..e187d7f0b 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/EndermanEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/EndermanEntity.java @@ -44,7 +44,7 @@ public class EndermanEntity extends MonsterEntity { public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { // Held block if (entityMetadata.getId() == 16) { - metadata.put(EntityData.CARRIED_BLOCK, session.getBlockTranslator().getBedrockBlockId((int) entityMetadata.getValue())); + metadata.put(EntityData.CARRIED_BLOCK, session.getBlockMappings().getBedrockBlockId((int) entityMetadata.getValue())); } // "Is screaming" - controls sound if (entityMetadata.getId() == 17) { diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/PiglinEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/PiglinEntity.java index 5b1ccd342..860f6dfd3 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/PiglinEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/PiglinEntity.java @@ -31,7 +31,6 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemRegistry; public class PiglinEntity extends BasePiglinEntity { @@ -61,7 +60,7 @@ public class PiglinEntity extends BasePiglinEntity { @Override public void updateOffHand(GeyserSession session) { // Check if the Piglin is holding Gold and set the ADMIRING flag accordingly so its pose updates - boolean changed = metadata.getFlags().setFlag(EntityFlag.ADMIRING, session.getTagCache().shouldPiglinAdmire(ItemRegistry.getItem(this.offHand))); + boolean changed = metadata.getFlags().setFlag(EntityFlag.ADMIRING, session.getTagCache().shouldPiglinAdmire(session.getItemMappings().getMapping(this.offHand))); if (changed) { super.updateBedrockMetadata(session); } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/PillagerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/PillagerEntity.java index 73794586f..325cac7ab 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/PillagerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/PillagerEntity.java @@ -29,7 +29,7 @@ import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemRegistry; +import org.geysermc.connector.registry.type.ItemMapping; public class PillagerEntity extends AbstractIllagerEntity { @@ -55,8 +55,9 @@ public class PillagerEntity extends AbstractIllagerEntity { * Check for a crossbow in either the mainhand or offhand. If one exists, indicate that the pillager should be posing */ protected void checkForCrossbow(GeyserSession session) { - boolean hasCrossbow = this.hand.getId() == ItemRegistry.CROSSBOW.getBedrockId() - || this.offHand.getId() == ItemRegistry.CROSSBOW.getBedrockId(); + ItemMapping crossbow = session.getItemMappings().getStoredItems().crossbow(); + boolean hasCrossbow = this.hand.getId() == crossbow.getBedrockId() + || this.offHand.getId() == crossbow.getBedrockId(); boolean usingItemChanged = metadata.getFlags().setFlag(EntityFlag.USING_ITEM, hasCrossbow); boolean chargedChanged = metadata.getFlags().setFlag(EntityFlag.CHARGED, hasCrossbow); diff --git a/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java b/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java index 1cfd425d9..b80757fbd 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java @@ -30,9 +30,8 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import lombok.Data; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemTranslator; +import org.geysermc.connector.registry.type.ItemMapping; @Data public class GeyserItemStack { @@ -105,8 +104,8 @@ public class GeyserItemStack { return itemData; } - public ItemEntry getItemEntry() { - return ItemRegistry.ITEM_ENTRIES.get(getJavaId()); + public ItemMapping getMapping(GeyserSession session) { + return session.getItemMappings().getMapping(this.javaId); } public boolean isEmpty() { diff --git a/connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java b/connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java index 84fc449e9..0be6eefae 100644 --- a/connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java +++ b/connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java @@ -27,6 +27,7 @@ package org.geysermc.connector.network; import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.v440.Bedrock_v440; +import com.nukkitx.protocol.bedrock.v448.Bedrock_v448; import java.util.ArrayList; import java.util.List; @@ -47,6 +48,7 @@ public class BedrockProtocol { static { SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v448.V448_CODEC); } /** diff --git a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java index be34ca81b..159924541 100644 --- a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java @@ -35,8 +35,8 @@ import org.geysermc.connector.common.AuthType; import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslatorRegistry; -import org.geysermc.connector.network.translators.item.ItemRegistry; -import org.geysermc.connector.network.translators.world.block.BlockTranslator1_17_0; +import org.geysermc.connector.registry.BlockRegistries; +import org.geysermc.connector.registry.Registries; import org.geysermc.connector.utils.*; import java.io.FileInputStream; @@ -71,7 +71,8 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { session.getUpstream().getSession().setPacketCodec(packetCodec); // Set the block translation based off of version - session.setBlockTranslator(BlockTranslator1_17_0.INSTANCE); + session.setBlockMappings(BlockRegistries.BLOCKS.forVersion(loginPacket.getProtocolVersion())); + session.setItemMappings(Registries.ITEMS.forVersion(loginPacket.getProtocolVersion())); LoginEncryptionUtils.encryptPlayerConnection(connector, session, loginPacket); @@ -131,7 +132,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { stackPacket.getResourcePacks().add(new ResourcePackStackPacket.Entry(header.getUuid().toString(), header.getVersionString(), "")); } - if (ItemRegistry.FURNACE_MINECART_DATA != null) { + if (session.getItemMappings().getFurnaceMinecartData() != null) { // Allow custom items to work stackPacket.getExperiments().add(new ExperimentData("data_driven_items", true)); } @@ -194,6 +195,8 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { titlePacket.setFadeInTime(0); titlePacket.setFadeOutTime(1); titlePacket.setStayTime(2); + titlePacket.setXuid(""); + titlePacket.setPlatformOnlineId(""); session.sendUpstreamPacket(titlePacket); } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 8c5455d1e..512f248ac 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -86,14 +86,13 @@ import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.auth.AuthData; import org.geysermc.connector.network.session.auth.BedrockClientData; import org.geysermc.connector.network.session.cache.*; -import org.geysermc.connector.network.translators.BiomeTranslator; -import org.geysermc.connector.network.translators.EntityIdentifierRegistry; import org.geysermc.connector.network.translators.PacketTranslatorRegistry; import org.geysermc.connector.network.translators.chat.MessageTranslator; import org.geysermc.connector.network.translators.collision.CollisionManager; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; -import org.geysermc.connector.network.translators.item.ItemRegistry; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.registry.Registries; +import org.geysermc.connector.registry.type.BlockMappings; +import org.geysermc.connector.registry.type.ItemMappings; import org.geysermc.connector.skin.FloodgateSkinUploader; import org.geysermc.connector.skin.SkinManager; import org.geysermc.connector.utils.*; @@ -175,10 +174,16 @@ public class GeyserSession implements CommandSender { private final CollisionManager collisionManager; /** - * Stores the block translations for this specific version. + * Stores the block mappings for this specific version. */ @Setter - private BlockTranslator blockTranslator; + private BlockMappings blockMappings; + + /** + * Stores the item translations for this specific version. + */ + @Setter + private ItemMappings itemMappings; private final Map skullCache = new ConcurrentHashMap<>(); private final Long2ObjectMap storedMaps = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>()); @@ -487,26 +492,26 @@ public class GeyserSession implements CommandSender { this.remoteAuthType = connector.getDefaultAuthType(); // Set the hardcoded shield ID to the ID we just defined in StartGamePacket - upstream.getSession().getHardcodedBlockingId().set(ItemRegistry.SHIELD.getBedrockId()); + upstream.getSession().getHardcodedBlockingId().set(this.itemMappings.getStoredItems().shield().getBedrockId()); - if (ItemRegistry.FURNACE_MINECART_DATA != null) { + if (this.itemMappings.getFurnaceMinecartData() != null) { ItemComponentPacket componentPacket = new ItemComponentPacket(); - componentPacket.getItems().add(ItemRegistry.FURNACE_MINECART_DATA); + componentPacket.getItems().add(this.itemMappings.getFurnaceMinecartData()); upstream.sendPacket(componentPacket); } ChunkUtils.sendEmptyChunks(this, playerEntity.getPosition().toInt(), 0, false); BiomeDefinitionListPacket biomeDefinitionListPacket = new BiomeDefinitionListPacket(); - biomeDefinitionListPacket.setDefinitions(BiomeTranslator.BIOMES); + biomeDefinitionListPacket.setDefinitions(Registries.BIOMES.get()); upstream.sendPacket(biomeDefinitionListPacket); AvailableEntityIdentifiersPacket entityPacket = new AvailableEntityIdentifiersPacket(); - entityPacket.setIdentifiers(EntityIdentifierRegistry.ENTITY_IDENTIFIERS); + entityPacket.setIdentifiers(Registries.ENTITY_IDENTIFIERS.get()); upstream.sendPacket(entityPacket); CreativeContentPacket creativePacket = new CreativeContentPacket(); - creativePacket.setContents(ItemRegistry.CREATIVE_ITEMS); + creativePacket.setContents(this.itemMappings.getCreativeItems()); upstream.sendPacket(creativePacket); PlayStatusPacket playStatusPacket = new PlayStatusPacket(); @@ -1054,7 +1059,7 @@ public class GeyserSession implements CommandSender { // startGamePacket.setCurrentTick(0); startGamePacket.setEnchantmentSeed(0); startGamePacket.setMultiplayerCorrelationId(""); - startGamePacket.setItemEntries(ItemRegistry.ITEMS); + startGamePacket.setItemEntries(this.itemMappings.getItemEntries()); startGamePacket.setVanillaVersion("*"); startGamePacket.setInventoriesServerAuthoritative(true); startGamePacket.setServerEngine(""); // Do we want to fill this in? diff --git a/connector/src/main/java/org/geysermc/connector/network/session/UpstreamSession.java b/connector/src/main/java/org/geysermc/connector/network/session/UpstreamSession.java index f973574b0..11df3139c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/UpstreamSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/UpstreamSession.java @@ -63,4 +63,13 @@ public class UpstreamSession { public InetSocketAddress getAddress() { return session.getRealAddress(); } + + /** + * Gets the session's protocol version. + * + * @return the session's protocol version. + */ + public int getProtocolVersion() { + return this.session.getPacketCodec().getProtocolVersion(); + } } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/BookEditCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/BookEditCache.java index cb3737895..d2ee8f552 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/BookEditCache.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/BookEditCache.java @@ -29,7 +29,6 @@ import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientEditB import lombok.Setter; import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemRegistry; /** * Manages updating the current writable book. @@ -64,7 +63,7 @@ public class BookEditCache { } // Don't send the update if the player isn't not holding a book, shouldn't happen if we catch all interactions GeyserItemStack itemStack = session.getPlayerInventory().getItemInHand(); - if (itemStack == null || itemStack.getJavaId() != ItemRegistry.WRITABLE_BOOK.getJavaId()) { + if (itemStack == null || itemStack.getJavaId() != this.session.getItemMappings().getStoredItems().writableBook().getJavaId()) { packet = null; return; } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/ChunkCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/ChunkCache.java index 4f93b0f53..72d271a79 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/ChunkCache.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/ChunkCache.java @@ -31,7 +31,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import lombok.Setter; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.world.block.BlockStateValues; import org.geysermc.connector.network.translators.world.chunk.GeyserColumn; import org.geysermc.connector.utils.MathUtils; @@ -81,11 +81,11 @@ public class ChunkCache { Chunk chunk = column.getChunks()[(y >> 4) - getChunkMinY()]; if (chunk == null) { - if (block != BlockTranslator.JAVA_AIR_ID) { + if (block != BlockStateValues.JAVA_AIR_ID) { // A previously empty chunk, which is no longer empty as a block has been added to it chunk = new Chunk(); // Fixes the chunk assuming that all blocks is the `block` variable we are updating. /shrug - chunk.getPalette().stateToId(BlockTranslator.JAVA_AIR_ID); + chunk.getPalette().stateToId(BlockStateValues.JAVA_AIR_ID); column.getChunks()[(y >> 4) - getChunkMinY()] = chunk; } else { // Nothing to update @@ -98,17 +98,17 @@ public class ChunkCache { public int getBlockAt(int x, int y, int z) { if (!cache) { - return BlockTranslator.JAVA_AIR_ID; + return BlockStateValues.JAVA_AIR_ID; } GeyserColumn column = this.getChunk(x >> 4, z >> 4); if (column == null) { - return BlockTranslator.JAVA_AIR_ID; + return BlockStateValues.JAVA_AIR_ID; } if (y < minY || (y >> 4) > column.getChunks().length - 1) { // Y likely goes above or below the height limit of this world - return BlockTranslator.JAVA_AIR_ID; + return BlockStateValues.JAVA_AIR_ID; } Chunk chunk = column.getChunks()[(y >> 4) - getChunkMinY()]; @@ -116,7 +116,7 @@ public class ChunkCache { return chunk.get(x & 0xF, y & 0xF, z & 0xF); } - return BlockTranslator.JAVA_AIR_ID; + return BlockStateValues.JAVA_AIR_ID; } public void removeChunk(int chunkX, int chunkZ) { diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/TagCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/TagCache.java index b1427a864..e10e4dad5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/TagCache.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/TagCache.java @@ -28,8 +28,8 @@ package org.geysermc.connector.network.session.cache; import com.github.steveice10.mc.protocol.packet.ingame.server.ServerDeclareTagsPacket; import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntLists; -import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.registry.type.BlockMapping; +import org.geysermc.connector.registry.type.ItemMapping; import java.util.Map; @@ -99,16 +99,16 @@ public class TagCache { this.piglinLoved = IntLists.emptyList(); } - public boolean isFlower(ItemEntry itemEntry) { - return flowers.contains(itemEntry.getJavaId()); + public boolean isFlower(ItemMapping mapping) { + return flowers.contains(mapping.getJavaId()); } - public boolean isFoxFood(ItemEntry itemEntry) { - return foxFood.contains(itemEntry.getJavaId()); + public boolean isFoxFood(ItemMapping mapping) { + return foxFood.contains(mapping.getJavaId()); } - public boolean shouldPiglinAdmire(ItemEntry itemEntry) { - return piglinLoved.contains(itemEntry.getJavaId()); + public boolean shouldPiglinAdmire(ItemMapping mapping) { + return piglinLoved.contains(mapping.getJavaId()); } public boolean isAxeEffective(BlockMapping blockMapping) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestTranslator.java index 493789bbb..3a3a4bbed 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestTranslator.java @@ -32,7 +32,8 @@ import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.world.block.BlockStateValues; +import org.geysermc.connector.registry.BlockRegistries; import org.geysermc.connector.utils.InventoryUtils; @Translator(packet = BlockPickRequestPacket.class) @@ -44,7 +45,7 @@ public class BedrockBlockPickRequestTranslator extends PacketTranslator= 2 && session.getGameMode() == GameMode.CREATIVE) { // Otherwise insufficient permissions - int blockState = session.getBlockTranslator().getJavaBlockState(packet.getBlockRuntimeId()); - String blockName = BlockTranslator.getJavaIdBlockMap().inverse().getOrDefault(blockState, ""); + int blockState = session.getBlockMappings().getJavaBlockState(packet.getBlockRuntimeId()); + String blockName = BlockRegistries.JAVA_IDENTIFIERS.get().inverse().getOrDefault(blockState, ""); // In the future this can be used for structure blocks too, however not all elements // are available in each GUI if (blockName.contains("jigsaw")) { @@ -243,7 +246,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator switch (packet.getAction()) { case INTERACT: - if (session.getPlayerInventory().getItemInHand().getJavaId() == ItemRegistry.SHIELD.getJavaId()) { + if (session.getPlayerInventory().getItemInHand().getJavaId() == session.getItemMappings().getStoredItems().shield().getJavaId()) { break; } ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(), diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/collision/CollisionManager.java b/connector/src/main/java/org/geysermc/connector/network/translators/collision/CollisionManager.java index b6d0ae176..ceb528650 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/collision/CollisionManager.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/collision/CollisionManager.java @@ -39,7 +39,8 @@ import org.geysermc.connector.entity.player.PlayerEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.collision.translators.BlockCollision; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.world.block.BlockStateValues; +import org.geysermc.connector.utils.BlockUtils; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; @@ -228,7 +229,7 @@ public class CollisionManager { // Used when correction code needs to be run before the main correction for (Vector3i blockPos : collidableBlocks) { - BlockCollision blockCollision = CollisionTranslator.getCollisionAt( + BlockCollision blockCollision = BlockUtils.getCollisionAt( session, blockPos.getX(), blockPos.getY(), blockPos.getZ() ); if (blockCollision != null) { @@ -238,7 +239,7 @@ public class CollisionManager { // Main correction code for (Vector3i blockPos : collidableBlocks) { - BlockCollision blockCollision = CollisionTranslator.getCollisionAt( + BlockCollision blockCollision = BlockUtils.getCollisionAt( session, blockPos.getX(), blockPos.getY(), blockPos.getZ() ); if (blockCollision != null) { @@ -259,7 +260,7 @@ public class CollisionManager { */ public boolean isUnderSlab() { Vector3i position = session.getPlayerEntity().getPosition().toInt(); - BlockCollision collision = CollisionTranslator.getCollisionAt(session, position.getX(), position.getY(), position.getZ()); + BlockCollision collision = BlockUtils.getCollisionAt(session, position.getX(), position.getY(), position.getZ()); if (collision != null) { // Determine, if the player's bounding box *were* at full height, if it would intersect with the block // at the current location. @@ -275,7 +276,7 @@ public class CollisionManager { * @return if the player is currently in a water block */ public boolean isPlayerInWater() { - return session.getConnector().getWorldManager().getBlockAt(session, session.getPlayerEntity().getPosition().toInt()) == BlockTranslator.JAVA_WATER_ID; + return session.getConnector().getWorldManager().getBlockAt(session, session.getPlayerEntity().getPosition().toInt()) == BlockStateValues.JAVA_WATER_ID; } /** diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/effect/EffectRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/effect/EffectRegistry.java deleted file mode 100644 index 91b21fb2a..000000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/effect/EffectRegistry.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (c) 2019-2021 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.connector.network.translators.effect; - -import com.fasterxml.jackson.databind.JsonNode; -import com.github.steveice10.mc.protocol.data.game.world.effect.SoundEffect; -import com.github.steveice10.mc.protocol.data.game.world.particle.ParticleType; -import com.nukkitx.protocol.bedrock.data.LevelEventType; -import com.nukkitx.protocol.bedrock.data.SoundEvent; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import lombok.NonNull; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.utils.FileUtils; - -import java.io.InputStream; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -/** - * Registry for particles and effects. - */ -public class EffectRegistry { - - public static final Map SOUND_EFFECTS = new HashMap<>(); - public static final Int2ObjectMap RECORDS = new Int2ObjectOpenHashMap<>(); - - /** - * Java particle type to Bedrock level event - */ - private static final Map PARTICLE_TO_LEVEL_EVENT = new HashMap<>(); - /** - * Java particle type to Bedrock namespaced string ID - */ - private static final Map PARTICLE_TO_STRING = new HashMap<>(); - - public static void init() { - // no-op - } - - static { - /* Load particles */ - InputStream particleStream = FileUtils.getResource("mappings/particles.json"); - JsonNode particleEntries; - try { - particleEntries = GeyserConnector.JSON_MAPPER.readTree(particleStream); - } catch (Exception e) { - throw new AssertionError("Unable to load particle map", e); - } - - Iterator> particlesIterator = particleEntries.fields(); - try { - while (particlesIterator.hasNext()) { - Map.Entry entry = particlesIterator.next(); - JsonNode bedrockId = entry.getValue().get("bedrockId"); - JsonNode eventType = entry.getValue().get("eventType"); - if (bedrockId != null) { - PARTICLE_TO_STRING.put(ParticleType.valueOf(entry.getKey().toUpperCase()), bedrockId.asText()); - } - if (eventType != null) { - PARTICLE_TO_LEVEL_EVENT.put(ParticleType.valueOf(entry.getKey().toUpperCase()), LevelEventType.valueOf(eventType.asText().toUpperCase())); - } - } - } catch (Exception e) { - e.printStackTrace(); - } - - /* Load effects */ - InputStream effectsStream = FileUtils.getResource("mappings/effects.json"); - JsonNode effects; - try { - effects = GeyserConnector.JSON_MAPPER.readTree(effectsStream); - } catch (Exception e) { - throw new AssertionError("Unable to load effects mappings", e); - } - - Iterator> effectsIterator = effects.fields(); - while (effectsIterator.hasNext()) { - Map.Entry entry = effectsIterator.next(); - JsonNode node = entry.getValue(); - try { - String type = node.get("type").asText(); - SoundEffect javaEffect = null; - Effect effect = null; - switch (type) { - case "soundLevel": { - javaEffect = SoundEffect.valueOf(entry.getKey()); - LevelEventType levelEventType = LevelEventType.valueOf(node.get("name").asText()); - int data = node.has("data") ? node.get("data").intValue() : 0; - effect = new SoundLevelEffect(levelEventType, data); - break; - } - case "soundEvent": { - javaEffect = SoundEffect.valueOf(entry.getKey()); - SoundEvent soundEvent = SoundEvent.valueOf(node.get("name").asText()); - String identifier = node.has("identifier") ? node.get("identifier").asText() : ""; - int extraData = node.has("extraData") ? node.get("extraData").intValue() : -1; - effect = new SoundEventEffect(soundEvent, identifier, extraData); - break; - } - case "playSound": { - javaEffect = SoundEffect.valueOf(entry.getKey()); - String name = node.get("name").asText(); - float volume = node.has("volume") ? node.get("volume").floatValue() : 1.0f; - boolean pitchSub = node.has("pitch_sub") && node.get("pitch_sub").booleanValue(); - float pitchMul = node.has("pitch_mul") ? node.get("pitch_mul").floatValue() : 1.0f; - float pitchAdd = node.has("pitch_add") ? node.get("pitch_add").floatValue() : 0.0f; - boolean relative = node.has("relative") && node.get("relative").booleanValue(); - effect = new PlaySoundEffect(name, volume, pitchSub, pitchMul, pitchAdd, relative); - break; - } - case "record": { - // Special case handled in ItemRegistry - break; - } - } - if (javaEffect != null) { - SOUND_EFFECTS.put(javaEffect, effect); - } - } catch (Exception e) { - GeyserConnector.getInstance().getLogger().warning("Failed to map sound effect " + entry.getKey() + " : " + e.toString()); - } - } - } - - /** - * Used for area effect clouds. - * - * @param type the Java particle to search for - * @return the Bedrock integer ID of the particle, or -1 if it does not exist - */ - public static int getParticleId(GeyserSession session, @NonNull ParticleType type) { - LevelEventType levelEventType = getParticleLevelEventType(type); - if (levelEventType == null) { - return -1; - } - - // Remove the legacy bit applied to particles for LevelEventType serialization - return session.getUpstream().getSession().getPacketCodec().getHelper().getLevelEventId(levelEventType) & ~0x4000; - } - - /** - * @param type the Java particle to search for - * @return the level event equivalent Bedrock particle - */ - public static LevelEventType getParticleLevelEventType(@NonNull ParticleType type) { - return PARTICLE_TO_LEVEL_EVENT.getOrDefault(type, null); - } - - /** - * @param type the Java particle to search for - * @return the namespaced ID equivalent for Bedrock - */ - public static String getParticleString(@NonNull ParticleType type) { - return PARTICLE_TO_STRING.getOrDefault(type, null); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index c8af7f38f..2ca80041b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -843,7 +843,7 @@ public abstract class InventoryTranslator { for (int slot : affectedSlots) { BedrockContainerSlot bedrockSlot = javaSlotToBedrockContainer(slot); List list = containerMap.computeIfAbsent(bedrockSlot.getContainer(), k -> new ArrayList<>()); - list.add(makeItemEntry(bedrockSlot.getSlot(), inventory.getItem(slot))); + list.add(makeItemEntry(session, bedrockSlot.getSlot(), inventory.getItem(slot))); } List containerEntries = new ArrayList<>(); @@ -851,13 +851,13 @@ public abstract class InventoryTranslator { containerEntries.add(new ItemStackResponsePacket.ContainerEntry(entry.getKey(), entry.getValue())); } - ItemStackResponsePacket.ItemEntry cursorEntry = makeItemEntry(0, session.getPlayerInventory().getCursor()); + ItemStackResponsePacket.ItemEntry cursorEntry = makeItemEntry(session, 0, session.getPlayerInventory().getCursor()); containerEntries.add(new ItemStackResponsePacket.ContainerEntry(ContainerSlotType.CURSOR, Collections.singletonList(cursorEntry))); return containerEntries; } - public static ItemStackResponsePacket.ItemEntry makeItemEntry(int bedrockSlot, GeyserItemStack itemStack) { + public static ItemStackResponsePacket.ItemEntry makeItemEntry(GeyserSession session, int bedrockSlot, GeyserItemStack itemStack) { ItemStackResponsePacket.ItemEntry itemEntry; if (!itemStack.isEmpty()) { // As of 1.16.210: Bedrock needs confirmation on what the current item durability is. @@ -866,7 +866,7 @@ public abstract class InventoryTranslator { if (itemStack.getNbt() != null) { Tag damage = itemStack.getNbt().get("Damage"); if (damage instanceof IntTag) { - durability = ItemUtils.getCorrectBedrockDurability(itemStack.getJavaId(), ((IntTag) damage).getValue()); + durability = ItemUtils.getCorrectBedrockDurability(session, itemStack.getJavaId(), ((IntTag) damage).getValue()); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java index b7f67879b..bb633780a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java @@ -38,7 +38,7 @@ import org.geysermc.connector.inventory.Container; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.registry.BlockRegistries; import java.util.Collections; import java.util.HashSet; @@ -57,7 +57,7 @@ public class BlockInventoryHolder extends InventoryHolder { private final Set validBlocks; public BlockInventoryHolder(String javaBlockIdentifier, ContainerType containerType, String... validBlocks) { - this.defaultJavaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier); + this.defaultJavaBlockState = BlockRegistries.JAVA_IDENTIFIERS.get(javaBlockIdentifier); this.containerType = containerType; if (validBlocks != null) { Set validBlocksTemp = new HashSet<>(validBlocks.length + 1); @@ -77,7 +77,7 @@ public class BlockInventoryHolder extends InventoryHolder { if (checkInteractionPosition(session)) { // Then, check to see if the interacted block is valid for this inventory by ensuring the block state identifier is valid int javaBlockId = session.getConnector().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition()); - String[] javaBlockString = BlockTranslator.getJavaIdBlockMap().inverse().getOrDefault(javaBlockId, "minecraft:air").split("\\["); + String[] javaBlockString = BlockRegistries.JAVA_IDENTIFIERS.get().inverse().getOrDefault(javaBlockId, "minecraft:air").split("\\["); if (isValidBlock(javaBlockString)) { // We can safely use this block inventory.setHolderPosition(session.getLastInteractionBlockPosition()); @@ -93,7 +93,7 @@ public class BlockInventoryHolder extends InventoryHolder { UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(position); - blockPacket.setRuntimeId(session.getBlockTranslator().getBedrockBlockId(defaultJavaBlockState)); + blockPacket.setRuntimeId(session.getBlockMappings().getBedrockBlockId(defaultJavaBlockState)); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); inventory.setHolderPosition(position); @@ -158,7 +158,7 @@ public class BlockInventoryHolder extends InventoryHolder { UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(holderPos); - blockPacket.setRuntimeId(session.getBlockTranslator().getBedrockBlockId(realBlock)); + blockPacket.setRuntimeId(session.getBlockMappings().getBedrockBlockId(realBlock)); blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CartographyInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CartographyInventoryTranslator.java index a3b50dace..76bf21bd3 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CartographyInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/CartographyInventoryTranslator.java @@ -48,11 +48,11 @@ public class CartographyInventoryTranslator extends AbstractBlockInventoryTransl if (javaDestinationSlot == 0) { // Bedrock Edition can use paper or an empty map in slot 0 GeyserItemStack itemStack = javaSourceSlot == -1 ? session.getPlayerInventory().getCursor() : inventory.getItem(javaSourceSlot); - return itemStack.getItemEntry().getJavaIdentifier().equals("minecraft:paper") || itemStack.getItemEntry().getJavaIdentifier().equals("minecraft:map"); + return itemStack.getMapping(session).getJavaIdentifier().equals("minecraft:paper") || itemStack.getMapping(session).getJavaIdentifier().equals("minecraft:map"); } else if (javaDestinationSlot == 1) { // Bedrock Edition can use a compass to create locator maps, or use a filled map, in the ADDITIONAL slot GeyserItemStack itemStack = javaSourceSlot == -1 ? session.getPlayerInventory().getCursor() : inventory.getItem(javaSourceSlot); - return itemStack.getItemEntry().getJavaIdentifier().equals("minecraft:compass") || itemStack.getItemEntry().getJavaIdentifier().equals("minecraft:filled_map"); + return itemStack.getMapping(session).getJavaIdentifier().equals("minecraft:compass") || itemStack.getMapping(session).getJavaIdentifier().equals("minecraft:filled_map"); } return false; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java index 17c93c15b..ec8f33f2e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/LoomInventoryTranslator.java @@ -112,7 +112,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { } // Reject the item if Bedrock is attempting to put in a dye that is not a dye in Java Edition - return !itemStack.getItemEntry().getJavaIdentifier().endsWith("_dye"); + return !itemStack.getMapping(session).getJavaIdentifier().endsWith("_dye"); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java index e3dbec507..adde2b26f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/PlayerInventoryTranslator.java @@ -43,16 +43,16 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.inventory.SlotType; -import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.utils.InventoryUtils; import org.geysermc.connector.utils.LanguageUtils; import java.util.Arrays; import java.util.Collections; +import java.util.function.IntFunction; public class PlayerInventoryTranslator extends InventoryTranslator { - private static final ItemData UNUSUABLE_CRAFTING_SPACE_BLOCK = InventoryUtils.createUnusableSpaceBlock(LanguageUtils.getLocaleStringLog("geyser.inventory.unusable_item.creative")); + private static final IntFunction UNUSUABLE_CRAFTING_SPACE_BLOCK = InventoryUtils.createUnusableSpaceBlock(LanguageUtils.getLocaleStringLog("geyser.inventory.unusable_item.creative")); public PlayerInventoryTranslator() { super(46); @@ -106,7 +106,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { slotPacket.setSlot(i + 27); if (session.getGameMode() == GameMode.CREATIVE) { - slotPacket.setItem(UNUSUABLE_CRAFTING_SPACE_BLOCK); + slotPacket.setItem(UNUSUABLE_CRAFTING_SPACE_BLOCK.apply(session.getUpstream().getProtocolVersion())); } else { slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i).getItemStack())); } @@ -384,12 +384,13 @@ public class PlayerInventoryTranslator extends InventoryTranslator { craftState = CraftState.RECIPE_ID; int creativeId = creativeAction.getCreativeItemNetworkId() - 1; - if (creativeId < 0 || creativeId >= ItemRegistry.CREATIVE_ITEMS.length) { + ItemData[] creativeItems = session.getItemMappings().getCreativeItems(); + if (creativeId < 0 || creativeId >= creativeItems.length) { return rejectRequest(request); } // Reference the creative items list we send to the client to know what it's asking of us - ItemData creativeItem = ItemRegistry.CREATIVE_ITEMS[creativeId]; - javaCreativeItem = ItemTranslator.translateToJava(creativeItem); + ItemData creativeItem = creativeItems[creativeId]; + javaCreativeItem = ItemTranslator.translateToJava(creativeItem, session.getItemMappings()); break; } case CRAFT_RESULTS_DEPRECATED: { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/ShulkerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/ShulkerInventoryTranslator.java index 76d1cb1cf..4f28d0e4e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/ShulkerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/ShulkerInventoryTranslator.java @@ -37,11 +37,12 @@ import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder; import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator; +import org.geysermc.connector.registry.Registries; public class ShulkerInventoryTranslator extends AbstractBlockInventoryTranslator { public ShulkerInventoryTranslator() { super(27, new BlockInventoryHolder("minecraft:shulker_box[facing=north]", ContainerType.CONTAINER) { - private final BlockEntityTranslator shulkerBoxTranslator = BlockEntityTranslator.BLOCK_ENTITY_TRANSLATORS.get("ShulkerBox"); + private final BlockEntityTranslator shulkerBoxTranslator = Registries.BLOCK_ENTITIES.get("ShulkerBox"); @Override protected boolean isValidBlock(String[] javaBlockString) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java index 2acce3a9b..e4dea7265 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/StonecutterInventoryTranslator.java @@ -75,7 +75,7 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl return rejectRequest(request); } - ItemStack javaOutput = ItemTranslator.translateToJava(craftData.getResultItems()[0]); + ItemStack javaOutput = ItemTranslator.translateToJava(craftData.getResultItems()[0], session.getItemMappings()); int button = results.indexOf(javaOutput.getId()); // If we've already pressed the button with this item, no need to press it again! if (container.getStonecutterButton() != button) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java index 78ac0b609..a20cca12e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/translators/chest/DoubleChestInventoryTranslator.java @@ -37,16 +37,16 @@ import org.geysermc.connector.inventory.Container; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockStateValues; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.network.translators.world.block.DoubleChestValue; import org.geysermc.connector.network.translators.world.block.entity.DoubleChestBlockEntityTranslator; +import org.geysermc.connector.registry.BlockRegistries; public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { private final int defaultJavaBlockState; public DoubleChestInventoryTranslator(int size) { super(size, 54); - this.defaultJavaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]"); + this.defaultJavaBlockState = BlockRegistries.JAVA_IDENTIFIERS.get("minecraft:chest[facing=north,type=single,waterlogged=false]"); } @Override @@ -54,7 +54,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { // See BlockInventoryHolder - same concept there except we're also dealing with a specific block state if (session.getLastInteractionPlayerPosition().equals(session.getPlayerEntity().getPosition())) { int javaBlockId = session.getConnector().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition()); - String[] javaBlockString = BlockTranslator.getJavaIdBlockMap().inverse().getOrDefault(javaBlockId, "minecraft:air").split("\\["); + String[] javaBlockString = BlockRegistries.JAVA_IDENTIFIERS.get().inverse().getOrDefault(javaBlockId, "minecraft:air").split("\\["); if (javaBlockString.length > 1 && (javaBlockString[0].equals("minecraft:chest") || javaBlockString[0].equals("minecraft:trapped_chest")) && !javaBlockString[1].contains("type=single")) { inventory.setHolderPosition(session.getLastInteractionBlockPosition()); @@ -82,7 +82,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { Vector3i position = session.getPlayerEntity().getPosition().toInt().add(Vector3i.UP); Vector3i pairPosition = position.add(Vector3i.UNIT_X); - int bedrockBlockId = session.getBlockTranslator().getBedrockBlockId(defaultJavaBlockState); + int bedrockBlockId = session.getBlockMappings().getBedrockBlockId(defaultJavaBlockState); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); @@ -154,7 +154,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(holderPos); - blockPacket.setRuntimeId(session.getBlockTranslator().getBedrockBlockId(realBlock)); + blockPacket.setRuntimeId(session.getBlockMappings().getBedrockBlockId(realBlock)); session.sendUpstreamPacket(blockPacket); holderPos = holderPos.add(Vector3i.UNIT_X); @@ -162,7 +162,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(holderPos); - blockPacket.setRuntimeId(session.getBlockTranslator().getBedrockBlockId(realBlock)); + blockPacket.setRuntimeId(session.getBlockMappings().getBedrockBlockId(realBlock)); session.sendUpstreamPacket(blockPacket); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java index f5029f749..b421044bf 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java @@ -37,10 +37,11 @@ import org.geysermc.connector.utils.LanguageUtils; import java.util.ArrayList; import java.util.List; +import java.util.function.IntFunction; @AllArgsConstructor public class ChestInventoryUpdater extends InventoryUpdater { - private static final ItemData UNUSUABLE_SPACE_BLOCK = InventoryUtils.createUnusableSpaceBlock(LanguageUtils.getLocaleStringLog("geyser.inventory.unusable_item.slot")); + private static final IntFunction UNUSUABLE_SPACE_BLOCK = InventoryUtils.createUnusableSpaceBlock(LanguageUtils.getLocaleStringLog("geyser.inventory.unusable_item.slot")); private final int paddedSize; @@ -53,7 +54,7 @@ public class ChestInventoryUpdater extends InventoryUpdater { if (i < translator.size) { bedrockItems.add(inventory.getItem(i).getItemData(session)); } else { - bedrockItems.add(UNUSUABLE_SPACE_BLOCK); + bedrockItems.add(UNUSUABLE_SPACE_BLOCK.apply(session.getUpstream().getProtocolVersion())); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java deleted file mode 100644 index 4d8a50e85..000000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java +++ /dev/null @@ -1,628 +0,0 @@ -/* - * Copyright (c) 2019-2021 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.connector.network.translators.item; - -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.JsonNode; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; -import com.google.common.collect.ImmutableSet; -import com.nukkitx.nbt.NbtMap; -import com.nukkitx.nbt.NbtMapBuilder; -import com.nukkitx.nbt.NbtType; -import com.nukkitx.nbt.NbtUtils; -import com.nukkitx.protocol.bedrock.data.SoundEvent; -import com.nukkitx.protocol.bedrock.data.inventory.ComponentItemData; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; -import com.nukkitx.protocol.bedrock.packet.StartGamePacket; -import it.unimi.dsi.fastutil.ints.*; -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.network.translators.effect.EffectRegistry; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; -import org.geysermc.connector.network.translators.world.block.BlockTranslator1_17_0; -import org.geysermc.connector.utils.FileUtils; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.*; - -/** - * Registry for anything item related. - */ -public class ItemRegistry { - - private static final Map JAVA_IDENTIFIER_MAP = new HashMap<>(); - - /** - * A list of all identifiers that only exist on Java. Used to prevent creative items from becoming these unintentionally. - */ - private static final Set JAVA_ONLY_ITEMS; - - public static final ItemData[] CREATIVE_ITEMS; - - public static final List ITEMS = new ArrayList<>(); - public static final Int2ObjectMap ITEM_ENTRIES = new Int2ObjectOpenHashMap<>(); - - /** - * A list of all Java item names. - */ - public static final String[] ITEM_NAMES; - - /** - * Bamboo item entry, used in PandaEntity.java - */ - public static ItemEntry BAMBOO; - /** - * Banner item entry, used in LivingEntity.java - */ - public static ItemEntry BANNER; - /** - * Boat item entries, used in BedrockInventoryTransactionTranslator.java - */ - public static final IntSet BOATS = new IntArraySet(); - /** - * Bucket item entries (excluding the milk bucket), used in BedrockInventoryTransactionTranslator.java - */ - public static final IntSet BUCKETS = new IntArraySet(); - /** - * Carpet item data, used in LlamaEntity.java - */ - public static final List CARPETS = new ArrayList<>(16); - /** - * Crossbow item entry, used in PillagerEntity.java - */ - public static ItemEntry CROSSBOW; - /** - * Fishing rod item entry, used in ItemUtils.java - */ - public static ItemEntry FISHING_ROD; - /** - * Empty item bucket, used in BedrockInventoryTransactionTranslator.java - */ - public static ItemEntry MILK_BUCKET; - /** - * Egg item entry, used in JavaEntityStatusTranslator.java - */ - public static ItemEntry EGG; - /** - * Shield item entry, used in Entity.java and LivingEntity.java - */ - public static ItemEntry SHIELD; - /** - * A list of all spawn eggs by their Bedrock IDs. Used in BedrockInventoryTransactionTranslator.java - */ - public static final IntSet SPAWN_EGGS = new IntArraySet(); - /** - * Wheat item entry, used in AbstractHorseEntity.java - */ - public static ItemEntry WHEAT; - /** - * Writable book item entry, used in BedrockBookEditTranslator.java - */ - public static ItemEntry WRITABLE_BOOK; - - public static int BARRIER_INDEX = 0; - - /** - * Stores the properties and data of the "custom" furnace minecart item. - */ - public static final ComponentItemData FURNACE_MINECART_DATA; - - public static void init() { - // no-op - } - - static { - /* Load item palette */ - InputStream stream = FileUtils.getResource("bedrock/runtime_item_states.json"); - - TypeReference> itemEntriesType = new TypeReference>() { - }; - - // Used to get the Bedrock namespaced ID (in instances where there are small differences) - Int2ObjectMap bedrockIdToIdentifier = new Int2ObjectOpenHashMap<>(); - - List itemNames = new ArrayList<>(); - - List itemEntries; - try { - itemEntries = GeyserConnector.JSON_MAPPER.readValue(stream, itemEntriesType); - } catch (Exception e) { - throw new AssertionError("Unable to load Bedrock runtime item IDs", e); - } - - int lodestoneCompassId = 0; - - for (JsonNode entry : itemEntries) { - ITEMS.add(new StartGamePacket.ItemEntry(entry.get("name").textValue(), (short) entry.get("id").intValue())); - bedrockIdToIdentifier.put(entry.get("id").intValue(), entry.get("name").textValue()); - if (entry.get("name").textValue().equals("minecraft:lodestone_compass")) { - lodestoneCompassId = entry.get("id").intValue(); - } - } - - Object2IntMap bedrockBlockIdOverrides = new Object2IntOpenHashMap<>(); - Object2IntMap blacklistedIdentifiers = new Object2IntOpenHashMap<>(); - - // Load creative items - // We load this before item mappings to get overridden block runtime ID mappings - stream = FileUtils.getResource("bedrock/creative_items.json"); - - JsonNode creativeItemEntries; - try { - creativeItemEntries = GeyserConnector.JSON_MAPPER.readTree(stream).get("items"); - } catch (Exception e) { - throw new AssertionError("Unable to load creative items", e); - } - - int netId = 1; - List creativeItems = new ArrayList<>(); - for (JsonNode itemNode : creativeItemEntries) { - int count = 1; - int damage = 0; - int blockRuntimeId = 0; - NbtMap tag = null; - JsonNode damageNode = itemNode.get("damage"); - if (damageNode != null) { - damage = damageNode.asInt(); - } - JsonNode countNode = itemNode.get("count"); - if (countNode != null) { - count = countNode.asInt(); - } - JsonNode blockRuntimeIdNode = itemNode.get("blockRuntimeId"); - if (blockRuntimeIdNode != null) { - blockRuntimeId = blockRuntimeIdNode.asInt(); - } - JsonNode nbtNode = itemNode.get("nbt_b64"); - if (nbtNode != null) { - byte[] bytes = Base64.getDecoder().decode(nbtNode.asText()); - ByteArrayInputStream bais = new ByteArrayInputStream(bytes); - try { - tag = (NbtMap) NbtUtils.createReaderLE(bais).readTag(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - String identifier = itemNode.get("id").textValue(); - int id = -1; - for (StartGamePacket.ItemEntry itemEntry : ITEMS) { - if (itemEntry.getIdentifier().equals(identifier)) { - id = itemEntry.getId(); - break; - } - } - if (id == -1) { - throw new RuntimeException("Unable to find matching Bedrock item for " + identifier); - } - - creativeItems.add(ItemData.builder() - .id(id) - .damage(damage) - .count(count) - .blockRuntimeId(blockRuntimeId) - .tag(tag) - .netId(netId++).build()); - - if (blockRuntimeId != 0) { - // Add override for item mapping, unless it already exists... then we know multiple states can exist - if (!blacklistedIdentifiers.containsKey(identifier)) { - if (bedrockBlockIdOverrides.containsKey(identifier)) { - bedrockBlockIdOverrides.remove(identifier); - // Save this as a blacklist, but also as knowledge of what the block state name should be - blacklistedIdentifiers.put(identifier, blockRuntimeId); - } else { - // Unless there's multiple possibilities for this one state, let this be - bedrockBlockIdOverrides.put(identifier, blockRuntimeId); - } - } - } - } - - // Load item mappings from Java Edition to Bedrock Edition - stream = FileUtils.getResource("mappings/items.json"); - - JsonNode items; - try { - items = GeyserConnector.JSON_MAPPER.readTree(stream); - } catch (Exception e) { - throw new AssertionError("Unable to load Java runtime item IDs", e); - } - - BlockTranslator blockTranslator = BlockTranslator1_17_0.INSTANCE; - - int itemIndex = 0; - int javaFurnaceMinecartId = 0; - boolean usingFurnaceMinecart = GeyserConnector.getInstance().getConfig().isAddNonBedrockItems(); - Iterator> iterator = items.fields(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - if (usingFurnaceMinecart && entry.getKey().equals("minecraft:furnace_minecart")) { - javaFurnaceMinecartId = itemIndex; - itemIndex++; - continue; - } - int bedrockId = entry.getValue().get("bedrock_id").intValue(); - String bedrockIdentifier = bedrockIdToIdentifier.get(bedrockId); - if (bedrockIdentifier == null) { - throw new RuntimeException("Missing Bedrock ID in mappings!: " + bedrockId); - } - JsonNode stackSizeNode = entry.getValue().get("stack_size"); - int stackSize = stackSizeNode == null ? 64 : stackSizeNode.intValue(); - - int bedrockBlockId = -1; - JsonNode blockRuntimeIdNode = entry.getValue().get("blockRuntimeId"); - if (blockRuntimeIdNode != null) { - int blockIdOverride = bedrockBlockIdOverrides.getOrDefault(bedrockIdentifier, -1); - if (blockIdOverride != -1) { - // Straight from BDS is our best chance of getting an item that doesn't run into issues - bedrockBlockId = blockIdOverride; - } else { - // Try to get an example block runtime ID from the creative contents packet, for Bedrock identifier obtaining - int aValidBedrockBlockId = blacklistedIdentifiers.getOrDefault(bedrockIdentifier, -1); - if (aValidBedrockBlockId == -1) { - // Fallback - bedrockBlockId = blockTranslator.getBedrockBlockId(blockRuntimeIdNode.intValue()); - } else { - // As of 1.16.220, every item requires a block runtime ID attached to it. - // This is mostly for identifying different blocks with the same item ID - wool, slabs, some walls. - // However, in order for some visuals and crafting to work, we need to send the first matching block state - // as indexed by Bedrock's block palette - // There are exceptions! But, ideally, the block ID override should take care of those. - String javaBlockIdentifier = BlockTranslator.getBlockMapping(blockRuntimeIdNode.intValue()).getCleanJavaIdentifier(); - NbtMapBuilder requiredBlockStatesBuilder = NbtMap.builder(); - String correctBedrockIdentifier = blockTranslator.getAllBedrockBlockStates().get(aValidBedrockBlockId).getString("name"); - boolean firstPass = true; - for (Map.Entry blockEntry : BlockTranslator.getJavaIdBlockMap().entrySet()) { - if (blockEntry.getKey().split("\\[")[0].equals(javaBlockIdentifier)) { - int bedrockBlockRuntimeId = blockTranslator.getBedrockBlockId(blockEntry.getValue()); - NbtMap blockTag = blockTranslator.getAllBedrockBlockStates().get(bedrockBlockRuntimeId); - String bedrockName = blockTag.getString("name"); - if (!bedrockName.equals(correctBedrockIdentifier)) { - continue; - } - NbtMap states = blockTag.getCompound("states"); - - if (firstPass) { - firstPass = false; - if (states.size() == 0) { - // No need to iterate and find all block states - this is the one, as there can't be any others - bedrockBlockId = bedrockBlockRuntimeId; - break; - } - requiredBlockStatesBuilder.putAll(states); - continue; - } - for (Map.Entry nbtEntry : states.entrySet()) { - Object value = requiredBlockStatesBuilder.get(nbtEntry.getKey()); - if (value != null && !nbtEntry.getValue().equals(value)) { // Null means this value has already been removed/deemed as unneeded - // This state can change between different block states, and therefore is not required - // to build a successful block state of this - requiredBlockStatesBuilder.remove(nbtEntry.getKey()); - } - } - if (requiredBlockStatesBuilder.size() == 0) { - // There are no required block states - // E.G. there was only a direction property that is no longer in play - // (States that are important include color for glass) - break; - } - } - } - - NbtMap requiredBlockStates = requiredBlockStatesBuilder.build(); - if (bedrockBlockId == -1) { - int i = -1; - // We need to loop around again (we can't cache the block tags above) because Bedrock can include states that we don't have a pairing for - // in it's "preferred" block state - I.E. the first matching block state in the list - for (NbtMap blockTag : blockTranslator.getAllBedrockBlockStates()) { - i++; - if (blockTag.getString("name").equals(correctBedrockIdentifier)) { - NbtMap states = blockTag.getCompound("states"); - boolean valid = true; - for (Map.Entry nbtEntry : requiredBlockStates.entrySet()) { - if (!states.get(nbtEntry.getKey()).equals(nbtEntry.getValue())) { - // A required block state doesn't match - this one is not valid - valid = false; - break; - } - } - if (valid) { - bedrockBlockId = i; - break; - } - } - } - if (bedrockBlockId == -1) { - throw new RuntimeException("Could not find a block match for " + entry.getKey()); - } - } - - // Because we have replaced the Bedrock block ID, we also need to replace the creative contents block runtime ID - // That way, creative items work correctly for these blocks - for (int j = 0; j < creativeItems.size(); j++) { - ItemData itemData = creativeItems.get(j); - if (itemData.getId() == bedrockId) { - if (itemData.getDamage() != 0) { - break; - } - NbtMap states = blockTranslator.getAllBedrockBlockStates().get(itemData.getBlockRuntimeId()).getCompound("states"); - boolean valid = true; - for (Map.Entry nbtEntry : requiredBlockStates.entrySet()) { - if (!states.get(nbtEntry.getKey()).equals(nbtEntry.getValue())) { - // A required block state doesn't match - this one is not valid - valid = false; - break; - } - } - if (valid) { - creativeItems.set(j, itemData.toBuilder().blockRuntimeId(bedrockBlockId).build()); - break; - } - } - } - } - } - } - - ItemEntry itemEntry; - if (entry.getValue().has("tool_type")) { - if (entry.getValue().has("tool_tier")) { - itemEntry = new ToolItemEntry( - entry.getKey(), bedrockIdentifier, itemIndex, bedrockId, - entry.getValue().get("bedrock_data").intValue(), - entry.getValue().get("tool_type").textValue(), - entry.getValue().get("tool_tier").textValue(), - bedrockBlockId, - stackSize); - } else { - itemEntry = new ToolItemEntry( - entry.getKey(), bedrockIdentifier, itemIndex, bedrockId, - entry.getValue().get("bedrock_data").intValue(), - entry.getValue().get("tool_type").textValue(), - "", bedrockBlockId, - stackSize); - } - } else if (entry.getKey().equals("minecraft:spectral_arrow") || entry.getKey().equals("minecraft:knowledge_book") - // To remove later... hopefully - || entry.getKey().contains("candle") || entry.getKey().equals("minecraft:bundle") || entry.getKey().equals("minecraft:sculk_sensor")) { - // These items don't exist on Bedrock, so set up a container that indicates they should have custom names - itemEntry = new TranslatableItemEntry( - entry.getKey(), bedrockIdentifier, itemIndex, bedrockId, - entry.getValue().get("bedrock_data").intValue(), - bedrockBlockId, - stackSize); - GeyserConnector.getInstance().getLogger().debug("Adding " + entry.getKey() + " as an item that needs to be translated."); - } else { - itemEntry = new ItemEntry( - entry.getKey(), bedrockIdentifier, itemIndex, bedrockId, - entry.getValue().get("bedrock_data").intValue(), - bedrockBlockId, - stackSize); - } - ITEM_ENTRIES.put(itemIndex, itemEntry); - - switch (entry.getKey()) { - case "minecraft:barrier": - BARRIER_INDEX = itemIndex; - break; - case "minecraft:bamboo": - BAMBOO = itemEntry; - break; - case "minecraft:crossbow": - CROSSBOW = itemEntry; - break; - case "minecraft:egg": - EGG = itemEntry; - break; - case "minecraft:fishing_rod": - FISHING_ROD = itemEntry; - break; - case "minecraft:shield": - SHIELD = itemEntry; - break; - case "minecraft:milk_bucket": - MILK_BUCKET = itemEntry; - break; - case "minecraft:wheat": - WHEAT = itemEntry; - break; - case "minecraft:white_banner": // As of 1.16.220, all banners share the same Bedrock ID and differ their colors through their damage value - BANNER = itemEntry; - break; - case "minecraft:writable_book": - WRITABLE_BOOK = itemEntry; - break; - default: - break; - } - - if (entry.getKey().contains("boat")) { - BOATS.add(itemEntry.getBedrockId()); - } else if (entry.getKey().contains("bucket") && !entry.getKey().contains("milk")) { - BUCKETS.add(itemEntry.getBedrockId()); - } else if (entry.getKey().contains("_carpet") && !entry.getKey().contains("moss")) { - // This should be the numerical order Java sends as an integer value for llamas - CARPETS.add(ItemData.builder() - .id(itemEntry.getBedrockId()) - .damage(itemEntry.getBedrockData()) - .count(1) - .blockRuntimeId(itemEntry.getBedrockBlockId()).build()); - } else if (entry.getKey().startsWith("minecraft:music_disc_")) { - // The Java record level event uses the item ID as the "key" to play the record - EffectRegistry.RECORDS.put(itemIndex, SoundEvent.valueOf("RECORD_" + - entry.getKey().replace("minecraft:music_disc_", "").toUpperCase(Locale.ENGLISH))); - } else if (entry.getKey().endsWith("_spawn_egg")) { - SPAWN_EGGS.add(itemEntry.getBedrockId()); - } - - itemNames.add(entry.getKey()); - - itemIndex++; - } - - itemNames.add("minecraft:furnace_minecart"); - - if (lodestoneCompassId == 0) { - throw new RuntimeException("Lodestone compass not found in item palette!"); - } - - // Add the loadstone compass since it doesn't exist on java but we need it for item conversion - ITEM_ENTRIES.put(itemIndex, new ItemEntry("minecraft:lodestone_compass", "minecraft:lodestone_compass", itemIndex, - lodestoneCompassId, 0, -1, 1)); - - if (usingFurnaceMinecart) { - // Add the furnace minecart as a custom item - int furnaceMinecartId = ITEMS.size() + 1; - - ITEMS.add(new StartGamePacket.ItemEntry("geysermc:furnace_minecart", (short) furnaceMinecartId, true)); - ITEM_ENTRIES.put(javaFurnaceMinecartId, new ItemEntry("minecraft:furnace_minecart", "geysermc:furnace_minecart", javaFurnaceMinecartId, - furnaceMinecartId, 0, -1, 1)); - creativeItems.add(ItemData.builder() - .netId(netId) - .id(furnaceMinecartId) - .count(1).build()); - - NbtMapBuilder builder = NbtMap.builder(); - builder.putString("name", "geysermc:furnace_minecart") - .putInt("id", furnaceMinecartId); - - NbtMapBuilder componentBuilder = NbtMap.builder(); - // Conveniently, as of 1.16.200, the furnace minecart has a texture AND translation string already. - componentBuilder.putCompound("minecraft:icon", NbtMap.builder().putString("texture", "minecart_furnace").build()); - componentBuilder.putCompound("minecraft:display_name", NbtMap.builder().putString("value", "item.minecartFurnace.name").build()); - - // Indicate that the arm animation should play on rails - List useOnTag = Collections.singletonList(NbtMap.builder().putString("tags", "q.any_tag('rail')").build()); - componentBuilder.putCompound("minecraft:entity_placer", NbtMap.builder() - .putList("dispense_on", NbtType.COMPOUND, useOnTag) - .putString("entity", "minecraft:minecart") - .putList("use_on", NbtType.COMPOUND, useOnTag) - .build()); - - NbtMapBuilder itemProperties = NbtMap.builder(); - // We always want to allow offhand usage when we can - matches Java Edition - itemProperties.putBoolean("allow_off_hand", true); - itemProperties.putBoolean("hand_equipped", false); - itemProperties.putInt("max_stack_size", 1); - itemProperties.putString("creative_group", "itemGroup.name.minecart"); - itemProperties.putInt("creative_category", 4); // 4 - "Items" - - componentBuilder.putCompound("item_properties", itemProperties.build()); - builder.putCompound("components", componentBuilder.build()); - FURNACE_MINECART_DATA = new ComponentItemData("geysermc:furnace_minecart", builder.build()); - } else { - FURNACE_MINECART_DATA = null; - } - - CREATIVE_ITEMS = creativeItems.toArray(new ItemData[0]); - - ITEM_NAMES = itemNames.toArray(new String[0]); - - Set javaOnlyItems = new ObjectOpenHashSet<>(); - Collections.addAll(javaOnlyItems, "minecraft:spectral_arrow", "minecraft:debug_stick", - "minecraft:knowledge_book", "minecraft:tipped_arrow", "minecraft:trader_llama_spawn_egg", - // To be removed in Bedrock 1.17.10... right??? RIGHT??? - "minecraft:candle", "minecraft:white_candle", "minecraft:orange_candle", "minecraft:magenta_candle", - "minecraft:light_blue_candle", "minecraft:yellow_candle", "minecraft:lime_candle", "minecraft:pink_candle", - "minecraft:gray_candle", "minecraft:light_gray_candle", "minecraft:cyan_candle", "minecraft:purple_candle", - "minecraft:blue_candle", "minecraft:brown_candle", "minecraft:green_candle", "minecraft:red_candle", "minecraft:black_candle", - "minecraft:bundle", "minecraft:sculk_sensor"); - if (!usingFurnaceMinecart) { - javaOnlyItems.add("minecraft:furnace_minecart"); - } - JAVA_ONLY_ITEMS = ImmutableSet.copyOf(javaOnlyItems); - } - - /** - * Gets an {@link ItemEntry} from the given {@link ItemStack}. - * - * @param stack the item stack - * @return an item entry from the given item stack - */ - public static ItemEntry getItem(ItemStack stack) { - return ITEM_ENTRIES.get(stack.getId()); - } - - /** - * Gets an {@link ItemEntry} from the given {@link ItemData}. - * - * @param data the item data - * @return an item entry from the given item data - */ - public static ItemEntry getItem(ItemData data) { - boolean isBlock = data.getBlockRuntimeId() != 0; - boolean hasDamage = data.getDamage() != 0; - - for (ItemEntry itemEntry : ITEM_ENTRIES.values()) { - if (itemEntry.getBedrockId() == data.getId()) { - if (isBlock && !hasDamage) { // Pre-1.16.220 will not use block runtime IDs at all, so we shouldn't check either - if (data.getBlockRuntimeId() != itemEntry.getBedrockBlockId()) { - continue; - } - } else { - if (!(itemEntry.getBedrockData() == data.getDamage() || - // Make exceptions for potions and tipped arrows, whose damage values can vary - (itemEntry.getJavaIdentifier().endsWith("potion") || itemEntry.getJavaIdentifier().equals("minecraft:arrow")))) { - continue; - } - } - if (!JAVA_ONLY_ITEMS.contains(itemEntry.getJavaIdentifier())) { - // From a Bedrock item data, we aren't getting one of these items - return itemEntry; - } - } - } - - // This will hide the message when the player clicks with an empty hand - if (data.getId() != 0 && data.getDamage() != 0) { - GeyserConnector.getInstance().getLogger().debug("Missing mapping for bedrock item " + data.getId() + ":" + data.getDamage()); - } - return ItemEntry.AIR; - } - - /** - * Gets an {@link ItemEntry} from the given Minecraft: Java Edition - * block state identifier. - * - * @param javaIdentifier the block state identifier - * @return an item entry from the given java edition identifier - */ - public static ItemEntry getItemEntry(String javaIdentifier) { - return JAVA_IDENTIFIER_MAP.computeIfAbsent(javaIdentifier, key -> { - for (ItemEntry entry : ITEM_ENTRIES.values()) { - if (entry.getJavaIdentifier().equals(key)) { - return entry; - } - } - return null; - }); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java index c2bef9c6d..c4d098f79 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java @@ -38,6 +38,9 @@ import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; import org.geysermc.connector.network.translators.chat.MessageTranslator; +import org.geysermc.connector.registry.BlockRegistries; +import org.geysermc.connector.registry.type.ItemMapping; +import org.geysermc.connector.registry.type.ItemMappings; import org.geysermc.connector.utils.FileUtils; import org.geysermc.connector.utils.LocaleUtils; import org.reflections.Reflections; @@ -73,8 +76,8 @@ public abstract class ItemTranslator { continue; } ItemTranslator itemStackTranslator = (ItemTranslator) clazz.newInstance(); - List appliedItems = itemStackTranslator.getAppliedItems(); - for (ItemEntry item : appliedItems) { + List appliedItems = itemStackTranslator.getAppliedItems(); + for (ItemMapping item : appliedItems) { ItemTranslator registered = ITEM_STACK_TRANSLATORS.get(item.getJavaId()); if (registered != null) { GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated item translator " + @@ -92,18 +95,23 @@ public abstract class ItemTranslator { NBT_TRANSLATORS = loadedNbtItemTranslators.keySet().stream().sorted(Comparator.comparingInt(loadedNbtItemTranslators::get)).collect(Collectors.toList()); } - public static ItemStack translateToJava(ItemData data) { + /** + * @param mappings item mappings to use while translating. This can't just be a Geyser session as this method is used + * when loading recipes. + */ + public static ItemStack translateToJava(ItemData data, ItemMappings mappings) { if (data == null) { return new ItemStack(0); } - ItemEntry javaItem = ItemRegistry.getItem(data); + + ItemMapping javaItem = mappings.getMapping(data); ItemStack itemStack; ItemTranslator itemStackTranslator = ITEM_STACK_TRANSLATORS.get(javaItem.getJavaId()); if (itemStackTranslator != null) { - itemStack = itemStackTranslator.translateToJava(data, javaItem); + itemStack = itemStackTranslator.translateToJava(data, javaItem, mappings); } else { - itemStack = DEFAULT_TRANSLATOR.translateToJava(data, javaItem); + itemStack = DEFAULT_TRANSLATOR.translateToJava(data, javaItem, mappings); } if (itemStack != null && itemStack.getNbt() != null) { @@ -125,9 +133,9 @@ public abstract class ItemTranslator { return ItemData.AIR; } - ItemEntry bedrockItem = ItemRegistry.getItem(stack); + ItemMapping bedrockItem = session.getItemMappings().getMapping(stack); if (bedrockItem == null) { - session.getConnector().getLogger().debug("No matching ItemEntry for " + stack); + session.getConnector().getLogger().debug("No matching ItemMapping for " + stack); return ItemData.AIR; } @@ -154,9 +162,9 @@ public abstract class ItemTranslator { ItemData.Builder builder; ItemTranslator itemStackTranslator = ITEM_STACK_TRANSLATORS.get(bedrockItem.getJavaId()); if (itemStackTranslator != null) { - builder = itemStackTranslator.translateToBedrock(itemStack, bedrockItem); + builder = itemStackTranslator.translateToBedrock(itemStack, bedrockItem, session.getItemMappings()); } else { - builder = DEFAULT_TRANSLATOR.translateToBedrock(itemStack, bedrockItem); + builder = DEFAULT_TRANSLATOR.translateToBedrock(itemStack, bedrockItem, session.getItemMappings()); } if (bedrockItem.isBlock()) { builder.blockRuntimeId(bedrockItem.getBedrockBlockId()); @@ -168,8 +176,8 @@ public abstract class ItemTranslator { String[] canBreak = new String[0]; ListTag canPlaceOn = nbt.get("CanPlaceOn"); String[] canPlace = new String[0]; - canBreak = getCanModify(session, canDestroy, canBreak); - canPlace = getCanModify(session, canPlaceOn, canPlace); + canBreak = getCanModify(canDestroy, canBreak); + canPlace = getCanModify(canPlaceOn, canPlace); builder.canBreak(canBreak); builder.canPlace(canPlace); } @@ -185,7 +193,7 @@ public abstract class ItemTranslator { * @param canModifyBedrock the empty list of items in Bedrock * @return the new list of items in Bedrock */ - private static String[] getCanModify(GeyserSession session, ListTag canModifyJava, String[] canModifyBedrock) { + private static String[] getCanModify(ListTag canModifyJava, String[] canModifyBedrock) { if (canModifyJava != null && canModifyJava.size() > 0) { canModifyBedrock = new String[canModifyJava.size()]; for (int i = 0; i < canModifyBedrock.length; i++) { @@ -195,7 +203,7 @@ public abstract class ItemTranslator { if (!block.startsWith("minecraft:")) block = "minecraft:" + block; // Get the Bedrock identifier of the item and replace it. // This will unfortunately be limited - for example, beds and banners will be translated weirdly - canModifyBedrock[i] = session.getBlockTranslator().getBedrockBlockIdentifier(block).replace("minecraft:", ""); + canModifyBedrock[i] = BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.get(block).replace("minecraft:", ""); } } return canModifyBedrock; @@ -203,19 +211,19 @@ public abstract class ItemTranslator { private static final ItemTranslator DEFAULT_TRANSLATOR = new ItemTranslator() { @Override - public List getAppliedItems() { + public List getAppliedItems() { return null; } }; - public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) { + public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { if (itemStack == null) { // Return, essentially, air return ItemData.builder(); } ItemData.Builder builder = ItemData.builder() - .id(itemEntry.getBedrockId()) - .damage(itemEntry.getBedrockData()) + .id(mapping.getBedrockId()) + .damage(mapping.getBedrockData()) .count(itemStack.getAmount()); if (itemStack.getNbt() != null) { builder.tag(this.translateNbtToBedrock(itemStack.getNbt())); @@ -223,15 +231,15 @@ public abstract class ItemTranslator { return builder; } - public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) { + public ItemStack translateToJava(ItemData itemData, ItemMapping mapping, ItemMappings mappings) { if (itemData == null) return null; if (itemData.getTag() == null) { - return new ItemStack(itemEntry.getJavaId(), itemData.getCount(), new CompoundTag("")); + return new ItemStack(mapping.getJavaId(), itemData.getCount(), new CompoundTag("")); } - return new ItemStack(itemEntry.getJavaId(), itemData.getCount(), this.translateToJavaNBT("", itemData.getTag())); + return new ItemStack(mapping.getJavaId(), itemData.getCount(), this.translateToJavaNBT("", itemData.getTag())); } - public abstract List getAppliedItems(); + public abstract List getAppliedItems(); public NbtMap translateNbtToBedrock(CompoundTag tag) { NbtMapBuilder builder = NbtMap.builder(); @@ -395,19 +403,19 @@ public abstract class ItemTranslator { * Translates the display name of the item * @param session the Bedrock client's session * @param tag the tag to translate - * @param itemEntry the item entry, in case it requires translation + * @param mapping the item entry, in case it requires translation * * @return the new tag to use, should the current one be null */ - public static CompoundTag translateDisplayProperties(GeyserSession session, CompoundTag tag, ItemEntry itemEntry) { - return translateDisplayProperties(session, tag, itemEntry, 'f'); + public static CompoundTag translateDisplayProperties(GeyserSession session, CompoundTag tag, ItemMapping mapping) { + return translateDisplayProperties(session, tag, mapping, 'f'); } /** * @param translationColor if this item is not available on Java, the color that the new name should be. * Normally, this should just be white, but for shulker boxes this should be gray. */ - public static CompoundTag translateDisplayProperties(GeyserSession session, CompoundTag tag, ItemEntry itemEntry, char translationColor) { + public static CompoundTag translateDisplayProperties(GeyserSession session, CompoundTag tag, ItemMapping mapping, char translationColor) { boolean hasCustomName = false; if (tag != null) { CompoundTag display = tag.get("display"); @@ -427,7 +435,7 @@ public abstract class ItemTranslator { } } - if (!hasCustomName && itemEntry instanceof TranslatableItemEntry) { + if (!hasCustomName && mapping.hasTranslation()) { // No custom name, but we need to localize the item's name if (tag == null) { tag = new CompoundTag(""); @@ -439,7 +447,7 @@ public abstract class ItemTranslator { tag.put(display); } - String translationKey = ((TranslatableItemEntry) itemEntry).getTranslationString(); + String translationKey = mapping.getTranslationString(); // Reset formatting since Bedrock defaults to italics display.put(new StringTag("Name", "§r§" + translationColor + LocaleUtils.getLocaleString(translationKey, session.getLocale()))); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/NbtItemStackTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/NbtItemStackTranslator.java index bfd1d777c..a7044c3b2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/NbtItemStackTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/NbtItemStackTranslator.java @@ -27,6 +27,7 @@ package org.geysermc.connector.network.translators.item; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.registry.type.ItemMapping; public class NbtItemStackTranslator { @@ -34,26 +35,28 @@ public class NbtItemStackTranslator { * Translate the item NBT to Bedrock * @param session the client's current session * @param itemTag the item's CompoundTag - * @param itemEntry Geyser's item entry + * @param mapping Geyser's item mapping */ - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { } /** * Translate the item NBT to Java. * @param itemTag the item's CompoundTag - * @param itemEntry Geyser's item entry + * @param mapping Geyser's item mapping */ - public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToJava(CompoundTag itemTag, ItemMapping mapping) { } /** - * @param itemEntry Geyser's item entry + * Gets whether this nbt translator takes in this item. + * + * @param mapping Geyser's item mapping * @return if the item should be processed under this class */ - public boolean acceptItem(ItemEntry itemEntry) { + public boolean acceptItem(ItemMapping mapping) { return true; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/StoredItemMappings.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/StoredItemMappings.java new file mode 100644 index 000000000..80a50f831 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/StoredItemMappings.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2019-2021 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.connector.network.translators.item; + +import lombok.Getter; +import lombok.experimental.Accessors; +import org.geysermc.connector.registry.type.ItemMapping; + +import javax.annotation.Nonnull; +import java.util.Map; + +/** + * A class to have easy access to specific item mappings per-version. + */ +@Getter +@Accessors(fluent = true) +public class StoredItemMappings { + private final ItemMapping bamboo; + private final ItemMapping banner; + private final ItemMapping barrier; + private final ItemMapping compass; + private final ItemMapping crossbow; + private final ItemMapping fishingRod; + private final ItemMapping lodestoneCompass; + private final ItemMapping milkBucket; + private final ItemMapping egg; + private final ItemMapping shield; + private final ItemMapping wheat; + private final ItemMapping writableBook; + + public StoredItemMappings(Map itemMappings) { + this.bamboo = load(itemMappings, "bamboo"); + this.banner = load(itemMappings, "white_banner"); // As of 1.17.10, all banners have the same Bedrock ID + this.barrier = load(itemMappings, "barrier"); + this.compass = load(itemMappings, "compass"); + this.crossbow = load(itemMappings, "crossbow"); + this.fishingRod = load(itemMappings, "fishing_rod"); + this.lodestoneCompass = load(itemMappings, "lodestone_compass"); + this.milkBucket = load(itemMappings, "milk_bucket"); + this.egg = load(itemMappings, "egg"); + this.shield = load(itemMappings, "shield"); + this.wheat = load(itemMappings, "wheat"); + this.writableBook = load(itemMappings, "writable_book"); + } + + @Nonnull + private ItemMapping load(Map itemMappings, String cleanIdentifier) { + ItemMapping mapping = itemMappings.get("minecraft:" + cleanIdentifier); + if (mapping == null) { + throw new RuntimeException("Could not find item " + cleanIdentifier); + } + + return mapping; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java index fb1256e40..116e703bc 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java @@ -32,10 +32,12 @@ 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.connector.network.BedrockProtocol; import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemTranslator; +import org.geysermc.connector.registry.Registries; +import org.geysermc.connector.registry.type.ItemMapping; +import org.geysermc.connector.registry.type.ItemMappings; import java.util.ArrayList; import java.util.HashMap; @@ -54,7 +56,7 @@ public class BannerTranslator extends ItemTranslator { */ public static final ListTag OMINOUS_BANNER_PATTERN; - private final List appliedItems; + private final List appliedItems; static { OMINOUS_BANNER_PATTERN = new ListTag("Patterns"); @@ -79,7 +81,9 @@ public class BannerTranslator extends ItemTranslator { } public BannerTranslator() { - appliedItems = ItemRegistry.ITEM_ENTRIES.values() + appliedItems = Registries.ITEMS.forVersion(BedrockProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) + .getItems() + .values() .stream() .filter(entry -> entry.getJavaIdentifier().endsWith("banner")) .collect(Collectors.toList()); @@ -153,12 +157,12 @@ public class BannerTranslator extends ItemTranslator { } @Override - public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) { + public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { if (itemStack.getNbt() == null) { - return super.translateToBedrock(itemStack, itemEntry); + return super.translateToBedrock(itemStack, mapping, mappings); } - ItemData.Builder builder = super.translateToBedrock(itemStack, itemEntry); + ItemData.Builder builder = super.translateToBedrock(itemStack, mapping, mappings); CompoundTag blockEntityTag = itemStack.getNbt().get("BlockEntityTag"); if (blockEntityTag != null && blockEntityTag.contains("Patterns")) { @@ -180,12 +184,12 @@ public class BannerTranslator extends ItemTranslator { } @Override - public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) { + public ItemStack translateToJava(ItemData itemData, ItemMapping mapping, ItemMappings mappings) { if (itemData.getTag() == null) { - return super.translateToJava(itemData, itemEntry); + return super.translateToJava(itemData, mapping, mappings); } - ItemStack itemStack = super.translateToJava(itemData, itemEntry); + ItemStack itemStack = super.translateToJava(itemData, mapping, mappings); NbtMap nbtTag = itemData.getTag(); if (nbtTag.containsKey("Type", NbtType.INT) && nbtTag.getInt("Type") == 1) { @@ -209,7 +213,7 @@ public class BannerTranslator extends ItemTranslator { } @Override - public List getAppliedItems() { + public List getAppliedItems() { return appliedItems; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/CompassTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/CompassTranslator.java index 08c7426fe..e35e5c252 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/CompassTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/CompassTranslator.java @@ -28,10 +28,12 @@ package org.geysermc.connector.network.translators.item.translators; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.opennbt.tag.builtin.*; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import org.geysermc.connector.network.BedrockProtocol; import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemTranslator; +import org.geysermc.connector.registry.Registries; +import org.geysermc.connector.registry.type.ItemMapping; +import org.geysermc.connector.registry.type.ItemMappings; import org.geysermc.connector.utils.LoadstoneTracker; import java.util.List; @@ -40,20 +42,25 @@ import java.util.stream.Collectors; @ItemRemapper public class CompassTranslator extends ItemTranslator { - private final List appliedItems; + private final List appliedItems; public CompassTranslator() { - appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("compass")).collect(Collectors.toList()); + appliedItems = Registries.ITEMS.forVersion(BedrockProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) + .getItems() + .values() + .stream() + .filter(entry -> entry.getJavaIdentifier().endsWith("compass")) + .collect(Collectors.toList()); } @Override - public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) { - if (itemStack.getNbt() == null) return super.translateToBedrock(itemStack, itemEntry); + public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { + if (itemStack.getNbt() == null) return super.translateToBedrock(itemStack, mapping, mappings); Tag lodestoneTag = itemStack.getNbt().get("LodestoneTracked"); if (lodestoneTag instanceof ByteTag) { // Get the fake lodestonecompass entry - itemEntry = ItemRegistry.getItemEntry("minecraft:lodestone_compass"); + mapping = mappings.getStoredItems().lodestoneCompass(); // Get the loadstone pos CompoundTag loadstonePos = itemStack.getNbt().get("LodestonePos"); @@ -75,20 +82,20 @@ public class CompassTranslator extends ItemTranslator { } } - return super.translateToBedrock(itemStack, itemEntry); + return super.translateToBedrock(itemStack, mapping, mappings); } @Override - public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) { + public ItemStack translateToJava(ItemData itemData, ItemMapping mapping, ItemMappings mappings) { boolean isLoadstone = false; - if (itemEntry.getBedrockIdentifier().equals("minecraft:lodestone_compass")) { + if (mapping.getBedrockIdentifier().equals("minecraft:lodestone_compass")) { // Revert the entry back to the compass - itemEntry = ItemRegistry.getItemEntry("minecraft:compass"); + mapping = mappings.getStoredItems().compass(); isLoadstone = true; } - ItemStack itemStack = super.translateToJava(itemData, itemEntry); + ItemStack itemStack = super.translateToJava(itemData, mapping, mappings); if (isLoadstone) { // Get the tracking id @@ -113,7 +120,7 @@ public class CompassTranslator extends ItemTranslator { } @Override - public List getAppliedItems() { + public List getAppliedItems() { return appliedItems; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/PotionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/PotionTranslator.java index 9f41472fe..2908754aa 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/PotionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/PotionTranslator.java @@ -30,11 +30,13 @@ import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.network.translators.item.ItemRegistry; +import org.geysermc.connector.network.BedrockProtocol; import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.item.Potion; +import org.geysermc.connector.registry.Registries; +import org.geysermc.connector.registry.type.ItemMapping; +import org.geysermc.connector.registry.type.ItemMappings; import java.util.List; import java.util.stream.Collectors; @@ -42,34 +44,39 @@ import java.util.stream.Collectors; @ItemRemapper public class PotionTranslator extends ItemTranslator { - private final List appliedItems; + private final List appliedItems; public PotionTranslator() { - appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("potion")).collect(Collectors.toList()); + appliedItems = Registries.ITEMS.forVersion(BedrockProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) + .getItems() + .values() + .stream() + .filter(entry -> entry.getJavaIdentifier().endsWith("potion")) + .collect(Collectors.toList()); } @Override - public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) { - if (itemStack.getNbt() == null) return super.translateToBedrock(itemStack, itemEntry); + public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { + 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) { return ItemData.builder() - .id(itemEntry.getBedrockId()) + .id(mapping.getBedrockId()) .damage(potion.getBedrockId()) .count(itemStack.getAmount()) .tag(translateNbtToBedrock(itemStack.getNbt())); } GeyserConnector.getInstance().getLogger().debug("Unknown Java potion: " + potionTag.getValue()); } - return super.translateToBedrock(itemStack, itemEntry); + return super.translateToBedrock(itemStack, mapping, mappings); } @Override - public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) { + public ItemStack translateToJava(ItemData itemData, ItemMapping mapping, ItemMappings mappings) { Potion potion = Potion.getByBedrockId(itemData.getDamage()); - ItemStack itemStack = super.translateToJava(itemData, itemEntry); + ItemStack itemStack = super.translateToJava(itemData, mapping, mappings); if (potion != null) { StringTag potionTag = new StringTag("Potion", potion.getJavaIdentifier()); itemStack.getNbt().put(potionTag); @@ -78,7 +85,7 @@ public class PotionTranslator extends ItemTranslator { } @Override - public List getAppliedItems() { + public List getAppliedItems() { return appliedItems; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/TippedArrowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/TippedArrowTranslator.java index 8b64732c4..ebc3936de 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/TippedArrowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/TippedArrowTranslator.java @@ -30,11 +30,13 @@ import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.network.BedrockProtocol; import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.network.translators.item.TippedArrowPotion; +import org.geysermc.connector.registry.Registries; +import org.geysermc.connector.registry.type.ItemMapping; +import org.geysermc.connector.registry.type.ItemMappings; import java.util.List; import java.util.stream.Collectors; @@ -42,40 +44,47 @@ import java.util.stream.Collectors; @ItemRemapper public class TippedArrowTranslator extends ItemTranslator { - private final List appliedItems; + private final List appliedItems; - private static final int TIPPED_ARROW_JAVA_ID = ItemRegistry.getItemEntry("minecraft:tipped_arrow").getJavaId(); + private static final int TIPPED_ARROW_JAVA_ID = Registries.ITEMS.forVersion(BedrockProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) + .getMapping("minecraft:tipped_arrow") + .getJavaId(); public TippedArrowTranslator() { - appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> - entry.getJavaIdentifier().contains("arrow") && !entry.getJavaIdentifier().contains("spectral")).collect(Collectors.toList()); + appliedItems = Registries.ITEMS.forVersion(BedrockProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) + .getItems() + .values() + .stream() + .filter(entry -> entry.getJavaIdentifier().contains("arrow") + && !entry.getJavaIdentifier().contains("spectral")) + .collect(Collectors.toList()); } @Override - public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) { - if (!itemEntry.getJavaIdentifier().equals("minecraft:tipped_arrow") || itemStack.getNbt() == null) { + public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { + if (!mapping.getJavaIdentifier().equals("minecraft:tipped_arrow") || itemStack.getNbt() == null) { // We're only concerned about minecraft:arrow when translating Bedrock -> Java - return super.translateToBedrock(itemStack, itemEntry); + return super.translateToBedrock(itemStack, mapping, mappings); } Tag potionTag = itemStack.getNbt().get("Potion"); if (potionTag instanceof StringTag) { TippedArrowPotion tippedArrowPotion = TippedArrowPotion.getByJavaIdentifier(((StringTag) potionTag).getValue()); if (tippedArrowPotion != null) { return ItemData.builder() - .id(itemEntry.getBedrockId()) + .id(mapping.getBedrockId()) .damage(tippedArrowPotion.getBedrockId()) .count(itemStack.getAmount()) .tag(translateNbtToBedrock(itemStack.getNbt())); } GeyserConnector.getInstance().getLogger().debug("Unknown Java potion (tipped arrow): " + potionTag.getValue()); } - return super.translateToBedrock(itemStack, itemEntry); + return super.translateToBedrock(itemStack, mapping, mappings); } @Override - public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) { + public ItemStack translateToJava(ItemData itemData, ItemMapping mapping, ItemMappings mappings) { TippedArrowPotion tippedArrowPotion = TippedArrowPotion.getByBedrockId(itemData.getDamage()); - ItemStack itemStack = super.translateToJava(itemData, itemEntry); + ItemStack itemStack = super.translateToJava(itemData, mapping, mappings); if (tippedArrowPotion != null) { itemStack = new ItemStack(TIPPED_ARROW_JAVA_ID, itemStack.getAmount(), itemStack.getNbt()); StringTag potionTag = new StringTag("Potion", tippedArrowPotion.getJavaIdentifier()); @@ -85,7 +94,7 @@ public class TippedArrowTranslator extends ItemTranslator { } @Override - public List getAppliedItems() { + public List getAppliedItems() { return appliedItems; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/AxolotlBucketTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/AxolotlBucketTranslator.java index a0fe4910b..f62ac05ae 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/AxolotlBucketTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/AxolotlBucketTranslator.java @@ -30,15 +30,15 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; +import org.geysermc.connector.registry.type.ItemMapping; import org.geysermc.connector.utils.LocaleUtils; @ItemRemapper public class AxolotlBucketTranslator extends NbtItemStackTranslator { @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { // Bedrock Edition displays the properties of the axolotl. Java does not. // To work around this, set the custom name to the Axolotl translation and it's displayed correctly itemTag.put(new ByteTag("AppendCustomName", (byte) 1)); @@ -49,7 +49,7 @@ public class AxolotlBucketTranslator extends NbtItemStackTranslator { } @Override - public boolean acceptItem(ItemEntry itemEntry) { - return itemEntry.getJavaIdentifier().equals("minecraft:axolotl_bucket"); + public boolean acceptItem(ItemMapping mapping) { + return mapping.getJavaIdentifier().equals("minecraft:axolotl_bucket"); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BasicItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BasicItemTranslator.java index c097dd544..58d72de0e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BasicItemTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BasicItemTranslator.java @@ -29,8 +29,8 @@ import com.github.steveice10.opennbt.tag.builtin.*; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; import org.geysermc.connector.network.translators.chat.MessageTranslator; -import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; +import org.geysermc.connector.registry.type.ItemMapping; import org.geysermc.connector.utils.ItemUtils; import java.util.ArrayList; @@ -40,11 +40,11 @@ import java.util.List; public class BasicItemTranslator extends NbtItemStackTranslator { @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { Tag damage = itemTag.get("Damage"); if (damage instanceof IntTag) { int originalDurability = ((IntTag) damage).getValue(); - int durability = ItemUtils.getCorrectBedrockDurability(itemEntry.getJavaId(), originalDurability); + int durability = ItemUtils.getCorrectBedrockDurability(session, mapping.getJavaId(), originalDurability); if (durability != originalDurability) { // Fix damage tag inconsistencies itemTag.put(new IntTag("Damage", durability)); @@ -68,7 +68,7 @@ public class BasicItemTranslator extends NbtItemStackTranslator { } @Override - public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToJava(CompoundTag itemTag, ItemMapping mapping) { CompoundTag displayTag = itemTag.get("display"); if (displayTag == null) { return; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BookPagesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BookPagesTranslator.java index 90eef3bce..208db0987 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BookPagesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BookPagesTranslator.java @@ -32,8 +32,8 @@ import com.github.steveice10.opennbt.tag.builtin.Tag; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; -import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.chat.MessageTranslator; +import org.geysermc.connector.registry.type.ItemMapping; import java.util.ArrayList; import java.util.List; @@ -42,7 +42,7 @@ import java.util.List; public class BookPagesTranslator extends NbtItemStackTranslator { @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { if (!itemTag.contains("pages")) { return; } @@ -65,7 +65,7 @@ public class BookPagesTranslator extends NbtItemStackTranslator { } @Override - public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToJava(CompoundTag itemTag, ItemMapping mapping) { if (!itemTag.contains("pages")) { return; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/CrossbowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/CrossbowTranslator.java index ae52e4221..b0e55737f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/CrossbowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/CrossbowTranslator.java @@ -30,30 +30,29 @@ import com.github.steveice10.opennbt.tag.builtin.*; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; +import org.geysermc.connector.registry.type.ItemMapping; @ItemRemapper public class CrossbowTranslator extends NbtItemStackTranslator { @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { if (itemTag.get("ChargedProjectiles") != null) { ListTag chargedProjectiles = itemTag.get("ChargedProjectiles"); if (!chargedProjectiles.getValue().isEmpty()) { CompoundTag projectile = (CompoundTag) chargedProjectiles.getValue().get(0); - ItemEntry projectileEntry = ItemRegistry.getItemEntry((String) projectile.get("id").getValue()); - if (projectileEntry == null) return; + ItemMapping projectileMapping = session.getItemMappings().getMapping((String) projectile.get("id").getValue()); + if (projectileMapping == null) return; CompoundTag tag = projectile.get("tag"); - ItemStack itemStack = new ItemStack(itemEntry.getJavaId(), (byte) projectile.get("Count").getValue(), tag); + ItemStack itemStack = new ItemStack(mapping.getJavaId(), (byte) projectile.get("Count").getValue(), tag); ItemData itemData = ItemTranslator.translateToBedrock(session, itemStack); CompoundTag newProjectile = new CompoundTag("chargedItem"); newProjectile.put(new ByteTag("Count", (byte) itemData.getCount())); - newProjectile.put(new StringTag("Name", projectileEntry.getBedrockIdentifier())); + newProjectile.put(new StringTag("Name", projectileMapping.getBedrockIdentifier())); newProjectile.put(new ShortTag("Damage", (short) itemData.getDamage())); @@ -63,7 +62,7 @@ public class CrossbowTranslator extends NbtItemStackTranslator { } @Override - public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToJava(CompoundTag itemTag, ItemMapping mapping) { if (itemTag.get("chargedItem") != null) { CompoundTag chargedItem = itemTag.get("chargedItem"); @@ -79,7 +78,7 @@ public class CrossbowTranslator extends NbtItemStackTranslator { } @Override - public boolean acceptItem(ItemEntry itemEntry) { - return "minecraft:crossbow".equals(itemEntry.getJavaIdentifier()); + public boolean acceptItem(ItemMapping mapping) { + return "minecraft:crossbow".equals(mapping.getJavaIdentifier()); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantedBookTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantedBookTranslator.java index cc01feb4f..0bca7a8ba 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantedBookTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantedBookTranslator.java @@ -31,13 +31,13 @@ import com.github.steveice10.opennbt.tag.builtin.Tag; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; @ItemRemapper(priority = 1) public class EnchantedBookTranslator extends NbtItemStackTranslator { @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { if (!itemTag.contains("StoredEnchantments")) { return; } @@ -50,7 +50,7 @@ public class EnchantedBookTranslator extends NbtItemStackTranslator { } @Override - public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToJava(CompoundTag itemTag, ItemMapping mapping) { if (!itemTag.contains("Enchantments")) { return; } @@ -63,7 +63,7 @@ public class EnchantedBookTranslator extends NbtItemStackTranslator { } @Override - public boolean acceptItem(ItemEntry itemEntry) { - return "minecraft:enchanted_book".equals(itemEntry.getJavaIdentifier()); + public boolean acceptItem(ItemMapping mapping) { + return "minecraft:enchanted_book".equals(mapping.getJavaIdentifier()); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantmentTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantmentTranslator.java index 2e381d223..58caad3f1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantmentTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantmentTranslator.java @@ -31,7 +31,7 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; import org.geysermc.connector.network.translators.item.Enchantment; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; import java.util.ArrayList; import java.util.List; @@ -41,7 +41,7 @@ import java.util.Map; public class EnchantmentTranslator extends NbtItemStackTranslator { @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { List newTags = new ArrayList<>(); if (itemTag.contains("Enchantments")) { ListTag enchantmentTag = itemTag.get("Enchantments"); @@ -73,7 +73,7 @@ public class EnchantmentTranslator extends NbtItemStackTranslator { } @Override - public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToJava(CompoundTag itemTag, ItemMapping mapping) { if (!itemTag.contains("ench")) { return; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkRocketTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkRocketTranslator.java index f294315c8..0d37f0477 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkRocketTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkRocketTranslator.java @@ -31,14 +31,14 @@ import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; import org.geysermc.connector.utils.MathUtils; @ItemRemapper public class FireworkRocketTranslator extends FireworkBaseTranslator { @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { CompoundTag fireworks = itemTag.get("Fireworks"); if (fireworks == null) { return; @@ -62,7 +62,7 @@ public class FireworkRocketTranslator extends FireworkBaseTranslator { } @Override - public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToJava(CompoundTag itemTag, ItemMapping mapping) { CompoundTag fireworks = itemTag.get("Fireworks"); if (fireworks == null) { return; @@ -86,7 +86,7 @@ public class FireworkRocketTranslator extends FireworkBaseTranslator { } @Override - public boolean acceptItem(ItemEntry itemEntry) { - return "minecraft:firework_rocket".equals(itemEntry.getJavaIdentifier()); + public boolean acceptItem(ItemMapping mapping) { + return "minecraft:firework_rocket".equals(mapping.getJavaIdentifier()); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkStarTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkStarTranslator.java index 686887b45..38eca4856 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkStarTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkStarTranslator.java @@ -31,13 +31,13 @@ import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; @ItemRemapper public class FireworkStarTranslator extends FireworkBaseTranslator { @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { Tag explosion = itemTag.get("Explosion"); if (explosion instanceof CompoundTag) { CompoundTag newExplosion = translateExplosionToBedrock((CompoundTag) explosion, "FireworksItem"); @@ -78,7 +78,7 @@ public class FireworkStarTranslator extends FireworkBaseTranslator { } @Override - public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToJava(CompoundTag itemTag, ItemMapping mapping) { Tag explosion = itemTag.get("FireworksItem"); if (explosion instanceof CompoundTag) { CompoundTag newExplosion = translateExplosionToJava((CompoundTag) explosion, "Explosion"); @@ -90,7 +90,7 @@ public class FireworkStarTranslator extends FireworkBaseTranslator { } @Override - public boolean acceptItem(ItemEntry itemEntry) { - return "minecraft:firework_star".equals(itemEntry.getJavaIdentifier()); + public boolean acceptItem(ItemMapping mapping) { + return "minecraft:firework_star".equals(mapping.getJavaIdentifier()); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/LeatherArmorTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/LeatherArmorTranslator.java index c2305738d..0fd6f1e7b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/LeatherArmorTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/LeatherArmorTranslator.java @@ -30,16 +30,19 @@ import com.github.steveice10.opennbt.tag.builtin.IntTag; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; + +import java.util.Arrays; +import java.util.List; @ItemRemapper public class LeatherArmorTranslator extends NbtItemStackTranslator { - private static final String[] ITEMS = new String[]{"minecraft:leather_helmet", "minecraft:leather_chestplate", - "minecraft:leather_leggings", "minecraft:leather_boots", "minecraft:leather_horse_armor"}; + private static final List ITEMS = Arrays.asList("minecraft:leather_helmet", "minecraft:leather_chestplate", + "minecraft:leather_leggings", "minecraft:leather_boots", "minecraft:leather_horse_armor"); @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { CompoundTag displayTag = itemTag.get("display"); if (displayTag == null) { return; @@ -52,7 +55,7 @@ public class LeatherArmorTranslator extends NbtItemStackTranslator { } @Override - public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToJava(CompoundTag itemTag, ItemMapping mapping) { IntTag color = itemTag.get("customColor"); if (color == null) { return; @@ -66,10 +69,7 @@ public class LeatherArmorTranslator extends NbtItemStackTranslator { } @Override - public boolean acceptItem(ItemEntry itemEntry) { - for (String item : ITEMS) { - if (itemEntry.getJavaIdentifier().equals(item)) return true; - } - return false; + public boolean acceptItem(ItemMapping mapping) { + return ITEMS.contains(mapping.getJavaIdentifier()); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/MapItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/MapItemTranslator.java index 79db364b1..14342a8b3 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/MapItemTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/MapItemTranslator.java @@ -28,14 +28,14 @@ package org.geysermc.connector.network.translators.item.translators.nbt; import com.github.steveice10.opennbt.tag.builtin.*; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; +import org.geysermc.connector.registry.type.ItemMapping; @ItemRemapper public class MapItemTranslator extends NbtItemStackTranslator { @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { // Can be either an IntTag or ShortTag Tag mapId = itemTag.get("map"); if (mapId == null) return; @@ -55,7 +55,7 @@ public class MapItemTranslator extends NbtItemStackTranslator { } @Override - public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToJava(CompoundTag itemTag, ItemMapping mapping) { IntTag tag = itemTag.get("map_name_index"); if (tag != null) { itemTag.put(new IntTag("map", tag.getValue())); @@ -65,7 +65,7 @@ public class MapItemTranslator extends NbtItemStackTranslator { } @Override - public boolean acceptItem(ItemEntry itemEntry) { - return itemEntry.getJavaIdentifier().equals("minecraft:filled_map"); + public boolean acceptItem(ItemMapping mapping) { + return mapping.getJavaIdentifier().equals("minecraft:filled_map"); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/PlayerHeadTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/PlayerHeadTranslator.java index 3824ff3c8..152c28daa 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/PlayerHeadTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/PlayerHeadTranslator.java @@ -30,15 +30,15 @@ import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; +import org.geysermc.connector.registry.type.ItemMapping; import org.geysermc.connector.utils.LocaleUtils; @ItemRemapper public class PlayerHeadTranslator extends NbtItemStackTranslator { @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { if (!itemTag.contains("display") || !((CompoundTag) itemTag.get("display")).contains("Name")) { if (itemTag.contains("SkullOwner")) { StringTag name; @@ -66,7 +66,7 @@ public class PlayerHeadTranslator extends NbtItemStackTranslator { } @Override - public boolean acceptItem(ItemEntry itemEntry) { - return itemEntry.getJavaIdentifier().equals("minecraft:player_head"); + public boolean acceptItem(ItemMapping mapping) { + return mapping.getJavaIdentifier().equals("minecraft:player_head"); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/ShulkerBoxItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/ShulkerBoxItemTranslator.java index 197e119fc..5f39d3a68 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/ShulkerBoxItemTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/ShulkerBoxItemTranslator.java @@ -29,12 +29,13 @@ import com.github.steveice10.opennbt.tag.builtin.*; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; import org.geysermc.connector.network.translators.item.*; +import org.geysermc.connector.registry.type.ItemMapping; @ItemRemapper public class ShulkerBoxItemTranslator extends NbtItemStackTranslator { @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { if (!itemTag.contains("BlockEntityTag")) return; // Empty shulker box CompoundTag blockEntityTag = itemTag.get("BlockEntityTag"); @@ -46,18 +47,18 @@ public class ShulkerBoxItemTranslator extends NbtItemStackTranslator { boxItemTag.put(new ByteTag("Slot", ((ByteTag) itemData.get("Slot")).getValue())); boxItemTag.put(new ByteTag("WasPickedUp", (byte) 0)); // ??? - ItemEntry boxItemEntry = ItemRegistry.getItemEntry(((StringTag) itemData.get("id")).getValue()); + ItemMapping boxMapping = session.getItemMappings().getMapping(((StringTag) itemData.get("id")).getValue()); - boxItemTag.put(new StringTag("Name", boxItemEntry.getBedrockIdentifier())); - boxItemTag.put(new ShortTag("Damage", (short) boxItemEntry.getBedrockData())); + boxItemTag.put(new StringTag("Name", boxMapping.getBedrockIdentifier())); + boxItemTag.put(new ShortTag("Damage", (short) boxMapping.getBedrockData())); boxItemTag.put(new ByteTag("Count", ((ByteTag) itemData.get("Count")).getValue())); // Only the display name is what we have interest in, so just translate that if relevant CompoundTag displayTag = itemData.get("tag"); - if (displayTag == null && boxItemEntry instanceof TranslatableItemEntry) { + if (displayTag == null && boxMapping.hasTranslation()) { displayTag = new CompoundTag("tag"); } if (displayTag != null) { - boxItemTag.put(ItemTranslator.translateDisplayProperties(session, displayTag, boxItemEntry, '7')); + boxItemTag.put(ItemTranslator.translateDisplayProperties(session, displayTag, boxMapping, '7')); } itemsList.add(boxItemTag); @@ -69,14 +70,14 @@ public class ShulkerBoxItemTranslator extends NbtItemStackTranslator { } @Override - public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToJava(CompoundTag itemTag, ItemMapping mapping) { if (itemTag.contains("Items")) { // Remove any extraneous Bedrock tag and don't touch the Java one itemTag.remove("Items"); } } @Override - public boolean acceptItem(ItemEntry itemEntry) { - return itemEntry.getJavaIdentifier().contains("shulker_box"); + public boolean acceptItem(ItemMapping mapping) { + return mapping.getJavaIdentifier().contains("shulker_box"); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaAdvancementsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaAdvancementsTranslator.java index 714578e9a..2e1057e0e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaAdvancementsTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaAdvancementsTranslator.java @@ -95,6 +95,8 @@ public class JavaAdvancementsTranslator extends PacketTranslator new HashSet<>()).add(node.getName().toLowerCase()); @@ -168,11 +167,12 @@ public class JavaDeclareCommandsTranslator extends PacketTranslator= 1) { // Create the root param node and build all the children ParamInfo rootParam = new ParamInfo(commandNode, null); - rootParam.buildChildren(allNodes); + rootParam.buildChildren(session, allNodes); List treeData = rootParam.getTree(); @@ -195,10 +195,11 @@ public class JavaDeclareCommandsTranslator extends PacketTranslator { + /** + * Required to use the specified cartography table recipes + */ + private static final List CARTOGRAPHY_RECIPES = Arrays.asList( + 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 + CraftingData.fromMulti(UUID.fromString("602234e4-cac1-4353-8bb7-b1ebff70024b"), ++LAST_RECIPE_NET_ID) // Map locking + ); @Override public void translate(ServerDeclareRecipesPacket packet, GeyserSession session) { + Map> recipeTypes = Registries.CRAFTING_DATA.forVersion(session.getUpstream().getProtocolVersion()); // Get the last known network ID (first used for the pregenerated recipes) and increment from there. - int netId = RecipeRegistry.LAST_RECIPE_NET_ID + 1; - Int2ObjectMap recipeMap = new Int2ObjectOpenHashMap<>(RecipeRegistry.ALL_CRAFTING_RECIPES); + int netId = InventoryUtils.LAST_RECIPE_NET_ID + 1; + + Int2ObjectMap recipeMap = new Int2ObjectOpenHashMap<>(Registries.RECIPES.forVersion(session.getUpstream().getProtocolVersion())); Int2ObjectMap> unsortedStonecutterData = new Int2ObjectOpenHashMap<>(); CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); craftingDataPacket.setCleanRecipes(true); @@ -94,55 +111,6 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator craftingData = recipeTypes.get(recipe.getType()); + if (craftingData != null) { + craftingDataPacket.getCraftingData().addAll(craftingData); + } + break; } } } - // Add all cartography table recipe UUIDs, so we can use the cartography table - craftingDataPacket.getCraftingData().addAll(RecipeRegistry.CARTOGRAPHY_RECIPE_DATA); - - craftingDataPacket.getPotionMixData().addAll(PotionMixRegistry.POTION_MIXES); + craftingDataPacket.getCraftingData().addAll(CARTOGRAPHY_RECIPES); + craftingDataPacket.getPotionMixData().addAll(Registries.POTION_MIXES.get()); Int2ObjectMap stonecutterRecipeMap = new Int2ObjectOpenHashMap<>(); for (Int2ObjectMap.Entry> data : unsortedStonecutterData.int2ObjectEntrySet()) { // Sort the list by each output item's Java identifier - this is how it's sorted on Java, and therefore // We can get the correct order for button pressing data.getValue().sort(Comparator.comparing((stoneCuttingRecipeData -> - ItemRegistry.getItem(stoneCuttingRecipeData.getResult()).getJavaIdentifier()))); + session.getItemMappings().getItems().get(stoneCuttingRecipeData.getResult().getId()).getJavaIdentifier()))); // Now that it's sorted, let's translate these recipes for (StoneCuttingRecipeData stoneCuttingData : data.getValue()) { @@ -222,8 +196,8 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator new IntOpenHashSet()).add(i); } int totalCombinations = 1; - for (Set optionSet : squashedOptions.keySet()) { + for (Set optionSet : squashedOptions.keySet()) { totalCombinations *= optionSet.size(); } if (totalCombinations > 500) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java index 162028ef8..af1cfc45b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java @@ -38,7 +38,6 @@ import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.item.ItemRegistry; @Translator(packet = ServerEntityStatusPacket.class) public class JavaEntityStatusTranslator extends PacketTranslator { @@ -98,7 +97,7 @@ public class JavaEntityStatusTranslator extends PacketTranslator { @@ -77,7 +76,7 @@ public class JavaBlockValueTranslator extends PacketTranslator { try { + if (session.isClosed()) { + return; + } ChunkUtils.ChunkData chunkData = ChunkUtils.translateToBedrock(session, column, yOffset); ChunkSection[] sections = chunkData.getSections(); @@ -74,7 +77,7 @@ public class JavaChunkDataTranslator extends PacketTranslator { @@ -44,7 +46,7 @@ public class JavaPlayBuiltinSoundTranslator extends PacketTranslator { @@ -50,7 +51,7 @@ public class JavaPlaySoundTranslator extends PacketTranslator createParticle(GeyserSession session, Particle particle) { switch (particle.getType()) { case BLOCK: { - int blockState = session.getBlockTranslator().getBedrockBlockId(((BlockParticleData) particle.getData()).getBlockState()); + int blockState = session.getBlockMappings().getBedrockBlockId(((BlockParticleData) particle.getData()).getBlockState()); return (position) -> { LevelEventPacket packet = new LevelEventPacket(); packet.setType(LevelEventType.PARTICLE_CRACK_BLOCK); @@ -91,7 +91,7 @@ public class JavaSpawnParticleTranslator extends PacketTranslator { LevelEventPacket packet = new LevelEventPacket(); // In fact, FallingDustParticle should have data like DustParticle, @@ -130,7 +130,7 @@ public class JavaSpawnParticleTranslator extends PacketTranslator { LevelEventPacket packet = new LevelEventPacket(); @@ -139,7 +139,7 @@ public class JavaSpawnParticleTranslator extends PacketTranslator { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaStopSoundTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaStopSoundTranslator.java index d7d0f0738..ebcf2234e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaStopSoundTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaStopSoundTranslator.java @@ -32,7 +32,8 @@ import com.nukkitx.protocol.bedrock.packet.StopSoundPacket; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.sound.SoundRegistry; +import org.geysermc.connector.registry.Registries; +import org.geysermc.connector.registry.type.SoundMapping; @Translator(packet = ServerStopSoundPacket.class) public class JavaStopSoundTranslator extends PacketTranslator { @@ -57,7 +58,7 @@ public class JavaStopSoundTranslator extends PacketTranslator " + soundMapping + (soundMapping == null ? "[not found]" : "") diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java index c4dcf50c9..cce48f5cc 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java @@ -41,9 +41,8 @@ import org.geysermc.connector.inventory.MerchantContainer; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemTranslator; +import org.geysermc.connector.registry.type.ItemMapping; import java.util.ArrayList; import java.util.List; @@ -136,18 +135,18 @@ public class JavaTradeListTranslator extends PacketTranslator> interactionEntry : SoundHandlerRegistry.INTERACTION_HANDLERS.entrySet()) { + for (Map.Entry> interactionEntry : Registries.SOUND_HANDLERS.get().entrySet()) { if (!(interactionEntry.getValue() instanceof BlockSoundInteractionHandler)) { continue; } @@ -68,7 +69,7 @@ public interface BlockSoundInteractionHandler extends SoundInteractionHandler> interactionEntry : SoundHandlerRegistry.INTERACTION_HANDLERS.entrySet()) { + for (Map.Entry> interactionEntry : Registries.SOUND_HANDLERS.get().entrySet()) { if (!(interactionEntry.getValue() instanceof EntitySoundInteractionHandler)) { continue; } @@ -70,7 +71,7 @@ public interface EntitySoundInteractionHandler extends SoundInteractionHandler bedrockBlockStates; - - /** - * Stores a list of differences in block identifiers. - * Items will not be added to this list if the key and value is the same. - */ - private static final Object2ObjectMap JAVA_TO_BEDROCK_IDENTIFIERS = new Object2ObjectOpenHashMap<>(); - private static final BiMap JAVA_ID_BLOCK_MAP = HashBiMap.create(); - private static final IntSet WATERLOGGED = new IntOpenHashSet(); - private final Object2IntMap itemFrames = new Object2IntOpenHashMap<>(); - private final Map flowerPotBlocks = new HashMap<>(); - - private static final Int2ObjectMap JAVA_RUNTIME_ID_TO_BLOCK_MAPPING = new Int2ObjectOpenHashMap<>(); - - /** - * Java numeric ID to java unique identifier, used for block names in the statistics screen - */ - public static final Int2ObjectMap JAVA_ID_TO_JAVA_IDENTIFIER_MAP = new Int2ObjectOpenHashMap<>(); - - /** - * Runtime command block ID, used for fixing command block minecart appearances - */ - @Getter - private final int bedrockRuntimeCommandBlockId; - - private final EmptyChunkProvider emptyChunkProvider; - - public static final int JAVA_COBWEB_BLOCK_ID; - public static final int JAVA_BELL_BLOCK_ID; - - public static final int JAVA_RUNTIME_FURNACE_ID; - public static final int JAVA_RUNTIME_FURNACE_LIT_ID; - - public static final int JAVA_RUNTIME_SPAWNER_ID; - - /** - * Contains a map of Java blocks to their respective Bedrock block tag, if the Java identifier is different from Bedrock. - * Required to fix villager trades with these blocks. - */ - private final Map javaIdentifierToBedrockTag; - - /** - * Stores the raw blocks JSON until it is no longer needed. - */ - public static JsonNode BLOCKS_JSON; - - static { - InputStream stream = FileUtils.getResource("mappings/blocks.json"); - try { - BLOCKS_JSON = GeyserConnector.JSON_MAPPER.readTree(stream); - } catch (Exception e) { - throw new AssertionError("Unable to load Java block mappings", e); - } - - int javaRuntimeId = -1; - int bellBlockId = -1; - int cobwebBlockId = -1; - int furnaceRuntimeId = -1; - int furnaceLitRuntimeId = -1; - int spawnerRuntimeId = -1; - int uniqueJavaId = -1; - int waterRuntimeId = -1; - Iterator> blocksIterator = BLOCKS_JSON.fields(); - while (blocksIterator.hasNext()) { - javaRuntimeId++; - Map.Entry entry = blocksIterator.next(); - String javaId = entry.getKey(); - - BlockMapping.BlockMappingBuilder builder = BlockMapping.builder(); - // TODO fix this, (no block should have a null hardness) - JsonNode hardnessNode = entry.getValue().get("block_hardness"); - if (hardnessNode != null) { - builder.hardness(hardnessNode.doubleValue()); - } - - JsonNode canBreakWithHandNode = entry.getValue().get("can_break_with_hand"); - if (canBreakWithHandNode != null) { - builder.canBreakWithHand(canBreakWithHandNode.booleanValue()); - } else { - builder.canBreakWithHand(false); - } - - JsonNode collisionIndexNode = entry.getValue().get("collision_index"); - if (hardnessNode != null) { - builder.collisionIndex(collisionIndexNode.intValue()); - } - - JsonNode pickItemNode = entry.getValue().get("pick_item"); - if (pickItemNode != null) { - builder.pickItem(pickItemNode.textValue()); - } - - boolean waterlogged = entry.getKey().contains("waterlogged=true") - || javaId.contains("minecraft:bubble_column") || javaId.contains("minecraft:kelp") || javaId.contains("seagrass"); - - if (waterlogged) { - WATERLOGGED.add(javaRuntimeId); - } - - JAVA_ID_BLOCK_MAP.put(javaId, javaRuntimeId); - - BlockStateValues.storeBlockStateValues(entry.getKey(), javaRuntimeId, entry.getValue()); - - String cleanJavaIdentifier = entry.getKey().split("\\[")[0]; - String bedrockIdentifier = entry.getValue().get("bedrock_identifier").asText(); - - if (!JAVA_ID_TO_JAVA_IDENTIFIER_MAP.containsValue(cleanJavaIdentifier)) { - uniqueJavaId++; - JAVA_ID_TO_JAVA_IDENTIFIER_MAP.put(uniqueJavaId, cleanJavaIdentifier); - } - - // Keeping this here since this is currently unchanged between versions - if (!cleanJavaIdentifier.equals(bedrockIdentifier)) { - JAVA_TO_BEDROCK_IDENTIFIERS.put(cleanJavaIdentifier, bedrockIdentifier); - } - - builder.javaBlockId(uniqueJavaId); - - builder.javaIdentifier(javaId); - - JAVA_RUNTIME_ID_TO_BLOCK_MAPPING.put(javaRuntimeId, builder.build()); - - if (javaId.startsWith("minecraft:bell[")) { - bellBlockId = uniqueJavaId; - - } else if (javaId.contains("cobweb")) { - cobwebBlockId = uniqueJavaId; - - } else if (javaId.startsWith("minecraft:furnace[facing=north")) { - if (javaId.contains("lit=true")) { - furnaceLitRuntimeId = javaRuntimeId; - } else { - furnaceRuntimeId = javaRuntimeId; - } - - } else if (javaId.startsWith("minecraft:spawner")) { - spawnerRuntimeId = javaRuntimeId; - - } else if ("minecraft:water[level=0]".equals(javaId)) { - waterRuntimeId = javaRuntimeId; - } - } - - if (bellBlockId == -1) { - throw new AssertionError("Unable to find bell in palette"); - } - JAVA_BELL_BLOCK_ID = bellBlockId; - - if (cobwebBlockId == -1) { - throw new AssertionError("Unable to find cobwebs in palette"); - } - JAVA_COBWEB_BLOCK_ID = cobwebBlockId; - - if (furnaceRuntimeId == -1) { - throw new AssertionError("Unable to find furnace in palette"); - } - JAVA_RUNTIME_FURNACE_ID = furnaceRuntimeId; - - if (furnaceLitRuntimeId == -1) { - throw new AssertionError("Unable to find lit furnace in palette"); - } - JAVA_RUNTIME_FURNACE_LIT_ID = furnaceLitRuntimeId; - - if (spawnerRuntimeId == -1) { - throw new AssertionError("Unable to find spawner in palette"); - } - JAVA_RUNTIME_SPAWNER_ID = spawnerRuntimeId; - - if (waterRuntimeId == -1) { - throw new AssertionError("Unable to find Java water in palette"); - } - JAVA_WATER_ID = waterRuntimeId; - - BlockMapping.AIR = JAVA_RUNTIME_ID_TO_BLOCK_MAPPING.get(JAVA_AIR_ID); - - BlockTranslator1_17_0.init(); - BLOCKS_JSON = null; // We no longer require this so let it garbage collect away - } - - public BlockTranslator(String paletteFile) { - /* Load block palette */ - InputStream stream = FileUtils.getResource(paletteFile); - - NbtList blocksTag; - try (NBTInputStream nbtInputStream = new NBTInputStream(new DataInputStream(new GZIPInputStream(stream)))) { - NbtMap blockPalette = (NbtMap) nbtInputStream.readTag(); - blocksTag = (NbtList) blockPalette.getList("blocks", NbtType.COMPOUND); - this.bedrockBlockStates = blocksTag; - } catch (Exception e) { - throw new AssertionError("Unable to get blocks from runtime block states", e); - } - - javaIdentifierToBedrockTag = new Object2ObjectOpenHashMap<>(); - - // New since 1.16.100 - find the block runtime ID by the order given to us in the block palette, - // as we no longer send a block palette - Object2IntMap blockStateOrderedMap = new Object2IntOpenHashMap<>(blocksTag.size()); - - for (int i = 0; i < blocksTag.size(); i++) { - NbtMap tag = blocksTag.get(i); - if (blockStateOrderedMap.containsKey(tag)) { - throw new AssertionError("Duplicate block states in Bedrock palette: " + tag); - } - blockStateOrderedMap.put(tag, i); - } - - int airRuntimeId = -1; - int commandBlockRuntimeId = -1; - int javaRuntimeId = -1; - int waterRuntimeId = -1; - Iterator> blocksIterator = BLOCKS_JSON.fields(); - while (blocksIterator.hasNext()) { - javaRuntimeId++; - Map.Entry entry = blocksIterator.next(); - String javaId = entry.getKey(); - - NbtMap blockTag = buildBedrockState(entry.getValue()); - int bedrockRuntimeId = blockStateOrderedMap.getOrDefault(blockTag, -1); - if (bedrockRuntimeId == -1) { - throw new RuntimeException("Unable to find " + javaId + " Bedrock runtime ID! Built compound tag: \n" + blockTag); - } - - switch (javaId) { - case "minecraft:air": - airRuntimeId = bedrockRuntimeId; - break; - case "minecraft:water[level=0]": - waterRuntimeId = bedrockRuntimeId; - break; - case "minecraft:command_block[conditional=false,facing=north]": - commandBlockRuntimeId = bedrockRuntimeId; - break; - } - - boolean waterlogged = entry.getKey().contains("waterlogged=true") - || javaId.contains("minecraft:bubble_column") || javaId.contains("minecraft:kelp") || javaId.contains("seagrass"); - - if (waterlogged) { - bedrockToJavaBlockMap.putIfAbsent(bedrockRuntimeId | 1 << 31, javaRuntimeId); - } else { - bedrockToJavaBlockMap.putIfAbsent(bedrockRuntimeId, javaRuntimeId); - } - - String cleanJavaIdentifier = entry.getKey().split("\\[")[0]; - - // Get the tag needed for non-empty flower pots - if (entry.getValue().get("pottable") != null) { - flowerPotBlocks.put(cleanJavaIdentifier, blockTag); - } - - if (!cleanJavaIdentifier.equals(entry.getValue().get("bedrock_identifier").asText())) { - javaIdentifierToBedrockTag.put(cleanJavaIdentifier, blockTag); - } - - javaToBedrockBlockMap.put(javaRuntimeId, bedrockRuntimeId); - } - - if (commandBlockRuntimeId == -1) { - throw new AssertionError("Unable to find command block in palette"); - } - bedrockRuntimeCommandBlockId = commandBlockRuntimeId; - - if (waterRuntimeId == -1) { - throw new AssertionError("Unable to find water in palette"); - } - bedrockWaterId = waterRuntimeId; - - if (airRuntimeId == -1) { - throw new AssertionError("Unable to find air in palette"); - } - bedrockAirId = airRuntimeId; - - // Loop around again to find all item frame runtime IDs - for (Object2IntMap.Entry entry : blockStateOrderedMap.object2IntEntrySet()) { - String name = entry.getKey().getString("name"); - if (name.equals("minecraft:frame") || name.equals("minecraft:glow_frame")) { - itemFrames.put(entry.getKey(), entry.getIntValue()); - } - } - - this.emptyChunkProvider = new EmptyChunkProvider(bedrockAirId); - } - - public static void init() { - // no-op - } - - private NbtMap buildBedrockState(JsonNode node) { - NbtMapBuilder tagBuilder = NbtMap.builder(); - String bedrockIdentifier = node.get("bedrock_identifier").textValue(); - tagBuilder.putString("name", bedrockIdentifier) - .putInt("version", getBlockStateVersion()); - - NbtMapBuilder statesBuilder = NbtMap.builder(); - - // check for states - if (node.has("bedrock_states")) { - Iterator> statesIterator = node.get("bedrock_states").fields(); - - while (statesIterator.hasNext()) { - Map.Entry stateEntry = statesIterator.next(); - JsonNode stateValue = stateEntry.getValue(); - switch (stateValue.getNodeType()) { - case BOOLEAN: - statesBuilder.putBoolean(stateEntry.getKey(), stateValue.booleanValue()); - continue; - case STRING: - statesBuilder.putString(stateEntry.getKey(), stateValue.textValue()); - continue; - case NUMBER: - statesBuilder.putInt(stateEntry.getKey(), stateValue.intValue()); - } - } - } - tagBuilder.put("states", adjustBlockStateForVersion(bedrockIdentifier, statesBuilder).build()); - return tagBuilder.build(); - } - - /** - * @return an adjusted state list, if necessary, that converts Geyser's new mapping to Bedrock's older version - * of the mapping. - */ - protected NbtMapBuilder adjustBlockStateForVersion(String bedrockIdentifier, NbtMapBuilder statesBuilder) { - return statesBuilder; - } - - public int getBedrockBlockId(int state) { - return javaToBedrockBlockMap.get(state); - } - - public int getJavaBlockState(int bedrockId) { - return bedrockToJavaBlockMap.get(bedrockId); - } - - /** - * @param javaIdentifier the Java identifier of the block to search for - * @return the Bedrock identifier if different, or else the Java identifier - */ - public String getBedrockBlockIdentifier(String javaIdentifier) { - return JAVA_TO_BEDROCK_IDENTIFIERS.getOrDefault(javaIdentifier, javaIdentifier); - } - - public int getItemFrame(NbtMap tag) { - return itemFrames.getOrDefault(tag, -1); - } - - public boolean isItemFrame(int bedrockBlockRuntimeId) { - return itemFrames.values().contains(bedrockBlockRuntimeId); - } - - /** - * Get the map of contained flower pot plants to Bedrock CompoundTag - * - * @return Map of flower pot blocks. - */ - public Map getFlowerPotBlocks() { - return flowerPotBlocks; - } - - public int getBedrockAirId() { - return bedrockAirId; - } - - public int getBedrockWaterId() { - return bedrockWaterId; - } - - public NbtList getAllBedrockBlockStates() { - return this.bedrockBlockStates; - } - - /** - * @return the "block state version" generated in the Bedrock block palette that completes an NBT indication of a - * block state. - */ - public abstract int getBlockStateVersion(); - - public byte[] getEmptyChunkData() { - return emptyChunkProvider.getEmptyLevelChunkData(); - } - - public ChunkSection getEmptyChunkSection() { - return emptyChunkProvider.getEmptySection(); - } - - /** - * @param javaId the Java string identifier to search for - * @return the Java block state integer, or {@link #JAVA_AIR_ID} if there is no valid entry. - */ - public static int getJavaBlockState(String javaId) { - return JAVA_ID_BLOCK_MAP.getOrDefault(javaId, JAVA_AIR_ID); - } - - public static boolean isWaterlogged(int state) { - return WATERLOGGED.contains(state); - } - - public static BiMap getJavaIdBlockMap() { - return JAVA_ID_BLOCK_MAP; - } - - /** - * @param javaRuntimeId the Java runtime ID of the block to search for. - * @return the corresponding block mapping for this runtime ID. - */ - public static BlockMapping getBlockMapping(int javaRuntimeId) { - return JAVA_RUNTIME_ID_TO_BLOCK_MAPPING.getOrDefault(javaRuntimeId, BlockMapping.AIR); - } - - /** - * @return a list of all Java block identifiers. For use with command suggestions. - */ - public static String[] getAllBlockIdentifiers() { - return JAVA_ID_TO_JAVA_IDENTIFIER_MAP.values().toArray(new String[0]); - } - - /** - * @param cleanJavaIdentifier the clean Java identifier of the block to look up - * - * @return the block tag of the block name mapped from Java to Bedrock. - */ - public NbtMap getBedrockBlockNbt(String cleanJavaIdentifier) { - return javaIdentifierToBedrockTag.get(cleanJavaIdentifier); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java index 983a3d06d..41843e96a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java @@ -31,69 +31,15 @@ import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.utils.BlockEntityUtils; -import org.geysermc.connector.utils.FileUtils; -import org.reflections.Reflections; - -import java.util.HashMap; -import java.util.Map; /** * The class that all block entities (on both Java and Bedrock) should translate with */ public abstract class BlockEntityTranslator { - public static final Map BLOCK_ENTITY_TRANSLATORS = new HashMap<>(); - /** - * A list of all block entities that only exist on Bedrock - */ - public static final ObjectArrayList BEDROCK_ONLY_BLOCK_ENTITIES = new ObjectArrayList<>(); - - /** - * Contains a list of irregular block entity name translations that can't be fit into the regex - */ - public static final Map BLOCK_ENTITY_TRANSLATIONS = new HashMap() { - { - // Bedrock/Java differences - put("minecraft:enchanting_table", "EnchantTable"); - put("minecraft:jigsaw", "JigsawBlock"); - put("minecraft:piston_head", "PistonArm"); - put("minecraft:trapped_chest", "Chest"); - // There are some legacy IDs sent but as far as I can tell they are not needed for things to work properly - } - }; - protected BlockEntityTranslator() { } - public static void init() { - // no-op - } - - static { - Reflections ref = GeyserConnector.getInstance().useXmlReflections() ? FileUtils.getReflections("org.geysermc.connector.network.translators.world.block.entity") : new Reflections("org.geysermc.connector.network.translators.world.block.entity"); - for (Class clazz : ref.getTypesAnnotatedWith(BlockEntity.class)) { - GeyserConnector.getInstance().getLogger().debug("Found annotated block entity: " + clazz.getCanonicalName()); - - try { - BLOCK_ENTITY_TRANSLATORS.put(clazz.getAnnotation(BlockEntity.class).name(), (BlockEntityTranslator) clazz.newInstance()); - } catch (InstantiationException | IllegalAccessException e) { - GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated block entity" + clazz.getCanonicalName()); - } - } - for (Class clazz : ref.getSubTypesOf(BedrockOnlyBlockEntity.class)) { - GeyserConnector.getInstance().getLogger().debug("Found Bedrock-only block entity: " + clazz.getCanonicalName()); - - try { - BedrockOnlyBlockEntity bedrockOnlyBlockEntity = (BedrockOnlyBlockEntity) clazz.newInstance(); - BEDROCK_ONLY_BLOCK_ENTITIES.add(bedrockOnlyBlockEntity); - } catch (InstantiationException | IllegalAccessException e) { - GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated block state " + clazz.getCanonicalName()); - } - } - } - public abstract void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState); public NbtMap getBlockEntityTag(String id, CompoundTag tag, int blockState) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CampfireBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CampfireBlockEntityTranslator.java index 40f305ad6..88bb14203 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CampfireBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CampfireBlockEntityTranslator.java @@ -29,8 +29,9 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; +import org.geysermc.connector.network.BedrockProtocol; +import org.geysermc.connector.registry.Registries; +import org.geysermc.connector.registry.type.ItemMapping; @BlockEntity(name = "Campfire") public class CampfireBlockEntityTranslator extends BlockEntityTranslator { @@ -45,11 +46,12 @@ public class CampfireBlockEntityTranslator extends BlockEntityTranslator { } protected NbtMap getItem(CompoundTag tag) { - ItemEntry entry = ItemRegistry.getItemEntry((String) tag.get("id").getValue()); + // TODO: Version independent mappings + ItemMapping mapping = Registries.ITEMS.forVersion(BedrockProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()).getMapping((String) tag.get("id").getValue()); NbtMapBuilder tagBuilder = NbtMap.builder() - .putString("Name", entry.getBedrockIdentifier()) + .putString("Name", mapping.getBedrockIdentifier()) .putByte("Count", (byte) tag.get("Count").getValue()) - .putShort("Damage", (short) entry.getBedrockData()); + .putShort("Damage", (short) mapping.getBedrockData()); tagBuilder.put("tag", NbtMap.builder().build()); return tagBuilder.build(); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/FlowerPotBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/FlowerPotBlockEntityTranslator.java index 1fa6cab02..833542543 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/FlowerPotBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/FlowerPotBlockEntityTranslator.java @@ -61,7 +61,7 @@ public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity { if (name != null) { // Get the Bedrock CompoundTag of the block. // This is where we need to store the *Java* name because Bedrock has six minecraft:sapling blocks with different block states. - NbtMap plant = session.getBlockTranslator().getFlowerPotBlocks().get(name); + NbtMap plant = session.getBlockMappings().getFlowerPotBlocks().get(name); if (plant != null) { tagBuilder.put("PlantBlock", plant.toBuilder().build()); } @@ -80,7 +80,7 @@ public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity { BlockEntityUtils.updateBlockEntity(session, tag, position); UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); updateBlockPacket.setDataLayer(0); - updateBlockPacket.setRuntimeId(session.getBlockTranslator().getBedrockBlockId(blockState)); + updateBlockPacket.setRuntimeId(session.getBlockMappings().getBedrockBlockId(blockState)); updateBlockPacket.setBlockPosition(position); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SignBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SignBlockEntityTranslator.java index ad6c32d4f..0551386c5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SignBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SignBlockEntityTranslator.java @@ -34,69 +34,72 @@ import org.geysermc.connector.utils.SignUtils; @BlockEntity(name = "Sign") public class SignBlockEntityTranslator extends BlockEntityTranslator { /** - * Maps a color stored in a sign's Color tag to a Bedrock Edition formatting code. - *
- * The color names correspond to dye names, because of this we can't use a more global method. + * Maps a color stored in a sign's Color tag to its ARGB value. * * @param javaColor The dye color stored in the sign's Color tag. - * @return A Bedrock Edition formatting code for valid dye colors, otherwise an empty string. + * @return Java Edition's integer matching the color specified */ - private String getBedrockSignColor(String javaColor) { - String base = "\u00a7"; + private int getBedrockSignColor(String javaColor) { + //TODO create a DyeColor class and combine with FireworkColor??? + int dyeColor; switch (javaColor) { case "white": - base += 'f'; + dyeColor = 16383998; break; case "orange": - base += '6'; + dyeColor = 16351261; break; case "magenta": - case "purple": - base += '5'; + dyeColor = 13061821; break; case "light_blue": - base += 'b'; + dyeColor = 3847130; break; case "yellow": - base += 'e'; + dyeColor = 16701501; break; case "lime": - base += 'a'; + dyeColor = 8439583; break; case "pink": - base += 'd'; + dyeColor = 15961002; break; case "gray": - base += '8'; + dyeColor = 4673362; break; case "light_gray": - base += '7'; + dyeColor = 10329495; break; case "cyan": - base += '3'; + dyeColor = 1481884; + break; + case "purple": + dyeColor = 8991416; break; case "blue": - base += '9'; + dyeColor = 3949738; break; - case "brown": // Brown does not have a bedrock counterpart. - case "red": // In Java Edition light red (&c) can only be applied using commands. Red dye gives &4. - base += '4'; + case "brown": + dyeColor = 8606770; break; case "green": - base += '2'; + dyeColor = 6192150; + break; + case "red": + dyeColor = 11546150; break; case "black": - base += '0'; - break; default: - return ""; + // The proper Java color is 1908001, but this does not render well with glow text. + dyeColor = 0; + break; } - return base; + // Add the transparency of the color, too. + return dyeColor | (255 << 24); } @Override public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - //TODO Bedrock 1.17.10 glow text StringBuilder signText = new StringBuilder(); for (int i = 0; i < 4; i++) { int currentLine = i + 1; @@ -127,16 +130,21 @@ public class SignBlockEntityTranslator extends BlockEntityTranslator { } } - // Java Edition 1.14 added the ability to change the text color of the whole sign using dye - Tag color = tag.get("Color"); - if (color != null) { - signText.append(getBedrockSignColor(color.getValue().toString())); - } - signText.append(finalSignLine); signText.append("\n"); } - builder.put("Text", signText.toString()); + builder.putString("Text", signText.toString()); + + // Java Edition 1.14 added the ability to change the text color of the whole sign using dye + Tag color = tag.get("Color"); + if (color != null) { + builder.putInt("SignTextColor", getBedrockSignColor(color.getValue().toString())); + } + + // Glowing text + boolean isGlowing = getOrDefault(tag.getValue().get("GlowingText"), (byte) 0) != (byte) 0; + builder.putBoolean("IgnoreLighting", isGlowing); + builder.putBoolean("TextIgnoreLegacyBugResolved", isGlowing); // ??? required } } diff --git a/connector/src/main/java/org/geysermc/connector/registry/AbstractMappedRegistry.java b/connector/src/main/java/org/geysermc/connector/registry/AbstractMappedRegistry.java new file mode 100644 index 000000000..034eef706 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/AbstractMappedRegistry.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry; + +import org.geysermc.connector.registry.loader.RegistryLoader; + +import java.util.Map; + +public abstract class AbstractMappedRegistry> extends Registry { + protected AbstractMappedRegistry(I input, RegistryLoader registryLoader) { + super(input, registryLoader); + } + + public V get(K key) { + return this.mappings.get(key); + } + + public V getOrDefault(K key, V defaultValue) { + return this.mappings.getOrDefault(key, defaultValue); + } + + public V register(K key, V value) { + return this.mappings.put(key, value); + } +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/registry/BlockRegistries.java b/connector/src/main/java/org/geysermc/connector/registry/BlockRegistries.java new file mode 100644 index 000000000..bc92f4b93 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/BlockRegistries.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.geysermc.connector.registry.loader.RegistryLoaders; +import org.geysermc.connector.registry.populator.BlockRegistryPopulator; +import org.geysermc.connector.registry.type.BlockMapping; +import org.geysermc.connector.registry.type.BlockMappings; + +public class BlockRegistries { + public static final VersionedRegistry BLOCKS = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); + + public static final SimpleMappedRegistry JAVA_TO_BEDROCK_IDENTIFIERS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new)); + + public static final SimpleMappedRegistry JAVA_BLOCKS = SimpleMappedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); + + public static final MappedRegistry> JAVA_IDENTIFIERS = MappedRegistry.create(RegistryLoaders.empty(HashBiMap::create)); + + public static final SimpleMappedRegistry JAVA_CLEAN_IDENTIFIERS = SimpleMappedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); + + public static final SimpleRegistry WATERLOGGED = SimpleRegistry.create(RegistryLoaders.empty(IntOpenHashSet::new)); + + static { + BlockRegistryPopulator.populate(); + } + + public static void init() { + // no-op + } +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/registry/MappedRegistry.java b/connector/src/main/java/org/geysermc/connector/registry/MappedRegistry.java new file mode 100644 index 000000000..41d831f98 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/MappedRegistry.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry; + +import org.geysermc.connector.registry.loader.RegistryLoader; + +import java.util.Map; +import java.util.function.Supplier; + +public class MappedRegistry> extends AbstractMappedRegistry { + protected MappedRegistry(I input, RegistryLoader registryLoader) { + super(input, registryLoader); + } + + public static > MappedRegistry createEmpty() { + return new MappedRegistry<>(null, input -> null); + } + + public static > MappedRegistry create(RegistryLoader registryLoader) { + return new MappedRegistry<>(null, registryLoader); + } + + public static > MappedRegistry create(I input, RegistryLoader registryLoader) { + return new MappedRegistry<>(input, registryLoader); + } + + public static > MappedRegistry create(Supplier> registryLoader) { + return new MappedRegistry<>(null, registryLoader.get()); + } + + public static > MappedRegistry create(I input, Supplier> registryLoader) { + return new MappedRegistry<>(input, registryLoader.get()); + } +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/registry/Registries.java b/connector/src/main/java/org/geysermc/connector/registry/Registries.java new file mode 100644 index 000000000..cb23e9976 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/Registries.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry; + +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.world.effect.SoundEffect; +import com.github.steveice10.mc.protocol.data.game.world.particle.ParticleType; +import com.nukkitx.nbt.NbtMap; +import com.nukkitx.protocol.bedrock.data.SoundEvent; +import com.nukkitx.protocol.bedrock.data.inventory.CraftingData; +import com.nukkitx.protocol.bedrock.data.inventory.PotionMixData; +import it.unimi.dsi.fastutil.Pair; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; +import org.geysermc.connector.network.translators.collision.translators.BlockCollision; +import org.geysermc.connector.network.translators.effect.Effect; +import org.geysermc.connector.network.translators.sound.SoundHandler; +import org.geysermc.connector.network.translators.sound.SoundInteractionHandler; +import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator; +import org.geysermc.connector.registry.loader.BlockEntityRegistryLoader; +import org.geysermc.connector.registry.loader.CollisionRegistryLoader; +import org.geysermc.connector.registry.loader.ParticleTypesRegistryLoader; +import org.geysermc.connector.registry.loader.PotionMixRegistryLoader; +import org.geysermc.connector.registry.loader.RegistryLoaders; +import org.geysermc.connector.registry.loader.SoundEffectsRegistryLoader; +import org.geysermc.connector.registry.loader.SoundHandlerRegistryLoader; +import org.geysermc.connector.registry.loader.SoundRegistryLoader; +import org.geysermc.connector.registry.populator.ItemRegistryPopulator; +import org.geysermc.connector.registry.populator.RecipeRegistryPopulator; +import org.geysermc.connector.registry.type.ItemMappings; +import org.geysermc.connector.registry.type.ParticleMapping; +import org.geysermc.connector.registry.type.SoundMapping; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class Registries { + public static final SimpleRegistry BIOMES = SimpleRegistry.create("bedrock/biome_definitions.dat", RegistryLoaders.NBT); + + public static final SimpleMappedRegistry BLOCK_ENTITIES = SimpleMappedRegistry.create("org.geysermc.connector.network.translators.world.block.entity", BlockEntityRegistryLoader::new); + + public static final SimpleMappedRegistry COLLISIONS = SimpleMappedRegistry.create(Pair.of("org.geysermc.connector.network.translators.collision.translators", "mappings/collision.json"), CollisionRegistryLoader::new); + + public static final VersionedRegistry>> CRAFTING_DATA = VersionedRegistry.create(RegistryLoaders.empty(Object2ObjectLinkedOpenHashMap::new)); + + public static final SimpleRegistry ENTITY_IDENTIFIERS = SimpleRegistry.create("bedrock/entity_identifiers.dat", RegistryLoaders.NBT); + + public static final VersionedRegistry ITEMS = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); + + public static final SimpleMappedRegistry PARTICLES = SimpleMappedRegistry.create("mappings/particles.json", ParticleTypesRegistryLoader::new); + + public static final SimpleRegistry> POTION_MIXES; + + public static final VersionedRegistry> RECIPES = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); + + public static final SimpleMappedRegistry RECORDS = SimpleMappedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); + + public static final SimpleMappedRegistry SOUNDS = SimpleMappedRegistry.create("mappings/sounds.json", SoundRegistryLoader::new); + + public static final SimpleMappedRegistry SOUND_EFFECTS = SimpleMappedRegistry.create("mappings/effects.json", SoundEffectsRegistryLoader::new); + + public static final SimpleMappedRegistry> SOUND_HANDLERS = SimpleMappedRegistry.create("org.geysermc.connector.network.translators.sound", SoundHandlerRegistryLoader::new); + + public static void init() { + // no-op + } + + static { + ItemRegistryPopulator.populate(); + RecipeRegistryPopulator.populate(); + + // Create registries that require other registries to load first + POTION_MIXES = SimpleRegistry.create(PotionMixRegistryLoader::new); + } +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/registry/Registry.java b/connector/src/main/java/org/geysermc/connector/registry/Registry.java new file mode 100644 index 000000000..ca3d22373 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/Registry.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry; + +import org.geysermc.connector.registry.loader.RegistryLoader; + +import java.util.function.Consumer; + +public abstract class Registry { + protected final M mappings; + + protected Registry(I input, RegistryLoader registryLoader) { + this.mappings = registryLoader.load(input); + } + + public M get() { + return this.mappings; + } + + public void register(Consumer consumer) { + consumer.accept(this.mappings); + } +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/registry/SimpleMappedRegistry.java b/connector/src/main/java/org/geysermc/connector/registry/SimpleMappedRegistry.java new file mode 100644 index 000000000..1188b3590 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/SimpleMappedRegistry.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry; + +import org.geysermc.connector.registry.loader.RegistryLoader; + +import java.util.Map; +import java.util.function.Supplier; + +public class SimpleMappedRegistry extends AbstractMappedRegistry> { + protected SimpleMappedRegistry(I input, RegistryLoader> registryLoader) { + super(input, registryLoader); + } + + public static SimpleMappedRegistry create(RegistryLoader> registryLoader) { + return new SimpleMappedRegistry<>(null, registryLoader); + } + + public static SimpleMappedRegistry create(I input, RegistryLoader> registryLoader) { + return new SimpleMappedRegistry<>(input, registryLoader); + } + + public static SimpleMappedRegistry create(Supplier>> registryLoader) { + return new SimpleMappedRegistry<>(null, registryLoader.get()); + } + + public static SimpleMappedRegistry create(I input, Supplier>> registryLoader) { + return new SimpleMappedRegistry<>(input, registryLoader.get()); + } +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/registry/SimpleRegistry.java b/connector/src/main/java/org/geysermc/connector/registry/SimpleRegistry.java new file mode 100644 index 000000000..1bea97954 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/SimpleRegistry.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry; + +import org.geysermc.connector.registry.loader.RegistryLoader; + +import java.util.function.Supplier; + +public class SimpleRegistry extends Registry { + private SimpleRegistry(I input, RegistryLoader registryLoader) { + super(input, registryLoader); + } + + public static SimpleRegistry create(Supplier> registryLoader) { + return new SimpleRegistry<>(null, registryLoader.get()); + } + + public static SimpleRegistry create(I input, Supplier> registryLoader) { + return new SimpleRegistry<>(input, registryLoader.get()); + } + + public static SimpleRegistry create(RegistryLoader registryLoader) { + return new SimpleRegistry<>(null, registryLoader); + } + + public static SimpleRegistry create(I input, RegistryLoader registryLoader) { + return new SimpleRegistry<>(input, registryLoader); + } +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/registry/VersionedRegistry.java b/connector/src/main/java/org/geysermc/connector/registry/VersionedRegistry.java new file mode 100644 index 000000000..d29bcddaa --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/VersionedRegistry.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry; + +import org.geysermc.connector.registry.loader.RegistryLoader; + +import java.util.Map; +import java.util.function.Supplier; + +public class VersionedRegistry extends AbstractMappedRegistry> { + protected VersionedRegistry(I input, RegistryLoader> registryLoader) { + super(input, registryLoader); + } + + public V forVersion(int version) { + V value = null; + for (Map.Entry entry : this.mappings.entrySet()) { + if (version < entry.getKey()) { + continue; + } + if (version == entry.getKey()) { + return entry.getValue(); + } + value = entry.getValue(); + } + return value; + } + + public static VersionedRegistry create(RegistryLoader> registryLoader) { + return new VersionedRegistry<>(null, registryLoader); + } + + public static VersionedRegistry create(I input, RegistryLoader> registryLoader) { + return new VersionedRegistry<>(input, registryLoader); + } + + public static VersionedRegistry< V> create(Supplier>> registryLoader) { + return new VersionedRegistry<>(null, registryLoader.get()); + } + + public static VersionedRegistry< V> create(I input, Supplier>> registryLoader) { + return new VersionedRegistry<>(input, registryLoader.get()); + } +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundHandlerRegistry.java b/connector/src/main/java/org/geysermc/connector/registry/loader/AnnotatedRegistryLoader.java similarity index 57% rename from connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundHandlerRegistry.java rename to connector/src/main/java/org/geysermc/connector/registry/loader/AnnotatedRegistryLoader.java index 6cfb97675..4f6354af5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundHandlerRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/registry/loader/AnnotatedRegistryLoader.java @@ -23,48 +23,37 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.sound; +package org.geysermc.connector.registry.loader; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.utils.FileUtils; import org.reflections.Reflections; -import java.util.HashMap; +import java.lang.annotation.Annotation; import java.util.Map; +import java.util.function.Function; -/** - * Registry that holds {@link SoundInteractionHandler}s. - */ -public class SoundHandlerRegistry { +public class AnnotatedRegistryLoader implements RegistryLoader> { + private final Class annotation; + private final Function mapper; - static final Map> INTERACTION_HANDLERS = new HashMap<>(); + public AnnotatedRegistryLoader(Class annotation, Function mapper) { + this.annotation = annotation; + this.mapper = mapper; + } - static { - Reflections ref = GeyserConnector.getInstance().useXmlReflections() ? FileUtils.getReflections("org.geysermc.connector.network.translators.sound") : new Reflections("org.geysermc.connector.network.translators.sound"); - for (Class clazz : ref.getTypesAnnotatedWith(SoundHandler.class)) { + @Override + public Map load(String input) { + Map entries = new Object2ObjectOpenHashMap<>(); + Reflections ref = GeyserConnector.getInstance().useXmlReflections() ? FileUtils.getReflections(input) : new Reflections(input); + for (Class clazz : ref.getTypesAnnotatedWith(this.annotation)) { try { - SoundInteractionHandler interactionHandler = (SoundInteractionHandler) clazz.newInstance(); - SoundHandler annotation = clazz.getAnnotation(SoundHandler.class); - INTERACTION_HANDLERS.put(annotation, interactionHandler); + entries.put(this.mapper.apply(clazz.getAnnotation(this.annotation)), (V) clazz.newInstance()); } catch (InstantiationException | IllegalAccessException ex) { ex.printStackTrace(); } } + return entries; } - - private SoundHandlerRegistry() { - } - - public static void init() { - // no-op - } - - /** - * Returns a map of the interaction handlers - * - * @return a map of the interaction handlers - */ - public static Map> getInteractionHandlers() { - return INTERACTION_HANDLERS; - } -} +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/registry/loader/BlockEntityRegistryLoader.java b/connector/src/main/java/org/geysermc/connector/registry/loader/BlockEntityRegistryLoader.java new file mode 100644 index 000000000..6824d611d --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/loader/BlockEntityRegistryLoader.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry.loader; + +import org.geysermc.connector.network.translators.world.block.entity.BlockEntity; +import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator; + +public class BlockEntityRegistryLoader extends AnnotatedRegistryLoader { + public BlockEntityRegistryLoader() { + super(BlockEntity.class, BlockEntity::name); + } +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/collision/CollisionTranslator.java b/connector/src/main/java/org/geysermc/connector/registry/loader/CollisionRegistryLoader.java similarity index 78% rename from connector/src/main/java/org/geysermc/connector/network/translators/collision/CollisionTranslator.java rename to connector/src/main/java/org/geysermc/connector/registry/loader/CollisionRegistryLoader.java index e5cf52bc8..a60dfdbca 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/collision/CollisionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/registry/loader/CollisionRegistryLoader.java @@ -23,36 +23,41 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.collision; +package org.geysermc.connector.registry.loader; import com.fasterxml.jackson.databind.node.ArrayNode; import com.google.common.collect.BiMap; +import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.collision.BoundingBox; +import org.geysermc.connector.network.translators.collision.CollisionRemapper; import org.geysermc.connector.network.translators.collision.translators.BlockCollision; import org.geysermc.connector.network.translators.collision.translators.EmptyCollision; import org.geysermc.connector.network.translators.collision.translators.OtherCollision; import org.geysermc.connector.network.translators.collision.translators.SolidCollision; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.registry.BlockRegistries; import org.geysermc.connector.utils.FileUtils; import org.reflections.Reflections; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.regex.Pattern; -public class CollisionTranslator { - private static final Int2ObjectMap COLLISION_MAP = new Int2ObjectOpenHashMap<>(); +public class CollisionRegistryLoader extends MultiResourceRegistryLoader> { + + @Override + public Map load(Pair input) { + Int2ObjectMap collisions = new Int2ObjectOpenHashMap<>(); - public static void init() { List> collisionTypes = new ArrayList<>(); - Map, CollisionRemapper> annotationMap = new HashMap<>(); - - Reflections ref = GeyserConnector.getInstance().useXmlReflections() ? FileUtils.getReflections("org.geysermc.connector.network.translators.collision.translators") : new Reflections("org.geysermc.connector.network.translators.collision.translators"); + Reflections ref = GeyserConnector.getInstance().useXmlReflections() ? FileUtils.getReflections(input.key()) : new Reflections(input.key()); for (Class clazz : ref.getTypesAnnotatedWith(CollisionRemapper.class)) { GeyserConnector.getInstance().getLogger().debug("Found annotated collision translator: " + clazz.getCanonicalName()); @@ -61,7 +66,7 @@ public class CollisionTranslator { } // Load collision mappings file - InputStream stream = FileUtils.getResource("mappings/collision.json"); + InputStream stream = FileUtils.getResource(input.value()); ArrayNode collisionList; try { @@ -70,28 +75,28 @@ public class CollisionTranslator { throw new AssertionError("Unable to load collision data", e); } - BiMap javaIdBlockMap = BlockTranslator.getJavaIdBlockMap(); + BiMap javaIdBlockMap = BlockRegistries.JAVA_IDENTIFIERS.get(); // Map of classes that don't change based on parameters that have already been created Map, BlockCollision> instantiatedCollision = new HashMap<>(); - for (Map.Entry entry : javaIdBlockMap.entrySet()) { BlockCollision newCollision = instantiateCollision(entry.getKey(), entry.getValue(), collisionTypes, annotationMap, instantiatedCollision, collisionList); if (newCollision != null) { instantiatedCollision.put(newCollision.getClass(), newCollision); } - COLLISION_MAP.put(entry.getValue().intValue(), newCollision); + collisions.put(entry.getValue().intValue(), newCollision); } + return collisions; } - private static BlockCollision instantiateCollision(String blockID, int numericBlockID, List> collisionTypes, Map, CollisionRemapper> annotationMap, Map, BlockCollision> instantiatedCollision, ArrayNode collisionList) { + private BlockCollision instantiateCollision(String blockID, int numericBlockID, List> collisionTypes, Map, CollisionRemapper> annotationMap, Map, BlockCollision> instantiatedCollision, ArrayNode collisionList) { String blockName = blockID.split("\\[")[0].replace("minecraft:", ""); String params = ""; if (blockID.contains("[")) { params = "[" + blockID.split("\\[")[1]; } - int collisionIndex = BlockTranslator.getBlockMapping(numericBlockID).getCollisionIndex(); + int collisionIndex = BlockRegistries.JAVA_BLOCKS.get(numericBlockID).getCollisionIndex(); for (Class type : collisionTypes) { CollisionRemapper annotation = annotationMap.get(type); @@ -163,25 +168,4 @@ public class CollisionTranslator { return collision; } - - // Note: these reuse classes, so don't try to store more than once instance or coordinates will get overwritten - - public static BlockCollision getCollision(int blockID, int x, int y, int z) { - BlockCollision collision = COLLISION_MAP.get(blockID); - if (collision != null) { - collision.setPosition(x, y, z); - } - return collision; - } - - - public static BlockCollision getCollisionAt(GeyserSession session, int x, int y, int z) { - try { - return getCollision(session.getConnector().getWorldManager().getBlockAt(session, x, y, z), x, y, z); - } catch (ArrayIndexOutOfBoundsException e) { - // Block out of world - return null; - } - } - } \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/registry/loader/EffectRegistryLoader.java b/connector/src/main/java/org/geysermc/connector/registry/loader/EffectRegistryLoader.java new file mode 100644 index 000000000..5e9e435f3 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/loader/EffectRegistryLoader.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry.loader; + +import com.fasterxml.jackson.databind.JsonNode; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.utils.FileUtils; + +import java.io.InputStream; +import java.util.Map; +import java.util.WeakHashMap; + +public abstract class EffectRegistryLoader implements RegistryLoader { + private static final Map loadedFiles = new WeakHashMap<>(); + + public void loadFile(String input) { + if (!loadedFiles.containsKey(input)) { + InputStream effectsStream = FileUtils.getResource(input); + JsonNode effects; + try { + effects = GeyserConnector.JSON_MAPPER.readTree(effectsStream); + } catch (Exception e) { + throw new AssertionError("Unable to load registrations for " + input, e); + } + loadedFiles.put(input, effects); + } + } + + public JsonNode get(String input) { + return loadedFiles.get(input); + } +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/registry/loader/MultiResourceRegistryLoader.java b/connector/src/main/java/org/geysermc/connector/registry/loader/MultiResourceRegistryLoader.java new file mode 100644 index 000000000..a2bb23696 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/loader/MultiResourceRegistryLoader.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry.loader; + +import it.unimi.dsi.fastutil.Pair; + +public abstract class MultiResourceRegistryLoader implements RegistryLoader, V> { +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/EntityIdentifierRegistry.java b/connector/src/main/java/org/geysermc/connector/registry/loader/NbtRegistryLoader.java similarity index 72% rename from connector/src/main/java/org/geysermc/connector/network/translators/EntityIdentifierRegistry.java rename to connector/src/main/java/org/geysermc/connector/registry/loader/NbtRegistryLoader.java index 5bb029882..773ee1038 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/EntityIdentifierRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/registry/loader/NbtRegistryLoader.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators; +package org.geysermc.connector.registry.loader; import com.nukkitx.nbt.NBTInputStream; import com.nukkitx.nbt.NbtMap; @@ -32,28 +32,15 @@ import org.geysermc.connector.utils.FileUtils; import java.io.InputStream; -/** - * Registry for entity identifiers. - */ -public class EntityIdentifierRegistry { - - public static final NbtMap ENTITY_IDENTIFIERS; - - private EntityIdentifierRegistry() { - } - - public static void init() { - // no-op - } - - static { - /* Load entity identifiers */ - InputStream stream = FileUtils.getResource("bedrock/entity_identifiers.dat"); +public class NbtRegistryLoader implements RegistryLoader { + @Override + public NbtMap load(String input) { + InputStream stream = FileUtils.getResource(input); try (NBTInputStream nbtInputStream = NbtUtils.createNetworkReader(stream)) { - ENTITY_IDENTIFIERS = (NbtMap) nbtInputStream.readTag(); + return (NbtMap) nbtInputStream.readTag(); } catch (Exception e) { - throw new AssertionError("Unable to get entities from entity identifiers", e); + throw new AssertionError("Failed to load registrations for " + input, e); } } -} +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/registry/loader/ParticleTypesRegistryLoader.java b/connector/src/main/java/org/geysermc/connector/registry/loader/ParticleTypesRegistryLoader.java new file mode 100644 index 000000000..3c3188236 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/loader/ParticleTypesRegistryLoader.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry.loader; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.steveice10.mc.protocol.data.game.world.particle.ParticleType; +import com.nukkitx.protocol.bedrock.data.LevelEventType; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.geysermc.connector.registry.type.ParticleMapping; + +import java.util.Iterator; +import java.util.Map; + +public class ParticleTypesRegistryLoader extends EffectRegistryLoader> { + + @Override + public Map load(String input) { + this.loadFile(input); + + Iterator> particlesIterator = this.get(input).fields(); + Map particles = new Object2ObjectOpenHashMap<>(); + try { + while (particlesIterator.hasNext()) { + Map.Entry entry = particlesIterator.next(); + JsonNode bedrockId = entry.getValue().get("bedrockId"); + JsonNode bedrockIdNumeric = entry.getValue().get("bedrockNumericId"); + JsonNode eventType = entry.getValue().get("eventType"); + particles.put(ParticleType.valueOf(entry.getKey().toUpperCase()), new ParticleMapping( + eventType == null ? null : LevelEventType.valueOf(eventType.asText().toUpperCase()), + bedrockId == null ? null : bedrockId.asText(), + bedrockIdNumeric == null ? -1 : bedrockIdNumeric.asInt()) + ); + } + } catch (Exception e) { + e.printStackTrace(); + } + return particles; + } +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/PotionMixRegistry.java b/connector/src/main/java/org/geysermc/connector/registry/loader/PotionMixRegistryLoader.java similarity index 70% rename from connector/src/main/java/org/geysermc/connector/network/translators/item/PotionMixRegistry.java rename to connector/src/main/java/org/geysermc/connector/registry/loader/PotionMixRegistryLoader.java index 30be7da23..7c43a21fd 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/PotionMixRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/registry/loader/PotionMixRegistryLoader.java @@ -23,14 +23,22 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.item; +package org.geysermc.connector.registry.loader; import com.nukkitx.protocol.bedrock.data.inventory.PotionMixData; +import org.geysermc.connector.network.BedrockProtocol; +import org.geysermc.connector.registry.Registries; +import org.geysermc.connector.registry.type.ItemMapping; +import org.geysermc.connector.network.translators.item.Potion; -import java.util.*; +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 {@link Collection} of {@link PotionMixData} that enables the + * Generates a collection of {@link PotionMixData} that enables the * Bedrock client to place brewing items into the brewing stand. * (Does not contain actual potion mixes.) * @@ -38,18 +46,11 @@ import java.util.*; * (Ex: Bedrock cannot normally place glass bottles or fully upgraded * potions into the brewing stand, but Java can.) */ -public class PotionMixRegistry { - public static final Collection POTION_MIXES; +public class PotionMixRegistryLoader implements RegistryLoader> { - private PotionMixRegistry() { - } - - public static void init() { - // no-op - } - - static { - List ingredients = new ArrayList<>(); + @Override + public Set load(Object input) { + List ingredients = new ArrayList<>(); ingredients.add(getNonNull("minecraft:nether_wart")); ingredients.add(getNonNull("minecraft:redstone")); ingredients.add(getNonNull("minecraft:glowstone_dust")); @@ -68,21 +69,21 @@ public class PotionMixRegistry { ingredients.add(getNonNull("minecraft:turtle_helmet")); ingredients.add(getNonNull("minecraft:phantom_membrane")); - List inputs = new ArrayList<>(); + List inputs = new ArrayList<>(); inputs.add(getNonNull("minecraft:potion")); inputs.add(getNonNull("minecraft:splash_potion")); inputs.add(getNonNull("minecraft:lingering_potion")); - ItemEntry glassBottle = getNonNull("minecraft:glass_bottle"); + ItemMapping glassBottle = getNonNull("minecraft:glass_bottle"); Set potionMixes = new HashSet<>(); // Add all types of potions as inputs - ItemEntry fillerIngredient = ingredients.get(0); - for (ItemEntry input : inputs) { - for (Potion potion : Potion.VALUES) { + ItemMapping fillerIngredient = ingredients.get(0); + for (ItemMapping entryInput : inputs) { + for (Potion potion : Potion.values()) { potionMixes.add(new PotionMixData( - input.getBedrockId(), potion.getBedrockId(), + entryInput.getBedrockId(), potion.getBedrockId(), fillerIngredient.getBedrockId(), fillerIngredient.getBedrockData(), glassBottle.getBedrockId(), glassBottle.getBedrockData()) ); @@ -91,22 +92,21 @@ public class PotionMixRegistry { // Add all brewing ingredients // Also adds glass bottle as input - for (ItemEntry ingredient : ingredients) { + for (ItemMapping ingredient : ingredients) { potionMixes.add(new PotionMixData( glassBottle.getBedrockId(), glassBottle.getBedrockData(), ingredient.getBedrockId(), ingredient.getBedrockData(), glassBottle.getBedrockId(), glassBottle.getBedrockData()) ); } - - POTION_MIXES = potionMixes; + return potionMixes; } - private static ItemEntry getNonNull(String javaIdentifier) { - ItemEntry itemEntry = ItemRegistry.getItemEntry(javaIdentifier); - if (itemEntry == null) + private static ItemMapping getNonNull(String javaIdentifier) { + ItemMapping itemMapping = Registries.ITEMS.forVersion(BedrockProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()).getMapping(javaIdentifier); + if (itemMapping == null) throw new NullPointerException("No item entry exists for java identifier: " + javaIdentifier); - return itemEntry; + return itemMapping; } -} +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/registry/loader/RegistryLoader.java b/connector/src/main/java/org/geysermc/connector/registry/loader/RegistryLoader.java new file mode 100644 index 000000000..495895789 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/loader/RegistryLoader.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry.loader; + +/** + * Represents a registry loader. + * + * @param the input to load the registry from + * @param the output of the registry + */ +@FunctionalInterface +public interface RegistryLoader { + O load(I input); +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator1_17_0.java b/connector/src/main/java/org/geysermc/connector/registry/loader/RegistryLoaders.java similarity index 73% rename from connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator1_17_0.java rename to connector/src/main/java/org/geysermc/connector/registry/loader/RegistryLoaders.java index d86d0e71f..9a9634157 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator1_17_0.java +++ b/connector/src/main/java/org/geysermc/connector/registry/loader/RegistryLoaders.java @@ -23,21 +23,14 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.world.block; +package org.geysermc.connector.registry.loader; -public class BlockTranslator1_17_0 extends BlockTranslator { - public static final BlockTranslator1_17_0 INSTANCE = new BlockTranslator1_17_0(); +import java.util.function.Supplier; - public BlockTranslator1_17_0() { - super("bedrock/block_palette.1_17_0.nbt"); +public class RegistryLoaders { + public static NbtRegistryLoader NBT = new NbtRegistryLoader(); + + public static RegistryLoader empty(Supplier value) { + return input -> value.get(); } - - @Override - public int getBlockStateVersion() { - return 17879555; - } - - public static void init() { - // no-op - } -} +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/registry/loader/SoundEffectsRegistryLoader.java b/connector/src/main/java/org/geysermc/connector/registry/loader/SoundEffectsRegistryLoader.java new file mode 100644 index 000000000..8103ece8b --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/loader/SoundEffectsRegistryLoader.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry.loader; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.steveice10.mc.protocol.data.game.world.effect.SoundEffect; +import com.nukkitx.protocol.bedrock.data.LevelEventType; +import com.nukkitx.protocol.bedrock.data.SoundEvent; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.network.translators.effect.Effect; +import org.geysermc.connector.network.translators.effect.PlaySoundEffect; +import org.geysermc.connector.network.translators.effect.SoundEventEffect; +import org.geysermc.connector.network.translators.effect.SoundLevelEffect; + +import java.util.Iterator; +import java.util.Map; + +public class SoundEffectsRegistryLoader extends EffectRegistryLoader> { + + @Override + public Map load(String input) { + this.loadFile(input); + + Iterator> effectsIterator = this.get(input).fields(); + Map soundEffects = new Object2ObjectOpenHashMap<>(); + while (effectsIterator.hasNext()) { + Map.Entry entry = effectsIterator.next(); + JsonNode node = entry.getValue(); + try { + String type = node.get("type").asText(); + SoundEffect javaEffect = null; + Effect effect = null; + switch (type) { + case "soundLevel": { + javaEffect = SoundEffect.valueOf(entry.getKey()); + LevelEventType levelEventType = LevelEventType.valueOf(node.get("name").asText()); + int data = node.has("data") ? node.get("data").intValue() : 0; + effect = new SoundLevelEffect(levelEventType, data); + break; + } + case "soundEvent": { + javaEffect = SoundEffect.valueOf(entry.getKey()); + SoundEvent soundEvent = SoundEvent.valueOf(node.get("name").asText()); + String identifier = node.has("identifier") ? node.get("identifier").asText() : ""; + int extraData = node.has("extraData") ? node.get("extraData").intValue() : -1; + effect = new SoundEventEffect(soundEvent, identifier, extraData); + break; + } + case "playSound": { + javaEffect = SoundEffect.valueOf(entry.getKey()); + String name = node.get("name").asText(); + float volume = node.has("volume") ? node.get("volume").floatValue() : 1.0f; + boolean pitchSub = node.has("pitch_sub") && node.get("pitch_sub").booleanValue(); + float pitchMul = node.has("pitch_mul") ? node.get("pitch_mul").floatValue() : 1.0f; + float pitchAdd = node.has("pitch_add") ? node.get("pitch_add").floatValue() : 0.0f; + boolean relative = !node.has("relative") || node.get("relative").booleanValue(); + effect = new PlaySoundEffect(name, volume, pitchSub, pitchMul, pitchAdd, relative); + break; + } + } + if (javaEffect != null) { + soundEffects.put(javaEffect, effect); + } + } catch (Exception e) { + GeyserConnector.getInstance().getLogger().warning("Failed to map sound effect " + entry.getKey() + " : " + e.toString()); + } + } + return soundEffects; + } +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/registry/loader/SoundHandlerRegistryLoader.java b/connector/src/main/java/org/geysermc/connector/registry/loader/SoundHandlerRegistryLoader.java new file mode 100644 index 000000000..42c10c2ce --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/loader/SoundHandlerRegistryLoader.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry.loader; + +import org.geysermc.connector.network.translators.sound.SoundHandler; +import org.geysermc.connector.network.translators.sound.SoundInteractionHandler; + +import java.util.function.Function; + +public class SoundHandlerRegistryLoader extends AnnotatedRegistryLoader> { + public SoundHandlerRegistryLoader() { + super(SoundHandler.class, Function.identity()); + } +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundRegistry.java b/connector/src/main/java/org/geysermc/connector/registry/loader/SoundRegistryLoader.java similarity index 59% rename from connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundRegistry.java rename to connector/src/main/java/org/geysermc/connector/registry/loader/SoundRegistryLoader.java index 90599eb19..4dc1dab58 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/registry/loader/SoundRegistryLoader.java @@ -23,33 +23,23 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.sound; +package org.geysermc.connector.registry.loader; import com.fasterxml.jackson.databind.JsonNode; -import com.nukkitx.protocol.bedrock.data.SoundEvent; -import lombok.Data; -import lombok.ToString; import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.registry.type.SoundMapping; import org.geysermc.connector.utils.FileUtils; + import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Iterator; import java.util.Map; -public class SoundRegistry { +public class SoundRegistryLoader implements RegistryLoader> { - private static final Map SOUNDS; - - private SoundRegistry() { - } - - public static void init() { - // no-op - } - - static { - /* Load sound mappings */ + @Override + public Map load(String input) { InputStream stream = FileUtils.getResource("mappings/sounds.json"); JsonNode soundsTree; try { @@ -63,7 +53,6 @@ public class SoundRegistry { while(soundsIterator.hasNext()) { Map.Entry next = soundsIterator.next(); JsonNode brMap = next.getValue(); - soundMappings.put(next.getKey(), new SoundMapping( next.getKey(), brMap.has("bedrock_mapping") && brMap.get("bedrock_mapping").isTextual() ? brMap.get("bedrock_mapping").asText() : null, @@ -74,50 +63,6 @@ public class SoundRegistry { ) ); } - SOUNDS = soundMappings; + return soundMappings; } - - /** - * Get's the sound mapping for a Java edition sound identifier - * @param java Java edition sound identifier - * @return SoundMapping object with information for bedrock, nukkit, java, etc. null if not found - */ - public static SoundMapping fromJava(String java) { - return SOUNDS.get(java); - } - - /** - * Maps a sound name to a sound event, null if one - * does not exist. - * - * @param sound the sound name - * @return a sound event from the given sound - */ - public static SoundEvent toSoundEvent(String sound) { - try { - return SoundEvent.valueOf(sound.toUpperCase().replaceAll("\\.", "_")); - } catch (Exception ex) { - return null; - } - } - - @Data - @ToString - public static class SoundMapping { - private final String java; - private final String bedrock; - private final String playsound; - private final int extraData; - private String identifier; - private boolean levelEvent; - - public SoundMapping(String java, String bedrock, String playsound, int extraData, String identifier, boolean levelEvent) { - this.java = java; - this.bedrock = bedrock == null || bedrock.equalsIgnoreCase("") ? null : bedrock; - this.playsound = playsound == null || playsound.equalsIgnoreCase("") ? null : playsound; - this.extraData = extraData; - this.identifier = identifier == null || identifier.equalsIgnoreCase("") ? ":" : identifier; - this.levelEvent = levelEvent; - } - } -} +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/registry/populator/BlockRegistryPopulator.java b/connector/src/main/java/org/geysermc/connector/registry/populator/BlockRegistryPopulator.java new file mode 100644 index 000000000..7903e820b --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/populator/BlockRegistryPopulator.java @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry.populator; + +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.collect.ImmutableMap; +import com.nukkitx.nbt.*; +import com.nukkitx.protocol.bedrock.v440.Bedrock_v440; +import com.nukkitx.protocol.bedrock.v448.Bedrock_v448; +import it.unimi.dsi.fastutil.ints.Int2IntMap; +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.network.translators.world.block.BlockStateValues; +import org.geysermc.connector.network.translators.world.chunk.BlockStorage; +import org.geysermc.connector.network.translators.world.chunk.ChunkSection; +import org.geysermc.connector.registry.BlockRegistries; +import org.geysermc.connector.registry.type.BlockMapping; +import org.geysermc.connector.registry.type.BlockMappings; +import org.geysermc.connector.utils.FileUtils; + +import java.io.DataInputStream; +import java.io.InputStream; +import java.util.Iterator; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.zip.GZIPInputStream; + +public class BlockRegistryPopulator { + private static final ImmutableMap> STATE_MAPPER = ImmutableMap.>builder() + .put("1_17_0", (bedrockIdentifier, statesBuilder) -> { + if (bedrockIdentifier.contains("candle")) { + // Replace candles with sea pickles or cake + if (bedrockIdentifier.contains("cake")) { + statesBuilder.remove("lit"); + statesBuilder.putInt("bite_counter", 0); + return "minecraft:cake"; + } else { + statesBuilder.put("cluster_count", statesBuilder.remove("candles")); + statesBuilder.putBoolean("dead_bit", ((byte) (statesBuilder.remove("lit"))) != 0); + return "minecraft:sea_pickle"; + } + } + return null; + }) + .put("1_17_10", (bedrockIdentifier, statesBuilder) -> null) + .build(); + + private static final Object2IntMap PALETTE_VERSIONS = new Object2IntOpenHashMap() { + { + put("1_17_0", Bedrock_v440.V440_CODEC.getProtocolVersion()); + put("1_17_10", Bedrock_v448.V448_CODEC.getProtocolVersion()); + } + }; + + /** + * Stores the raw blocks JSON until it is no longer needed. + */ + private static JsonNode BLOCKS_JSON; + + public static void populate() { + registerJavaBlocks(); + registerBedrockBlocks(); + + BLOCKS_JSON = null; + } + + private static void registerBedrockBlocks() { + for (Map.Entry> palette : STATE_MAPPER.entrySet()) { + InputStream stream = FileUtils.getResource(String.format("bedrock/block_palette.%s.nbt", palette.getKey())); + NbtList blocksTag; + try (NBTInputStream nbtInputStream = new NBTInputStream(new DataInputStream(new GZIPInputStream(stream)))) { + NbtMap blockPalette = (NbtMap) nbtInputStream.readTag(); + blocksTag = (NbtList) blockPalette.getList("blocks", NbtType.COMPOUND); + } catch (Exception e) { + throw new AssertionError("Unable to get blocks from runtime block states", e); + } + Map javaIdentifierToBedrockTag = new Object2ObjectOpenHashMap<>(blocksTag.size()); + // New since 1.16.100 - find the block runtime ID by the order given to us in the block palette, + // as we no longer send a block palette + Object2IntMap blockStateOrderedMap = new Object2IntOpenHashMap<>(blocksTag.size()); + + int stateVersion = -1; + for (int i = 0; i < blocksTag.size(); i++) { + NbtMap tag = blocksTag.get(i); + if (blockStateOrderedMap.containsKey(tag)) { + throw new AssertionError("Duplicate block states in Bedrock palette: " + tag); + } + blockStateOrderedMap.put(tag, i); + if (stateVersion == -1) { + stateVersion = tag.getInt("version"); + } + } + int airRuntimeId = -1; + int commandBlockRuntimeId = -1; + int javaRuntimeId = -1; + int waterRuntimeId = -1; + Iterator> blocksIterator = BLOCKS_JSON.fields(); + + BiFunction stateMapper = STATE_MAPPER.getOrDefault(palette.getKey(), (i, s) -> null); + + Int2IntMap javaToBedrockBlockMap = new Int2IntOpenHashMap(); + Int2IntMap bedrockToJavaBlockMap = new Int2IntOpenHashMap(); + + Map flowerPotBlocks = new Object2ObjectOpenHashMap<>(); + Object2IntMap itemFrames = new Object2IntOpenHashMap<>(); + + BlockMappings.BlockMappingsBuilder builder = BlockMappings.builder(); + while (blocksIterator.hasNext()) { + javaRuntimeId++; + Map.Entry entry = blocksIterator.next(); + String javaId = entry.getKey(); + + NbtMap blockTag = buildBedrockState(entry.getValue(), stateVersion, stateMapper); + int bedrockRuntimeId = blockStateOrderedMap.getOrDefault(blockTag, -1); + if (bedrockRuntimeId == -1) { + throw new RuntimeException("Unable to find " + javaId + " Bedrock runtime ID! Built compound tag: \n" + blockTag); + } + + switch (javaId) { + case "minecraft:air": + airRuntimeId = bedrockRuntimeId; + break; + case "minecraft:water[level=0]": + waterRuntimeId = bedrockRuntimeId; + break; + case "minecraft:command_block[conditional=false,facing=north]": + commandBlockRuntimeId = bedrockRuntimeId; + break; + } + + boolean waterlogged = entry.getKey().contains("waterlogged=true") + || javaId.contains("minecraft:bubble_column") || javaId.contains("minecraft:kelp") || javaId.contains("seagrass"); + + if (waterlogged) { + bedrockToJavaBlockMap.putIfAbsent(bedrockRuntimeId | 1 << 31, javaRuntimeId); + int finalJavaRuntimeId = javaRuntimeId; + BlockRegistries.WATERLOGGED.register(set -> set.add(finalJavaRuntimeId)); + } else { + bedrockToJavaBlockMap.putIfAbsent(bedrockRuntimeId, javaRuntimeId); + } + + String cleanJavaIdentifier = entry.getKey().split("\\[")[0]; + + // Get the tag needed for non-empty flower pots + if (entry.getValue().get("pottable") != null) { + flowerPotBlocks.put(cleanJavaIdentifier, blockTag); + } + + if (!cleanJavaIdentifier.equals(entry.getValue().get("bedrock_identifier").asText())) { + javaIdentifierToBedrockTag.put(cleanJavaIdentifier, blockTag); + } + + javaToBedrockBlockMap.put(javaRuntimeId, bedrockRuntimeId); + } + + if (commandBlockRuntimeId == -1) { + throw new AssertionError("Unable to find command block in palette"); + } + builder.commandBlockRuntimeId(commandBlockRuntimeId); + + if (waterRuntimeId == -1) { + throw new AssertionError("Unable to find water in palette"); + } + builder.bedrockWaterId(waterRuntimeId); + + if (airRuntimeId == -1) { + throw new AssertionError("Unable to find air in palette"); + } + builder.bedrockAirId(airRuntimeId); + + // Loop around again to find all item frame runtime IDs + for (Object2IntMap.Entry entry : blockStateOrderedMap.object2IntEntrySet()) { + String name = entry.getKey().getString("name"); + if (name.equals("minecraft:frame") || name.equals("minecraft:glow_frame")) { + itemFrames.put(entry.getKey(), entry.getIntValue()); + } + } + builder.bedrockBlockStates(blocksTag); + + BlockRegistries.BLOCKS.register(PALETTE_VERSIONS.getInt(palette.getKey()), builder.blockStateVersion(stateVersion) + .emptyChunkSection(new ChunkSection(new BlockStorage[]{new BlockStorage(airRuntimeId)})) + .javaToBedrockBlockMap(javaToBedrockBlockMap) + .bedrockToJavaBlockMap(bedrockToJavaBlockMap) + .javaIdentifierToBedrockTag(javaIdentifierToBedrockTag) + .itemFrames(itemFrames) + .flowerPotBlocks(flowerPotBlocks) + .build()); + } + } + + private static void registerJavaBlocks() { + InputStream stream = FileUtils.getResource("mappings/blocks.json"); + + JsonNode blocksJson; + try { + blocksJson = GeyserConnector.JSON_MAPPER.readTree(stream); + } catch (Exception e) { + throw new AssertionError("Unable to load Java block mappings", e); + } + + int javaRuntimeId = -1; + int bellBlockId = -1; + int cobwebBlockId = -1; + int furnaceRuntimeId = -1; + int furnaceLitRuntimeId = -1; + int spawnerRuntimeId = -1; + int uniqueJavaId = -1; + int waterRuntimeId = -1; + Iterator> blocksIterator = blocksJson.fields(); + while (blocksIterator.hasNext()) { + javaRuntimeId++; + Map.Entry entry = blocksIterator.next(); + String javaId = entry.getKey(); + + // TODO fix this, (no block should have a null hardness) + BlockMapping.BlockMappingBuilder builder = BlockMapping.builder(); + JsonNode hardnessNode = entry.getValue().get("block_hardness"); + if (hardnessNode != null) { + builder.hardness(hardnessNode.doubleValue()); + } + + JsonNode canBreakWithHandNode = entry.getValue().get("can_break_with_hand"); + if (canBreakWithHandNode != null) { + builder.canBreakWithHand(canBreakWithHandNode.booleanValue()); + } else { + builder.canBreakWithHand(false); + } + + JsonNode collisionIndexNode = entry.getValue().get("collision_index"); + if (hardnessNode != null) { + builder.collisionIndex(collisionIndexNode.intValue()); + } + + JsonNode pickItemNode = entry.getValue().get("pick_item"); + if (pickItemNode != null) { + builder.pickItem(pickItemNode.textValue()); + } + + builder.javaIdentifier(javaId); + builder.javaBlockId(uniqueJavaId); + + BlockRegistries.JAVA_IDENTIFIERS.register(javaId, javaRuntimeId); + BlockRegistries.JAVA_BLOCKS.register(javaRuntimeId, builder.build()); + + BlockStateValues.storeBlockStateValues(entry.getKey(), javaRuntimeId, entry.getValue()); + + String cleanJavaIdentifier = entry.getKey().split("\\[")[0]; + String bedrockIdentifier = entry.getValue().get("bedrock_identifier").asText(); + + if (!BlockRegistries.JAVA_CLEAN_IDENTIFIERS.get().containsValue(cleanJavaIdentifier)) { + uniqueJavaId++; + BlockRegistries.JAVA_CLEAN_IDENTIFIERS.register(uniqueJavaId, cleanJavaIdentifier); + } + + // Keeping this here since this is currently unchanged between versions + if (!cleanJavaIdentifier.equals(bedrockIdentifier)) { + BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.register(cleanJavaIdentifier, bedrockIdentifier); + } + + if (javaId.startsWith("minecraft:bell[")) { + bellBlockId = uniqueJavaId; + + } else if (javaId.contains("cobweb")) { + cobwebBlockId = uniqueJavaId; + + } else if (javaId.startsWith("minecraft:furnace[facing=north")) { + if (javaId.contains("lit=true")) { + furnaceLitRuntimeId = javaRuntimeId; + } else { + furnaceRuntimeId = javaRuntimeId; + } + + } else if (javaId.startsWith("minecraft:spawner")) { + spawnerRuntimeId = javaRuntimeId; + + } else if ("minecraft:water[level=0]".equals(javaId)) { + waterRuntimeId = 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"); + } + BlockStateValues.JAVA_COBWEB_ID = cobwebBlockId; + + if (furnaceRuntimeId == -1) { + throw new AssertionError("Unable to find furnace in palette"); + } + BlockStateValues.JAVA_FURNACE_ID = furnaceRuntimeId; + + if (furnaceLitRuntimeId == -1) { + throw new AssertionError("Unable to find lit furnace in palette"); + } + BlockStateValues.JAVA_FURNACE_LIT_ID = furnaceLitRuntimeId; + + if (spawnerRuntimeId == -1) { + throw new AssertionError("Unable to find spawner in palette"); + } + BlockStateValues.JAVA_SPAWNER_ID = spawnerRuntimeId; + + if (waterRuntimeId == -1) { + throw new AssertionError("Unable to find Java water in palette"); + } + BlockStateValues.JAVA_WATER_ID = waterRuntimeId; + + BLOCKS_JSON = blocksJson; + } + + private static NbtMap buildBedrockState(JsonNode node, int blockStateVersion, BiFunction statesMapper) { + NbtMapBuilder tagBuilder = NbtMap.builder(); + String bedrockIdentifier = node.get("bedrock_identifier").textValue(); + tagBuilder.putString("name", bedrockIdentifier) + .putInt("version", blockStateVersion); + + NbtMapBuilder statesBuilder = NbtMap.builder(); + + // check for states + if (node.has("bedrock_states")) { + Iterator> statesIterator = node.get("bedrock_states").fields(); + + while (statesIterator.hasNext()) { + Map.Entry stateEntry = statesIterator.next(); + JsonNode stateValue = stateEntry.getValue(); + switch (stateValue.getNodeType()) { + case BOOLEAN: + statesBuilder.putBoolean(stateEntry.getKey(), stateValue.booleanValue()); + continue; + case STRING: + statesBuilder.putString(stateEntry.getKey(), stateValue.textValue()); + continue; + case NUMBER: + statesBuilder.putInt(stateEntry.getKey(), stateValue.intValue()); + } + } + } + String newIdentifier = statesMapper.apply(bedrockIdentifier, statesBuilder); + if (newIdentifier != null) { + tagBuilder.putString("name", newIdentifier); + } + tagBuilder.put("states", statesBuilder.build()); + return tagBuilder.build(); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/registry/populator/ItemRegistryPopulator.java b/connector/src/main/java/org/geysermc/connector/registry/populator/ItemRegistryPopulator.java new file mode 100644 index 000000000..222521241 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/populator/ItemRegistryPopulator.java @@ -0,0 +1,519 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry.populator; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.NbtType; +import com.nukkitx.nbt.NbtUtils; +import com.nukkitx.protocol.bedrock.data.SoundEvent; +import com.nukkitx.protocol.bedrock.data.inventory.ComponentItemData; +import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.packet.StartGamePacket; +import com.nukkitx.protocol.bedrock.v440.Bedrock_v440; +import com.nukkitx.protocol.bedrock.v448.Bedrock_v448; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.objects.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.network.translators.item.StoredItemMappings; +import org.geysermc.connector.registry.BlockRegistries; +import org.geysermc.connector.registry.Registries; +import org.geysermc.connector.registry.type.*; +import org.geysermc.connector.utils.FileUtils; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.*; + +public class ItemRegistryPopulator { + private static final Map PALETTE_VERSIONS = new Object2ObjectOpenHashMap(){ + { + put("1_17_0", new PaletteVersion(Bedrock_v440.V440_CODEC.getProtocolVersion(), new Object2ObjectOpenHashMap() { + { + put("minecraft:candle", "minecraft:sea_pickle"); + put("minecraft:white_candle", "minecraft:sea_pickle"); + put("minecraft:orange_candle", "minecraft:sea_pickle"); + put("minecraft:magenta_candle", "minecraft:sea_pickle"); + put("minecraft:light_blue_candle", "minecraft:sea_pickle"); + put("minecraft:yellow_candle", "minecraft:sea_pickle"); + put("minecraft:lime_candle", "minecraft:sea_pickle"); + put("minecraft:pink_candle", "minecraft:sea_pickle"); + put("minecraft:gray_candle", "minecraft:sea_pickle"); + put("minecraft:light_gray_candle", "minecraft:sea_pickle"); + put("minecraft:cyan_candle", "minecraft:sea_pickle"); + put("minecraft:purple_candle", "minecraft:sea_pickle"); + put("minecraft:blue_candle", "minecraft:sea_pickle"); + put("minecraft:brown_candle", "minecraft:sea_pickle"); + put("minecraft:green_candle", "minecraft:sea_pickle"); + put("minecraft:red_candle", "minecraft:sea_pickle"); + put("minecraft:black_candle", "minecraft:sea_pickle"); + } + })); + put("1_17_10", new PaletteVersion(Bedrock_v448.V448_CODEC.getProtocolVersion(), Collections.emptyMap())); + } + }; + + @Getter + @AllArgsConstructor + private static class PaletteVersion { + private final int protocolVersion; + /** + * Key - item not available in this version. Value - Java replacement item + */ + private final Map additionalTranslatedItems; + } + + public static void populate() { + // Load item mappings from Java Edition to Bedrock Edition + InputStream stream = FileUtils.getResource("mappings/items.json"); + + TypeReference> mappingItemsType = new TypeReference>() { }; + + Map items; + try { + items = GeyserConnector.JSON_MAPPER.readValue(stream, mappingItemsType); + } catch (Exception e) { + throw new AssertionError("Unable to load Java runtime item IDs", e); + } + + /* Load item palette */ + for (Map.Entry palette : PALETTE_VERSIONS.entrySet()) { + stream = FileUtils.getResource(String.format("bedrock/runtime_item_states.%s.json", palette.getKey())); + + TypeReference> paletteEntriesType = new TypeReference>() { }; + + // Used to get the Bedrock namespaced ID (in instances where there are small differences) + Object2IntMap bedrockIdentifierToId = new Object2IntOpenHashMap<>(); + + List itemNames = new ArrayList<>(); + + List itemEntries; + try { + itemEntries = GeyserConnector.JSON_MAPPER.readValue(stream, paletteEntriesType); + } catch (Exception e) { + throw new AssertionError("Unable to load Bedrock runtime item IDs", e); + } + + Map entries = new Object2ObjectOpenHashMap<>(); + + for (PaletteItem entry : itemEntries) { + entries.put(entry.getName(), new StartGamePacket.ItemEntry(entry.getName(), (short) entry.getId())); + bedrockIdentifierToId.put(entry.getName(), entry.getId()); + } + + Object2IntMap bedrockBlockIdOverrides = new Object2IntOpenHashMap<>(); + Object2IntMap blacklistedIdentifiers = new Object2IntOpenHashMap<>(); + + // Load creative items + // We load this before item mappings to get overridden block runtime ID mappings + stream = FileUtils.getResource(String.format("bedrock/creative_items.%s.json", palette.getKey())); + + JsonNode creativeItemEntries; + try { + creativeItemEntries = GeyserConnector.JSON_MAPPER.readTree(stream).get("items"); + } catch (Exception e) { + throw new AssertionError("Unable to load creative items", e); + } + + IntList boats = new IntArrayList(); + IntList buckets = new IntArrayList(); + IntList spawnEggs = new IntArrayList(); + List carpets = new ObjectArrayList<>(); + + Int2ObjectMap mappings = new Int2ObjectOpenHashMap<>(); + // Temporary mapping to create stored items + Map identifierToMapping = new Object2ObjectOpenHashMap<>(); + + int netId = 1; + List creativeItems = new ArrayList<>(); + for (JsonNode itemNode : creativeItemEntries) { + int count = 1; + int damage = 0; + int blockRuntimeId = 0; + NbtMap tag = null; + JsonNode damageNode = itemNode.get("damage"); + if (damageNode != null) { + damage = damageNode.asInt(); + } + JsonNode countNode = itemNode.get("count"); + if (countNode != null) { + count = countNode.asInt(); + } + JsonNode blockRuntimeIdNode = itemNode.get("blockRuntimeId"); + if (blockRuntimeIdNode != null) { + blockRuntimeId = blockRuntimeIdNode.asInt(); + } + JsonNode nbtNode = itemNode.get("nbt_b64"); + if (nbtNode != null) { + byte[] bytes = Base64.getDecoder().decode(nbtNode.asText()); + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + try { + tag = (NbtMap) NbtUtils.createReaderLE(bais).readTag(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + String identifier = itemNode.get("id").textValue(); + StartGamePacket.ItemEntry entry = entries.get(identifier); + int id = -1; + if (entry != null) { + id = entry.getId(); + } + + if (id == -1) { + throw new RuntimeException("Unable to find matching Bedrock item for " + identifier); + } + + creativeItems.add(ItemData.builder() + .id(id) + .damage(damage) + .count(count) + .blockRuntimeId(blockRuntimeId) + .tag(tag) + .netId(netId++) + .build()); + + if (blockRuntimeId != 0) { + // Add override for item mapping, unless it already exists... then we know multiple states can exist + if (!blacklistedIdentifiers.containsKey(identifier)) { + if (bedrockBlockIdOverrides.containsKey(identifier)) { + bedrockBlockIdOverrides.removeInt(identifier); + // Save this as a blacklist, but also as knowledge of what the block state name should be + blacklistedIdentifiers.put(identifier, blockRuntimeId); + } else { + // Unless there's multiple possibilities for this one state, let this be + bedrockBlockIdOverrides.put(identifier, blockRuntimeId); + } + } + } + } + + BlockMappings blockMappings = BlockRegistries.BLOCKS.forVersion(palette.getValue().getProtocolVersion()); + + int itemIndex = 0; + int javaFurnaceMinecartId = 0; + boolean usingFurnaceMinecart = GeyserConnector.getInstance().getConfig().isAddNonBedrockItems(); + + Set javaOnlyItems = new ObjectOpenHashSet<>(); + Collections.addAll(javaOnlyItems, "minecraft:spectral_arrow", "minecraft:debug_stick", + "minecraft:knowledge_book", "minecraft:tipped_arrow", "minecraft:trader_llama_spawn_egg", + "minecraft:bundle", "minecraft:sculk_sensor"); + if (!usingFurnaceMinecart) { + javaOnlyItems.add("minecraft:furnace_minecart"); + } + // Java-only items for this version + javaOnlyItems.addAll(palette.getValue().getAdditionalTranslatedItems().keySet()); + + for (Map.Entry entry : items.entrySet()) { + GeyserMappingItem mappingItem; + String replacementItem = palette.getValue().getAdditionalTranslatedItems().get(entry.getKey()); + if (replacementItem != null) { + mappingItem = items.get(replacementItem); + } else { + // This items has a mapping specifically for this version of the game + mappingItem = entry.getValue(); + } + + if (usingFurnaceMinecart && entry.getKey().equals("minecraft:furnace_minecart")) { + javaFurnaceMinecartId = itemIndex; + itemIndex++; + continue; + } + String bedrockIdentifier = mappingItem.getBedrockIdentifier(); + int bedrockId = bedrockIdentifierToId.getInt(bedrockIdentifier); + if (bedrockIdentifier == null) { + throw new RuntimeException("Missing Bedrock ID in mappings!: " + bedrockId); + } + int stackSize = mappingItem.getStackSize() == null ? 64 : mappingItem.getStackSize(); + + int bedrockBlockId = -1; + Integer blockRuntimeIdNode = entry.getValue().getBlockRuntimeId(); + if (blockRuntimeIdNode != null) { + int blockIdOverride = bedrockBlockIdOverrides.getOrDefault(bedrockIdentifier, -1); + if (blockIdOverride != -1) { + // Straight from BDS is our best chance of getting an item that doesn't run into issues + bedrockBlockId = blockIdOverride; + } else { + // Try to get an example block runtime ID from the creative contents packet, for Bedrock identifier obtaining + int aValidBedrockBlockId = blacklistedIdentifiers.getOrDefault(bedrockIdentifier, -1); + if (aValidBedrockBlockId == -1) { + // Fallback + bedrockBlockId = blockMappings.getBedrockBlockId(blockRuntimeIdNode); + } else { + // As of 1.16.220, every item requires a block runtime ID attached to it. + // This is mostly for identifying different blocks with the same item ID - wool, slabs, some walls. + // However, in order for some visuals and crafting to work, we need to send the first matching block state + // as indexed by Bedrock's block palette + // There are exceptions! But, ideally, the block ID override should take care of those. + String javaBlockIdentifier = BlockRegistries.JAVA_BLOCKS.get(blockRuntimeIdNode).getCleanJavaIdentifier(); + NbtMapBuilder requiredBlockStatesBuilder = NbtMap.builder(); + String correctBedrockIdentifier = blockMappings.getBedrockBlockStates().get(aValidBedrockBlockId).getString("name"); + boolean firstPass = true; + for (Map.Entry blockEntry : BlockRegistries.JAVA_IDENTIFIERS.get().entrySet()) { + if (blockEntry.getKey().split("\\[")[0].equals(javaBlockIdentifier)) { + int bedrockBlockRuntimeId = blockMappings.getBedrockBlockId(blockEntry.getValue()); + NbtMap blockTag = blockMappings.getBedrockBlockStates().get(bedrockBlockRuntimeId); + String bedrockName = blockTag.getString("name"); + if (!bedrockName.equals(correctBedrockIdentifier)) { + continue; + } + NbtMap states = blockTag.getCompound("states"); + + if (firstPass) { + firstPass = false; + if (states.size() == 0) { + // No need to iterate and find all block states - this is the one, as there can't be any others + bedrockBlockId = bedrockBlockRuntimeId; + break; + } + requiredBlockStatesBuilder.putAll(states); + continue; + } + for (Map.Entry nbtEntry : states.entrySet()) { + Object value = requiredBlockStatesBuilder.get(nbtEntry.getKey()); + if (value != null && !nbtEntry.getValue().equals(value)) { // Null means this value has already been removed/deemed as unneeded + // This state can change between different block states, and therefore is not required + // to build a successful block state of this + requiredBlockStatesBuilder.remove(nbtEntry.getKey()); + } + } + if (requiredBlockStatesBuilder.size() == 0) { + // There are no required block states + // E.G. there was only a direction property that is no longer in play + // (States that are important include color for glass) + break; + } + } + } + + NbtMap requiredBlockStates = requiredBlockStatesBuilder.build(); + if (bedrockBlockId == -1) { + int i = -1; + // We need to loop around again (we can't cache the block tags above) because Bedrock can include states that we don't have a pairing for + // in it's "preferred" block state - I.E. the first matching block state in the list + for (NbtMap blockTag : blockMappings.getBedrockBlockStates()) { + i++; + if (blockTag.getString("name").equals(correctBedrockIdentifier)) { + NbtMap states = blockTag.getCompound("states"); + boolean valid = true; + for (Map.Entry nbtEntry : requiredBlockStates.entrySet()) { + if (!states.get(nbtEntry.getKey()).equals(nbtEntry.getValue())) { + // A required block state doesn't match - this one is not valid + valid = false; + break; + } + } + if (valid) { + bedrockBlockId = i; + break; + } + } + } + if (bedrockBlockId == -1) { + throw new RuntimeException("Could not find a block match for " + entry.getKey()); + } + } + + // Because we have replaced the Bedrock block ID, we also need to replace the creative contents block runtime ID + // That way, creative items work correctly for these blocks + for (int j = 0; j < creativeItems.size(); j++) { + ItemData itemData = creativeItems.get(j); + if (itemData.getId() == bedrockId) { + if (itemData.getDamage() != 0) { + break; + } + NbtMap states = blockMappings.getBedrockBlockStates().get(itemData.getBlockRuntimeId()).getCompound("states"); + boolean valid = true; + for (Map.Entry nbtEntry : requiredBlockStates.entrySet()) { + if (!states.get(nbtEntry.getKey()).equals(nbtEntry.getValue())) { + // A required block state doesn't match - this one is not valid + valid = false; + break; + } + } + if (valid) { + creativeItems.set(j, itemData.toBuilder().blockRuntimeId(bedrockBlockId).build()); + break; + } + } + } + } + } + } + + ItemMapping.ItemMappingBuilder mappingBuilder = ItemMapping.builder() + .javaIdentifier(entry.getKey()) + .javaId(itemIndex) + .bedrockIdentifier(bedrockIdentifier) + .bedrockId(bedrockId) + .bedrockData(mappingItem.getBedrockData()) + .bedrockBlockId(bedrockBlockId) + .stackSize(stackSize); + + if (mappingItem.getToolType() != null) { + if (mappingItem.getToolTier() != null) { + mappingBuilder = mappingBuilder.toolType(mappingItem.getToolType()) + .toolTier(mappingItem.getToolTier()); + } else { + mappingBuilder = mappingBuilder.toolType(mappingItem.getToolType()) + .toolTier(""); + } + } + if (javaOnlyItems.contains(entry.getKey())) { + // These items don't exist on Bedrock, so set up a variable that indicates they should have custom names + mappingBuilder = mappingBuilder.translationString((bedrockBlockId != -1 ? "block." : "item.") + entry.getKey().replace(":", ".")); + GeyserConnector.getInstance().getLogger().debug("Adding " + entry.getKey() + " as an item that needs to be translated."); + } + + ItemMapping mapping = mappingBuilder.build(); + + if (entry.getKey().contains("boat")) { + boats.add(bedrockId); + } else if (entry.getKey().contains("bucket") && !entry.getKey().contains("milk")) { + buckets.add(bedrockId); + } else if (entry.getKey().contains("_carpet") && !entry.getKey().contains("moss")) { + // This should be the numerical order Java sends as an integer value for llamas + carpets.add(ItemData.builder() + .id(mapping.getBedrockId()) + .damage(mapping.getBedrockData()) + .count(1) + .blockRuntimeId(mapping.getBedrockBlockId()) + .build()); + } else if (entry.getKey().startsWith("minecraft:music_disc_")) { + // The Java record level event uses the item ID as the "key" to play the record + Registries.RECORDS.register(itemIndex, SoundEvent.valueOf("RECORD_" + + entry.getKey().replace("minecraft:music_disc_", "").toUpperCase(Locale.ENGLISH))); + } else if (entry.getKey().endsWith("_spawn_egg")) { + spawnEggs.add(mapping.getBedrockId()); + } + + mappings.put(itemIndex, mapping); + identifierToMapping.put(entry.getKey(), mapping); + + itemNames.add(entry.getKey()); + + itemIndex++; + } + + itemNames.add("minecraft:furnace_minecart"); + + int lodestoneCompassId = entries.get("minecraft:lodestone_compass").getId(); + if (lodestoneCompassId == 0) { + throw new RuntimeException("Lodestone compass not found in item palette!"); + } + + // Add the lodestone compass since it doesn't exist on java but we need it for item conversion + ItemMapping lodestoneEntry = ItemMapping.builder() + .javaIdentifier("minecraft:lodestone_compass") + .bedrockIdentifier("minecraft:lodestone_compass") + .javaId(itemIndex) + .bedrockId(lodestoneCompassId) + .bedrockData(0) + .bedrockBlockId(-1) + .stackSize(1) + .build(); + mappings.put(itemIndex, lodestoneEntry); + identifierToMapping.put(lodestoneEntry.getJavaIdentifier(), lodestoneEntry); + + ComponentItemData furnaceMinecartData = null; + if (usingFurnaceMinecart) { + // Add the furnace minecart as a custom item + int furnaceMinecartId = mappings.size() + 1; + + entries.put("geysermc:furnace_minecart", new StartGamePacket.ItemEntry("geysermc:furnace_minecart", (short) furnaceMinecartId, true)); + + mappings.put(javaFurnaceMinecartId, ItemMapping.builder() + .javaIdentifier("geysermc:furnace_minecart") + .bedrockIdentifier("geysermc:furnace_minecart") + .javaId(javaFurnaceMinecartId) + .bedrockId(furnaceMinecartId) + .bedrockData(0) + .bedrockBlockId(-1) + .stackSize(1) + .build()); + + creativeItems.add(ItemData.builder() + .netId(netId) + .id(furnaceMinecartId) + .count(1).build()); + + NbtMapBuilder builder = NbtMap.builder(); + builder.putString("name", "geysermc:furnace_minecart") + .putInt("id", furnaceMinecartId); + + NbtMapBuilder componentBuilder = NbtMap.builder(); + // Conveniently, as of 1.16.200, the furnace minecart has a texture AND translation string already. + componentBuilder.putCompound("minecraft:icon", NbtMap.builder().putString("texture", "minecart_furnace").build()); + componentBuilder.putCompound("minecraft:display_name", NbtMap.builder().putString("value", "item.minecartFurnace.name").build()); + + // Indicate that the arm animation should play on rails + List useOnTag = Collections.singletonList(NbtMap.builder().putString("tags", "q.any_tag('rail')").build()); + componentBuilder.putCompound("minecraft:entity_placer", NbtMap.builder() + .putList("dispense_on", NbtType.COMPOUND, useOnTag) + .putString("entity", "minecraft:minecart") + .putList("use_on", NbtType.COMPOUND, useOnTag) + .build()); + + NbtMapBuilder itemProperties = NbtMap.builder(); + // We always want to allow offhand usage when we can - matches Java Edition + itemProperties.putBoolean("allow_off_hand", true); + itemProperties.putBoolean("hand_equipped", false); + itemProperties.putInt("max_stack_size", 1); + itemProperties.putString("creative_group", "itemGroup.name.minecart"); + itemProperties.putInt("creative_category", 4); // 4 - "Items" + + componentBuilder.putCompound("item_properties", itemProperties.build()); + builder.putCompound("components", componentBuilder.build()); + furnaceMinecartData = new ComponentItemData("geysermc:furnace_minecart", builder.build()); + } + + ItemMappings itemMappings = ItemMappings.builder() + .items(mappings) + .creativeItems(creativeItems.toArray(new ItemData[0])) + .itemEntries(new ArrayList<>(entries.values())) + .itemNames(itemNames.toArray(new String[0])) + .storedItems(new StoredItemMappings(identifierToMapping)) + .javaOnlyItems(javaOnlyItems) + .bucketIds(buckets) + .boatIds(boats) + .spawnEggIds(spawnEggs) + .carpets(carpets) + .furnaceMinecartData(furnaceMinecartData) + .build(); + + Registries.ITEMS.register(palette.getValue().getProtocolVersion(), itemMappings); + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/RecipeRegistry.java b/connector/src/main/java/org/geysermc/connector/registry/populator/RecipeRegistryPopulator.java similarity index 51% rename from connector/src/main/java/org/geysermc/connector/network/translators/item/RecipeRegistry.java rename to connector/src/main/java/org/geysermc/connector/registry/populator/RecipeRegistryPopulator.java index 506317ab9..97eeccece 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/RecipeRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/registry/populator/RecipeRegistryPopulator.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.item; +package org.geysermc.connector.registry.populator; import com.fasterxml.jackson.databind.JsonNode; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; @@ -40,144 +40,95 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.network.translators.item.ItemTranslator; +import org.geysermc.connector.registry.Registries; +import org.geysermc.connector.registry.type.ItemMapping; +import org.geysermc.connector.registry.type.ItemMappings; import org.geysermc.connector.utils.FileUtils; +import org.geysermc.connector.utils.LanguageUtils; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.*; -/** - * Manages any recipe-related storing - */ -public class RecipeRegistry { +import static org.geysermc.connector.utils.InventoryUtils.LAST_RECIPE_NET_ID; - /** - * Stores the last used recipe network ID. Since 1.16.200 (and for server-authoritative inventories), - * each recipe needs a unique network ID (or else in .200 the client crashes). - */ - public static int LAST_RECIPE_NET_ID = 0; +public class RecipeRegistryPopulator { - /** - * A list of all the following crafting recipes, but in a format understood by Java servers. - * Used for console autocrafting. - */ - public static final Int2ObjectMap ALL_CRAFTING_RECIPES = new Int2ObjectOpenHashMap<>(); - - /** - * A list of all possible leather armor dyeing recipes. - * Created manually. - */ - public static final List LEATHER_DYEING_RECIPES = new ObjectArrayList<>(); - /** - * A list of all possible firework rocket recipes, including the base rocket. - * Obtained from a ProxyPass dump of protocol v407 - */ - public static final List FIREWORK_ROCKET_RECIPES = new ObjectArrayList<>(); - /** - * A list of all possible firework star recipes. - * Obtained from a ProxyPass dump of protocol v407 - */ - public static final List FIREWORK_STAR_RECIPES = new ObjectArrayList<>(); - /** - * A list of all possible shulker box dyeing options. - * Obtained from a ProxyPass dump of protocol v407 - */ - public static final List SHULKER_BOX_DYEING_RECIPES = new ObjectArrayList<>(); - /** - * A list of all possible suspicious stew recipes. - * Obtained from a ProxyPass dump of protocol v407 - */ - public static final List SUSPICIOUS_STEW_RECIPES = new ObjectArrayList<>(); - /** - * A list of all possible tipped arrow recipes. - * Obtained from a ProxyPass dump of protocol v407 - */ - public static final List TIPPED_ARROW_RECIPES = new ObjectArrayList<>(); - - /** - * Recipe data that, when sent to the client, enables cartography features. - * This does not have a Java equivalent. - */ - public static final List CARTOGRAPHY_RECIPE_DATA = new ObjectArrayList<>(); - - /** - * Recipe data that, when sent to the client, enables book cloning - */ - public static final CraftingData BOOK_CLONING_RECIPE_DATA; - /** - * Recipe data that, when sent to the client, enables tool repairing in a crafting table - */ - public static final CraftingData TOOL_REPAIRING_RECIPE_DATA; - /** - * Recipe data that, when sent to the client, enables map extending in a crafting table - */ - public static final CraftingData MAP_EXTENDING_RECIPE_DATA; - /** - * Recipe data that, when sent to the client, enables map cloning in a crafting table - */ - public static final CraftingData MAP_CLONING_RECIPE_DATA; - /** - * Recipe data that, when sent to the client, enables banner duplicating - */ - public static final CraftingData BANNER_DUPLICATING_RECIPE_DATA; - - - static { - BOOK_CLONING_RECIPE_DATA = CraftingData.fromMulti(UUID.fromString("d1ca6b84-338e-4f2f-9c6b-76cc8b4bd98d"), LAST_RECIPE_NET_ID++); - TOOL_REPAIRING_RECIPE_DATA = CraftingData.fromMulti(UUID.fromString("00000000-0000-0000-0000-000000000001"), LAST_RECIPE_NET_ID++); - MAP_EXTENDING_RECIPE_DATA = CraftingData.fromMulti(UUID.fromString("d392b075-4ba1-40ae-8789-af868d56f6ce"), LAST_RECIPE_NET_ID++); - MAP_CLONING_RECIPE_DATA = CraftingData.fromMulti(UUID.fromString("85939755-ba10-4d9d-a4cc-efb7a8e943c4"), LAST_RECIPE_NET_ID++); - BANNER_DUPLICATING_RECIPE_DATA = CraftingData.fromMulti(UUID.fromString("b5c5d105-75a2-4076-af2b-923ea2bf4bf0"), LAST_RECIPE_NET_ID++); - - CARTOGRAPHY_RECIPE_DATA.add(CraftingData.fromMulti(UUID.fromString("8b36268c-1829-483c-a0f1-993b7156a8f2"), LAST_RECIPE_NET_ID++)); // Map extending - CARTOGRAPHY_RECIPE_DATA.add(CraftingData.fromMulti(UUID.fromString("442d85ed-8272-4543-a6f1-418f90ded05d"), LAST_RECIPE_NET_ID++)); // Map cloning - CARTOGRAPHY_RECIPE_DATA.add(CraftingData.fromMulti(UUID.fromString("98c84b38-1085-46bd-b1ce-dd38c159e6cc"), LAST_RECIPE_NET_ID++)); // Map upgrading - CARTOGRAPHY_RECIPE_DATA.add(CraftingData.fromMulti(UUID.fromString("602234e4-cac1-4353-8bb7-b1ebff70024b"), LAST_RECIPE_NET_ID++)); // Map locking - // https://github.com/pmmp/PocketMine-MP/blob/stable/src/pocketmine/inventory/MultiRecipe.php - - // Get all recipes that are not directly sent from a Java server + public static void populate() { InputStream stream = FileUtils.getResource("mappings/recipes.json"); JsonNode items; try { items = GeyserConnector.JSON_MAPPER.readTree(stream); } catch (Exception e) { - throw new AssertionError("Unable to load Java runtime item IDs", e); + throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.runtime_java"), e); } - for (JsonNode entry : items.get("leather_armor")) { - // This won't be perfect, as we can't possibly send every leather input for every kind of color - // But it does display the correct output from a base leather armor, and besides visuals everything works fine - LEATHER_DYEING_RECIPES.add(getCraftingDataFromJsonNode(entry)); - } - for (JsonNode entry : items.get("firework_rockets")) { - FIREWORK_ROCKET_RECIPES.add(getCraftingDataFromJsonNode(entry)); - } - for (JsonNode entry : items.get("firework_stars")) { - FIREWORK_STAR_RECIPES.add(getCraftingDataFromJsonNode(entry)); - } - for (JsonNode entry : items.get("shulker_boxes")) { - SHULKER_BOX_DYEING_RECIPES.add(getCraftingDataFromJsonNode(entry)); - } - for (JsonNode entry : items.get("suspicious_stew")) { - SUSPICIOUS_STEW_RECIPES.add(getCraftingDataFromJsonNode(entry)); - } - for (JsonNode entry : items.get("tipped_arrows")) { - TIPPED_ARROW_RECIPES.add(getCraftingDataFromJsonNode(entry)); + int currentRecipeId = LAST_RECIPE_NET_ID; + for (Map.Entry version : Registries.ITEMS.get().entrySet()) { + // Make a bit of an assumption here that the last recipe net ID will be equivalent between all versions + LAST_RECIPE_NET_ID = currentRecipeId; + Map> craftingData = new EnumMap<>(RecipeType.class); + Int2ObjectMap recipes = new Int2ObjectOpenHashMap<>(); + + craftingData.put(RecipeType.CRAFTING_SPECIAL_BOOKCLONING, + Collections.singletonList(CraftingData.fromMulti(UUID.fromString("d1ca6b84-338e-4f2f-9c6b-76cc8b4bd98d"), ++LAST_RECIPE_NET_ID))); + craftingData.put(RecipeType.CRAFTING_SPECIAL_REPAIRITEM, + Collections.singletonList(CraftingData.fromMulti(UUID.fromString("00000000-0000-0000-0000-000000000001"), ++LAST_RECIPE_NET_ID))); + craftingData.put(RecipeType.CRAFTING_SPECIAL_MAPEXTENDING, + Collections.singletonList(CraftingData.fromMulti(UUID.fromString("d392b075-4ba1-40ae-8789-af868d56f6ce"), ++LAST_RECIPE_NET_ID))); + craftingData.put(RecipeType.CRAFTING_SPECIAL_MAPCLONING, + Collections.singletonList(CraftingData.fromMulti(UUID.fromString("85939755-ba10-4d9d-a4cc-efb7a8e943c4"), ++LAST_RECIPE_NET_ID))); + craftingData.put(RecipeType.CRAFTING_SPECIAL_BANNERADDPATTERN, + Collections.singletonList(CraftingData.fromMulti(UUID.fromString("b5c5d105-75a2-4076-af2b-923ea2bf4bf0"), ++LAST_RECIPE_NET_ID))); + + // https://github.com/pmmp/PocketMine-MP/blob/stable/src/pocketmine/inventory/MultiRecipe.php + + for (JsonNode entry : items.get("leather_armor")) { + // This won't be perfect, as we can't possibly send every leather input for every kind of color + // But it does display the correct output from a base leather armor, and besides visuals everything works fine + craftingData.computeIfAbsent(RecipeType.CRAFTING_SPECIAL_ARMORDYE, + c -> new ObjectArrayList<>()).add(getCraftingDataFromJsonNode(entry, recipes, version.getValue())); + } + for (JsonNode entry : items.get("firework_rockets")) { + craftingData.computeIfAbsent(RecipeType.CRAFTING_SPECIAL_FIREWORK_ROCKET, + c -> new ObjectArrayList<>()).add(getCraftingDataFromJsonNode(entry, recipes, version.getValue())); + } + for (JsonNode entry : items.get("firework_stars")) { + craftingData.computeIfAbsent(RecipeType.CRAFTING_SPECIAL_FIREWORK_STAR, + c -> new ObjectArrayList<>()).add(getCraftingDataFromJsonNode(entry, recipes, version.getValue())); + } + for (JsonNode entry : items.get("shulker_boxes")) { + craftingData.computeIfAbsent(RecipeType.CRAFTING_SPECIAL_SHULKERBOXCOLORING, + c -> new ObjectArrayList<>()).add(getCraftingDataFromJsonNode(entry, recipes, version.getValue())); + } + for (JsonNode entry : items.get("suspicious_stew")) { + craftingData.computeIfAbsent(RecipeType.CRAFTING_SPECIAL_SUSPICIOUSSTEW, + c -> new ObjectArrayList<>()).add(getCraftingDataFromJsonNode(entry, recipes, version.getValue())); + } + for (JsonNode entry : items.get("tipped_arrows")) { + craftingData.computeIfAbsent(RecipeType.CRAFTING_SPECIAL_TIPPEDARROW, + c -> new ObjectArrayList<>()).add(getCraftingDataFromJsonNode(entry, recipes, version.getValue())); + } + + Registries.CRAFTING_DATA.register(version.getKey(), craftingData); + Registries.RECIPES.register(version.getKey(), recipes); } } /** * Computes a Bedrock crafting recipe from the given JSON data. * @param node the JSON data to compute + * @param recipes a list of all the recipes * @return the {@link CraftingData} to send to the Bedrock client. */ - private static CraftingData getCraftingDataFromJsonNode(JsonNode node) { - int netId = LAST_RECIPE_NET_ID++; + private static CraftingData getCraftingDataFromJsonNode(JsonNode node, Int2ObjectMap recipes, ItemMappings mappings) { + int netId = ++LAST_RECIPE_NET_ID; int type = node.get("bedrockRecipeType").asInt(); JsonNode outputNode = node.get("output"); - ItemEntry outputEntry = ItemRegistry.getItemEntry(outputNode.get("identifier").asText()); + ItemMapping outputEntry = mappings.getMapping(outputNode.get("identifier").asText()); ItemData output = getBedrockItemFromIdentifierJson(outputEntry, outputNode); UUID uuid = UUID.randomUUID(); if (type == 1) { @@ -194,7 +145,7 @@ public class RecipeRegistry { while (iterator.hasNext()) { Map.Entry entry = iterator.next(); JsonNode inputNode = entry.getValue(); - ItemEntry inputEntry = ItemRegistry.getItemEntry(inputNode.get("identifier").asText()); + ItemMapping inputEntry = mappings.getMapping(inputNode.get("identifier").asText()); letterToRecipe.put(entry.getKey(), getBedrockItemFromIdentifierJson(inputEntry, inputNode)); } @@ -212,12 +163,12 @@ public class RecipeRegistry { /* Convert into a Java recipe class for autocrafting */ List ingredients = new ArrayList<>(); for (ItemData input : inputs) { - ingredients.add(new Ingredient(new ItemStack[]{ItemTranslator.translateToJava(input)})); + ingredients.add(new Ingredient(new ItemStack[]{ItemTranslator.translateToJava(input, mappings)})); } ShapedRecipeData data = new ShapedRecipeData(shape.get(0).length(), shape.size(), "crafting_table", - ingredients.toArray(new Ingredient[0]), ItemTranslator.translateToJava(output)); + ingredients.toArray(new Ingredient[0]), ItemTranslator.translateToJava(output, mappings)); Recipe recipe = new Recipe(RecipeType.CRAFTING_SHAPED, "", data); - ALL_CRAFTING_RECIPES.put(netId, recipe); + recipes.put(netId, recipe); /* Convert end */ return CraftingData.fromShaped(uuid.toString(), shape.get(0).length(), shape.size(), @@ -225,19 +176,19 @@ public class RecipeRegistry { } List inputs = new ObjectArrayList<>(); for (JsonNode entry : node.get("inputs")) { - ItemEntry inputEntry = ItemRegistry.getItemEntry(entry.get("identifier").asText()); + ItemMapping inputEntry = mappings.getMapping(entry.get("identifier").asText()); inputs.add(getBedrockItemFromIdentifierJson(inputEntry, entry)); } /* Convert into a Java Recipe class for autocrafting */ List ingredients = new ArrayList<>(); for (ItemData input : inputs) { - ingredients.add(new Ingredient(new ItemStack[]{ItemTranslator.translateToJava(input)})); + ingredients.add(new Ingredient(new ItemStack[]{ItemTranslator.translateToJava(input, mappings)})); } ShapelessRecipeData data = new ShapelessRecipeData("crafting_table", - ingredients.toArray(new Ingredient[0]), ItemTranslator.translateToJava(output)); + ingredients.toArray(new Ingredient[0]), ItemTranslator.translateToJava(output, mappings)); Recipe recipe = new Recipe(RecipeType.CRAFTING_SHAPELESS, "", data); - ALL_CRAFTING_RECIPES.put(netId, recipe); + recipes.put(netId, recipe); /* Convert end */ if (type == 5) { @@ -249,7 +200,7 @@ public class RecipeRegistry { inputs, Collections.singletonList(output), uuid, "crafting_table", 0, netId); } - private static ItemData getBedrockItemFromIdentifierJson(ItemEntry itemEntry, JsonNode itemNode) { + private static ItemData getBedrockItemFromIdentifierJson(ItemMapping mapping, JsonNode itemNode) { int count = 1; short damage = 0; NbtMap tag = null; @@ -272,14 +223,11 @@ public class RecipeRegistry { } } return ItemData.builder() - .id(itemEntry.getBedrockId()) + .id(mapping.getBedrockId()) .damage(damage) .count(count) - .blockRuntimeId(itemEntry.isBlock() ? itemEntry.getBedrockBlockId() : 0) - .tag(tag).build(); + .blockRuntimeId(mapping.isBlock() ? mapping.getBedrockBlockId() : 0) + .tag(tag) + .build(); } - - public static void init() { - // no-op - } -} +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/registry/type/BlockMappings.java b/connector/src/main/java/org/geysermc/connector/registry/type/BlockMappings.java new file mode 100644 index 000000000..0cadcf232 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/type/BlockMappings.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry.type; + +import com.nukkitx.nbt.NbtList; +import com.nukkitx.nbt.NbtMap; +import it.unimi.dsi.fastutil.ints.Int2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import lombok.Builder; +import lombok.Value; +import org.geysermc.connector.network.translators.world.chunk.ChunkSection; + +import java.util.Map; + +@Builder +@Value +public class BlockMappings { + int bedrockAirId; + int bedrockWaterId; + + int blockStateVersion; + + ChunkSection emptyChunkSection; + + Int2IntMap javaToBedrockBlockMap; + Int2IntMap bedrockToJavaBlockMap; + + NbtList bedrockBlockStates; + + /** + * Contains a map of Java blocks to their respective Bedrock block tag, if the Java identifier is different from Bedrock. + * Required to fix villager trades with these blocks. + */ + Map javaIdentifierToBedrockTag; + + int commandBlockRuntimeId; + + Object2IntMap itemFrames; + Map flowerPotBlocks; + + public int getBedrockBlockId(int state) { + return this.javaToBedrockBlockMap.get(state); + } + + public int getJavaBlockState(int bedrockId) { + return this.bedrockToJavaBlockMap.get(bedrockId); + } + + public int getItemFrame(NbtMap tag) { + return this.itemFrames.getOrDefault(tag, -1); + } + + public boolean isItemFrame(int bedrockBlockRuntimeId) { + return this.itemFrames.values().contains(bedrockBlockRuntimeId); + } + + /** + * @param cleanJavaIdentifier the clean Java identifier of the block to look up + * + * @return the block tag of the block name mapped from Java to Bedrock. + */ + public NbtMap getBedrockBlockNbt(String cleanJavaIdentifier) { + return this.javaIdentifierToBedrockTag.get(cleanJavaIdentifier); + } +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/TranslatableItemEntry.java b/connector/src/main/java/org/geysermc/connector/registry/type/GeyserMappingItem.java similarity index 65% rename from connector/src/main/java/org/geysermc/connector/network/translators/item/TranslatableItemEntry.java rename to connector/src/main/java/org/geysermc/connector/registry/type/GeyserMappingItem.java index 3967abb17..9219a8793 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/TranslatableItemEntry.java +++ b/connector/src/main/java/org/geysermc/connector/registry/type/GeyserMappingItem.java @@ -23,19 +23,20 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.item; +package org.geysermc.connector.registry.type; -import lombok.Getter; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; /** - * Used when an item should have a custom name applied, if there already isn't one. + * Represents Geyser's own serialized item information before being processed per-version */ -public class TranslatableItemEntry extends ItemEntry { - @Getter - private final String translationString; - - public TranslatableItemEntry(String javaIdentifier, String bedrockIdentifier, int javaId, int bedrockId, int bedrockData, int bedrockBlockId, int stackSize) { - super(javaIdentifier, bedrockIdentifier, javaId, bedrockId, bedrockData, bedrockBlockId, stackSize); - this.translationString = (isBlock() ? "block." : "item.") + javaIdentifier.replace(":", "."); - } +@Data +public class GeyserMappingItem { + @JsonProperty("bedrock_identifier") String bedrockIdentifier; + @JsonProperty("bedrock_data") int bedrockData; + Integer blockRuntimeId; + @JsonProperty("stack_size") Integer stackSize; + @JsonProperty("tool_type") String toolType; + @JsonProperty("tool_tier") String toolTier; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemEntry.java b/connector/src/main/java/org/geysermc/connector/registry/type/ItemMapping.java similarity index 52% rename from connector/src/main/java/org/geysermc/connector/network/translators/item/ItemEntry.java rename to connector/src/main/java/org/geysermc/connector/registry/type/ItemMapping.java index 74ce0951f..fff00950b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemEntry.java +++ b/connector/src/main/java/org/geysermc/connector/registry/type/ItemMapping.java @@ -23,38 +23,64 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.item; +package org.geysermc.connector.registry.type; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.ToString; -import org.geysermc.connector.network.translators.world.block.BlockTranslator1_17_0; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Value; +import org.geysermc.connector.network.BedrockProtocol; +import org.geysermc.connector.registry.BlockRegistries; -@Getter -@AllArgsConstructor -@ToString -public class ItemEntry { - public static final ItemEntry AIR = new ItemEntry("minecraft:air", "minecraft:air", 0, 0, 0, - BlockTranslator1_17_0.INSTANCE.getBedrockAirId(), 64); +@Value +@Builder +@EqualsAndHashCode +public class ItemMapping { + public static final ItemMapping AIR = new ItemMapping("minecraft:air", "minecraft:air", 0, 0, 0, + BlockRegistries.BLOCKS.forVersion(BedrockProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()).getBedrockAirId(), + 64, null, null, null); + + String javaIdentifier; + String bedrockIdentifier; + int javaId; + int bedrockId; + int bedrockData; - private final String javaIdentifier; - private final String bedrockIdentifier; - private final int javaId; - private final int bedrockId; - private final int bedrockData; /** * The Bedrock block runtime ID to render this item with. The specific state *does* matter in how this item is rendered and used as a crafting ingredient. * Required since 1.16.220. */ - private final int bedrockBlockId; - private final int stackSize; + int bedrockBlockId; + int stackSize; + String toolType; + String toolTier; + + String translationString; + + /** + * Gets if this item is a block. + * + * @return if this item is a block + */ public boolean isBlock() { - return bedrockBlockId != -1; + return this.bedrockBlockId != -1; } - @Override - public boolean equals(Object obj) { - return obj == this || (obj instanceof ItemEntry && ((ItemEntry) obj).getBedrockId() == this.getBedrockId() && ((ItemEntry) obj).getJavaIdentifier().equals(this.getJavaIdentifier())); + /** + * Gets if this item has a translation string present. + * + * @return if this item has a translation string present + */ + public boolean hasTranslation() { + return this.translationString != null; } -} + + /** + * Gets if this item is a tool. + * + * @return if this item is a tool + */ + public boolean isTool() { + return this.toolType != null; + } +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/registry/type/ItemMappings.java b/connector/src/main/java/org/geysermc/connector/registry/type/ItemMappings.java new file mode 100644 index 000000000..767b6b2e0 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/type/ItemMappings.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry.type; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.nukkitx.protocol.bedrock.data.inventory.ComponentItemData; +import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.packet.StartGamePacket; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.IntList; +import lombok.Builder; +import lombok.Value; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.network.translators.item.StoredItemMappings; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; + +@Builder +@Value +public class ItemMappings { + + Map cachedJavaMappings = new WeakHashMap<>(); + + Int2ObjectMap items; + + ItemData[] creativeItems; + List itemEntries; + + StoredItemMappings storedItems; + String[] itemNames; + Set javaOnlyItems; + + IntList bucketIds; + IntList boatIds; + IntList spawnEggIds; + List carpets; + + @Nullable ComponentItemData furnaceMinecartData; + + /** + * Gets an {@link ItemMapping} from the given {@link ItemStack}. + * + * @param itemStack the itemstack + * @return an item entry from the given java edition identifier + */ + public ItemMapping getMapping(ItemStack itemStack) { + return this.getMapping(itemStack.getId()); + } + + /** + * Gets an {@link ItemMapping} from the given Minecraft: Java + * Edition id. + * + * @param javaId the id + * @return an item entry from the given java edition identifier + */ + public ItemMapping getMapping(int javaId) { + return this.items.get(javaId); + } + + /** + * Gets an {@link ItemMapping} from the given Minecraft: Java Edition + * block state identifier. + * + * @param javaIdentifier the block state identifier + * @return an item entry from the given java edition identifier + */ + public ItemMapping getMapping(String javaIdentifier) { + return this.cachedJavaMappings.computeIfAbsent(javaIdentifier, key -> { + for (ItemMapping mapping : this.items.values()) { + if (mapping.getJavaIdentifier().equals(key)) { + return mapping; + } + } + return null; + }); + } + + /** + * Gets an {@link ItemMapping} from the given {@link ItemData}. + * + * @param data the item data + * @return an item entry from the given item data + */ + public ItemMapping getMapping(ItemData data) { + boolean isBlock = data.getBlockRuntimeId() != 0; + boolean hasDamage = data.getDamage() != 0; + + for (ItemMapping mapping : this.items.values()) { + if (mapping.getBedrockId() == data.getId()) { + if (isBlock && !hasDamage) { // Pre-1.16.220 will not use block runtime IDs at all, so we shouldn't check either + if (data.getBlockRuntimeId() != mapping.getBedrockBlockId()) { + continue; + } + } else { + if (!(mapping.getBedrockData() == data.getDamage() || + // Make exceptions for potions and tipped arrows, whose damage values can vary + (mapping.getJavaIdentifier().endsWith("potion") || mapping.getJavaIdentifier().equals("minecraft:arrow")))) { + continue; + } + } + if (!this.javaOnlyItems.contains(mapping.getJavaIdentifier())) { + // From a Bedrock item data, we aren't getting one of these items + return mapping; + } + } + } + + // This will hide the message when the player clicks with an empty hand + if (data.getId() != 0 && data.getDamage() != 0) { + GeyserConnector.getInstance().getLogger().debug("Missing mapping for bedrock item " + data.getId() + ":" + data.getDamage()); + } + return ItemMapping.AIR; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/registry/type/PaletteItem.java b/connector/src/main/java/org/geysermc/connector/registry/type/PaletteItem.java new file mode 100644 index 000000000..4582d1e80 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/type/PaletteItem.java @@ -0,0 +1,35 @@ + +/* + * Copyright (c) 2019-2021 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.connector.registry.type; + +import lombok.Data; + +@Data +public class PaletteItem { + String name; + int id; +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/registry/type/ParticleMapping.java b/connector/src/main/java/org/geysermc/connector/registry/type/ParticleMapping.java new file mode 100644 index 000000000..2ed21ddb3 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/type/ParticleMapping.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry.type; + +import com.nukkitx.protocol.bedrock.data.LevelEventType; +import lombok.Value; + +import javax.annotation.ParametersAreNullableByDefault; + +@Value +@ParametersAreNullableByDefault +public class ParticleMapping { + LevelEventType levelEventType; + String identifier; + int id; +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/registry/type/SoundMapping.java b/connector/src/main/java/org/geysermc/connector/registry/type/SoundMapping.java new file mode 100644 index 000000000..ba0bcd862 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/registry/type/SoundMapping.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2019-2021 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.connector.registry.type; + +import lombok.Value; + +@Value +public class SoundMapping { + String java; + String bedrock; + String playsound; + int extraData; + String identifier; + boolean levelEvent; + + public SoundMapping(String java, String bedrock, String playsound, int extraData, String identifier, boolean levelEvent) { + this.java = java; + this.bedrock = bedrock == null || bedrock.equalsIgnoreCase("") ? null : bedrock; + this.playsound = playsound == null || playsound.equalsIgnoreCase("") ? null : playsound; + this.extraData = extraData; + this.identifier = identifier == null || identifier.equalsIgnoreCase("") ? ":" : identifier; + this.levelEvent = levelEvent; + } +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/BiomeTranslator.java b/connector/src/main/java/org/geysermc/connector/utils/BiomeUtils.java similarity index 70% rename from connector/src/main/java/org/geysermc/connector/network/translators/BiomeTranslator.java rename to connector/src/main/java/org/geysermc/connector/utils/BiomeUtils.java index d797381ce..650367a4a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/BiomeTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/utils/BiomeUtils.java @@ -1,95 +1,63 @@ -/* - * Copyright (c) 2019-2021 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.connector.network.translators; - -import com.nukkitx.nbt.NBTInputStream; -import com.nukkitx.nbt.NbtMap; -import com.nukkitx.nbt.NbtUtils; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.utils.FileUtils; - -import java.io.InputStream; -import java.util.Arrays; - -// Based off of ProtocolSupport's LegacyBiomeData.java: -// https://github.com/ProtocolSupport/ProtocolSupport/blob/b2cad35977f3fcb65bee57b9e14fc9c975f71d32/src/protocolsupport/protocol/typeremapper/legacy/LegacyBiomeData.java -// Array index formula by https://wiki.vg/Chunk_Format -public class BiomeTranslator { - - public static final NbtMap BIOMES; - - private BiomeTranslator() { - } - - public static void init() { - // no-op - } - - static { - /* Load biomes */ - InputStream stream = FileUtils.getResource("bedrock/biome_definitions.dat"); - - NbtMap biomesTag; - - try (NBTInputStream biomenbtInputStream = NbtUtils.createNetworkReader(stream)) { - biomesTag = (NbtMap) biomenbtInputStream.readTag(); - BIOMES = biomesTag; - } catch (Exception ex) { - GeyserConnector.getInstance().getLogger().warning("Failed to get biomes from biome definitions, is there something wrong with the file?"); - throw new AssertionError(ex); - } - } - - public static byte[] toBedrockBiome(int[] biomeData) { - byte[] bedrockData = new byte[256]; - if (biomeData == null) { - return bedrockData; - } - - for (int y = 0; y < 16; y += 4) { - for (int z = 0; z < 16; z += 4) { - for (int x = 0; x < 16; x += 4) { - byte biomeId = biomeID(biomeData, x, y, z); - int offset = ((z + (y / 4)) << 4) | x; - Arrays.fill(bedrockData, offset, offset + 4, biomeId); - } - } - } - return bedrockData; - } - - private static byte biomeID(int[] biomeData, int x, int y, int z) { - int biomeId = biomeData[((y >> 2) & 63) << 4 | ((z >> 2) & 3) << 2 | ((x >> 2) & 3)]; - if (biomeId == 0) { - biomeId = 42; // Ocean - } else if (biomeId >= 40 && biomeId <= 43) { // Java has multiple End dimensions that Bedrock doesn't recognize - biomeId = 9; - } else if (biomeId >= 170) { // Nether biomes. Dunno why it's like this :microjang: - biomeId += 8; - } - return (byte) biomeId; - } -} +/* + * Copyright (c) 2019-2021 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.connector.utils; + +import java.util.Arrays; + +// Based off of ProtocolSupport's LegacyBiomeData.java: +// https://github.com/ProtocolSupport/ProtocolSupport/blob/b2cad35977f3fcb65bee57b9e14fc9c975f71d32/src/protocolsupport/protocol/typeremapper/legacy/LegacyBiomeData.java +// Array index formula by https://wiki.vg/Chunk_Format +public class BiomeUtils { + public static byte[] toBedrockBiome(int[] biomeData) { + byte[] bedrockData = new byte[256]; + if (biomeData == null) { + return bedrockData; + } + + for (int y = 0; y < 16; y += 4) { + for (int z = 0; z < 16; z += 4) { + for (int x = 0; x < 16; x += 4) { + byte biomeId = biomeID(biomeData, x, y, z); + int offset = ((z + (y / 4)) << 4) | x; + Arrays.fill(bedrockData, offset, offset + 4, biomeId); + } + } + } + return bedrockData; + } + + private static byte biomeID(int[] biomeData, int x, int y, int z) { + int biomeId = biomeData[((y >> 2) & 63) << 4 | ((z >> 2) & 3) << 2 | ((x >> 2) & 3)]; + if (biomeId == 0) { + biomeId = 42; // Ocean + } else if (biomeId >= 40 && biomeId <= 43) { // Java has multiple End dimensions that Bedrock doesn't recognize + biomeId = 9; + } else if (biomeId >= 170) { // Nether biomes. Dunno why it's like this :microjang: + biomeId += 8; + } + return (byte) biomeId; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java b/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java index d932c7d24..97a5e90db 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java @@ -29,17 +29,56 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.world.block.entity.BedrockOnlyBlockEntity; import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator; +import org.geysermc.connector.registry.Registries; + +import java.util.HashMap; +import java.util.Map; import javax.annotation.Nonnull; public class BlockEntityUtils { - private static final BlockEntityTranslator EMPTY_TRANSLATOR = BlockEntityTranslator.BLOCK_ENTITY_TRANSLATORS.get("Empty"); + /** + * A list of all block entities that require the Java block state in order to fill out their block entity information. + * This list will be smaller with cache chunks on as we don't need to double-cache data + */ + public static final ObjectArrayList BEDROCK_ONLY_BLOCK_ENTITIES = new ObjectArrayList<>(); + + /** + * Contains a list of irregular block entity name translations that can't be fit into the regex + */ + public static final Map BLOCK_ENTITY_TRANSLATIONS = new HashMap() { + { + // Bedrock/Java differences + put("minecraft:enchanting_table", "EnchantTable"); + put("minecraft:jigsaw", "JigsawBlock"); + put("minecraft:piston_head", "PistonArm"); + put("minecraft:trapped_chest", "Chest"); + // There are some legacy IDs sent but as far as I can tell they are not needed for things to work properly + } + }; + + private static final BlockEntityTranslator EMPTY_TRANSLATOR = Registries.BLOCK_ENTITIES.get("Empty"); + + static { + for (BlockEntityTranslator translator : Registries.BLOCK_ENTITIES.get().values()) { + if (!(translator instanceof BedrockOnlyBlockEntity)) { + continue; + } + + GeyserConnector.getInstance().getLogger().debug("Found Bedrock-only block entity: " + translator.getClass().getCanonicalName()); + BedrockOnlyBlockEntity bedrockOnlyBlockEntity = (BedrockOnlyBlockEntity) translator; + BEDROCK_ONLY_BLOCK_ENTITIES.add(bedrockOnlyBlockEntity); + } + } public static String getBedrockBlockEntityId(String id) { // These are the only exceptions when it comes to block entity ids - String value = BlockEntityTranslator.BLOCK_ENTITY_TRANSLATIONS.get(id); + String value = BLOCK_ENTITY_TRANSLATIONS.get(id); if (value != null) { return value; } @@ -61,7 +100,7 @@ public class BlockEntityUtils { } public static BlockEntityTranslator getBlockEntityTranslator(String name) { - BlockEntityTranslator blockEntityTranslator = BlockEntityTranslator.BLOCK_ENTITY_TRANSLATORS.get(name); + BlockEntityTranslator blockEntityTranslator = Registries.BLOCK_ENTITIES.get(name); if (blockEntityTranslator != null) { return blockEntityTranslator; } diff --git a/connector/src/main/java/org/geysermc/connector/utils/BlockUtils.java b/connector/src/main/java/org/geysermc/connector/utils/BlockUtils.java index 0ad3f0148..ea613ef6b 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/BlockUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/BlockUtils.java @@ -32,10 +32,11 @@ import com.nukkitx.math.vector.Vector3i; import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ToolItemEntry; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.collision.translators.BlockCollision; +import org.geysermc.connector.network.translators.world.block.BlockStateValues; +import org.geysermc.connector.registry.Registries; import org.geysermc.connector.registry.type.BlockMapping; +import org.geysermc.connector.registry.type.ItemMapping; public class BlockUtils { /** @@ -56,7 +57,7 @@ public class BlockUtils { case "shovel": return session.getTagCache().isShovelEffective(blockMapping); case "sword": - return blockMapping.getJavaBlockId() == BlockTranslator.JAVA_COBWEB_BLOCK_ID; + return blockMapping.getJavaBlockId() == BlockStateValues.JAVA_COBWEB_ID; default: session.getConnector().getLogger().warning("Unknown tool type: " + itemToolType); return false; @@ -146,17 +147,16 @@ public class BlockUtils { return 1.0 / speed; } - public static double getBreakTime(GeyserSession session, BlockMapping blockMapping, ItemEntry item, CompoundTag nbtData, boolean isSessionPlayer) { + public static double getBreakTime(GeyserSession session, BlockMapping blockMapping, ItemMapping item, CompoundTag nbtData, boolean isSessionPlayer) { boolean isShearsEffective = session.getTagCache().isShearsEffective(blockMapping); //TODO called twice boolean canHarvestWithHand = blockMapping.isCanBreakWithHand(); String toolType = ""; String toolTier = ""; boolean correctTool = false; boolean toolCanBreak = false; - if (item instanceof ToolItemEntry) { - ToolItemEntry toolItem = (ToolItemEntry) item; - toolType = toolItem.getToolType(); - toolTier = toolItem.getToolTier(); + if (item.isTool()) { + toolType = item.getToolType(); + toolTier = item.getToolTier(); correctTool = correctTool(session, blockMapping, toolType); toolCanBreak = canToolTierBreakBlock(session, blockMapping, toolTier); } @@ -189,16 +189,16 @@ public class BlockUtils { public static double getSessionBreakTime(GeyserSession session, BlockMapping blockMapping) { PlayerInventory inventory = session.getPlayerInventory(); GeyserItemStack item = inventory.getItemInHand(); - ItemEntry itemEntry; + ItemMapping mapping; CompoundTag nbtData; if (item != null) { - itemEntry = item.getItemEntry(); + mapping = item.getMapping(session); nbtData = item.getNbt(); } else { - itemEntry = null; + mapping = ItemMapping.AIR; nbtData = new CompoundTag(""); } - return getBreakTime(session, blockMapping, itemEntry, nbtData, true); + return getBreakTime(session, blockMapping, mapping, nbtData, true); } /** @@ -225,4 +225,16 @@ public class BlockUtils { return blockPos; } + // Note: these reuse classes, so don't try to store more than once instance or coordinates will get overwritten + public static BlockCollision getCollision(int blockId, int x, int y, int z) { + BlockCollision collision = Registries.COLLISIONS.get(blockId); + if (collision != null) { + collision.setPosition(x, y, z); + } + return collision; + } + + public static BlockCollision getCollisionAt(GeyserSession session, int x, int y, int z) { + return getCollision(session.getConnector().getWorldManager().getBlockAt(session, x, y, z), x, y, z); + } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java b/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java index 343f5c53e..5681e1d4f 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java @@ -51,7 +51,6 @@ import org.geysermc.connector.entity.player.SkullPlayerEntity; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.translators.LecternInventoryTranslator; import org.geysermc.connector.network.translators.world.block.BlockStateValues; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.network.translators.world.block.entity.BedrockOnlyBlockEntity; import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator; import org.geysermc.connector.network.translators.world.block.entity.SkullBlockEntityTranslator; @@ -59,12 +58,13 @@ import org.geysermc.connector.network.translators.world.chunk.BlockStorage; import org.geysermc.connector.network.translators.world.chunk.ChunkSection; import org.geysermc.connector.network.translators.world.chunk.bitarray.BitArray; import org.geysermc.connector.network.translators.world.chunk.bitarray.BitArrayVersion; +import org.geysermc.connector.registry.BlockRegistries; import java.util.ArrayList; import java.util.BitSet; import java.util.List; -import static org.geysermc.connector.network.translators.world.block.BlockTranslator.JAVA_AIR_ID; +import static org.geysermc.connector.network.translators.world.block.BlockStateValues.JAVA_AIR_ID; @UtilityClass public class ChunkUtils { @@ -109,15 +109,15 @@ public class ChunkUtils { if (javaPalette instanceof GlobalPalette) { // As this is the global palette, simply iterate through the whole chunk section once - ChunkSection section = new ChunkSection(session.getBlockTranslator().getBedrockAirId()); + ChunkSection section = new ChunkSection(session.getBlockMappings().getBedrockAirId()); for (int yzx = 0; yzx < BlockStorage.SIZE; yzx++) { int javaId = javaData.get(yzx); - int bedrockId = session.getBlockTranslator().getBedrockBlockId(javaId); + int bedrockId = session.getBlockMappings().getBedrockBlockId(javaId); int xzy = indexYZXtoXZY(yzx); section.getBlockStorageArray()[0].setFullBlock(xzy, bedrockId); - if (BlockTranslator.isWaterlogged(javaId)) { - section.getBlockStorageArray()[1].setFullBlock(xzy, session.getBlockTranslator().getBedrockWaterId()); + if (BlockRegistries.WATERLOGGED.get().contains(javaId)) { + section.getBlockStorageArray()[1].setFullBlock(xzy, session.getBlockMappings().getBedrockWaterId()); } // Check if block is piston or flower to see if we'll need to create additional block entities, as they're only block entities in Bedrock @@ -139,9 +139,9 @@ public class ChunkUtils { // Iterate through palette and convert state IDs to Bedrock, doing some additional checks as we go for (int i = 0; i < javaPalette.size(); i++) { int javaId = javaPalette.idToState(i); - bedrockPalette.add(session.getBlockTranslator().getBedrockBlockId(javaId)); + bedrockPalette.add(session.getBlockMappings().getBedrockBlockId(javaId)); - if (BlockTranslator.isWaterlogged(javaId)) { + if (BlockRegistries.WATERLOGGED.get().contains(javaId)) { waterloggedPaletteIds.set(i); } @@ -195,8 +195,8 @@ public class ChunkUtils { // V1 palette IntList layer1Palette = new IntArrayList(2); - layer1Palette.add(session.getBlockTranslator().getBedrockAirId()); // Air - see BlockStorage's constructor for more information - layer1Palette.add(session.getBlockTranslator().getBedrockWaterId()); + layer1Palette.add(session.getBlockMappings().getBedrockAirId()); // Air - see BlockStorage's constructor for more information + layer1Palette.add(session.getBlockMappings().getBedrockWaterId()); layers = new BlockStorage[]{ layer0, new BlockStorage(BitArrayVersion.V1.createArray(BlockStorage.SIZE, layer1Data), layer1Palette) }; } @@ -317,7 +317,7 @@ public class ChunkUtils { skull.despawnEntity(session, position); } - int blockId = session.getBlockTranslator().getBedrockBlockId(blockState); + int blockId = session.getBlockMappings().getBedrockBlockId(blockState); UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); updateBlockPacket.setDataLayer(0); @@ -330,10 +330,10 @@ public class ChunkUtils { UpdateBlockPacket waterPacket = new UpdateBlockPacket(); waterPacket.setDataLayer(1); waterPacket.setBlockPosition(position); - if (BlockTranslator.isWaterlogged(blockState)) { - waterPacket.setRuntimeId(session.getBlockTranslator().getBedrockWaterId()); + if (BlockRegistries.WATERLOGGED.get().contains(blockState)) { + waterPacket.setRuntimeId(session.getBlockMappings().getBedrockWaterId()); } else { - waterPacket.setRuntimeId(session.getBlockTranslator().getBedrockAirId()); + waterPacket.setRuntimeId(session.getBlockMappings().getBedrockAirId()); } session.sendUpstreamPacket(waterPacket); @@ -364,7 +364,7 @@ public class ChunkUtils { // Iterates through all Bedrock-only block entity translators and determines if a manual block entity packet // needs to be sent - for (BedrockOnlyBlockEntity bedrockOnlyBlockEntity : BlockEntityTranslator.BEDROCK_ONLY_BLOCK_ENTITIES) { + for (BedrockOnlyBlockEntity bedrockOnlyBlockEntity : BlockEntityUtils.BEDROCK_ONLY_BLOCK_ENTITIES) { if (bedrockOnlyBlockEntity.isBlock(blockState)) { // Flower pots are block entities only in Bedrock and are not updated anywhere else like note blocks bedrockOnlyBlockEntity.updateBlock(session, blockState, position); @@ -383,7 +383,7 @@ public class ChunkUtils { data.setChunkX(chunkX + x); data.setChunkZ(chunkZ + z); data.setSubChunksLength(0); - data.setData(session.getBlockTranslator().getEmptyChunkData()); + data.setData(new byte[0]); data.setCachingEnabled(false); session.sendUpstreamPacket(data); diff --git a/connector/src/main/java/org/geysermc/connector/utils/CooldownUtils.java b/connector/src/main/java/org/geysermc/connector/utils/CooldownUtils.java index 43675ebfd..583c2ddae 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/CooldownUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/CooldownUtils.java @@ -61,6 +61,8 @@ public class CooldownUtils { SetTitlePacket titlePacket = new SetTitlePacket(); titlePacket.setType(SetTitlePacket.Type.TITLE); titlePacket.setText(" "); + titlePacket.setXuid(""); + titlePacket.setPlatformOnlineId(""); session.sendUpstreamPacket(titlePacket); session.setLastHitTime(System.currentTimeMillis()); long lastHitTime = session.getLastHitTime(); // Used later to prevent multiple scheduled cooldown threads @@ -86,6 +88,8 @@ public class CooldownUtils { titlePacket.setFadeInTime(0); titlePacket.setFadeOutTime(5); titlePacket.setStayTime(2); + titlePacket.setXuid(""); + titlePacket.setPlatformOnlineId(""); session.sendUpstreamPacket(titlePacket); if (hasCooldown(session)) { session.getConnector().getGeneralThreadPool().schedule(() -> computeCooldown(session, sessionPreference, lastHitTime), 50, TimeUnit.MILLISECONDS); // Updated per tick. 1000 divided by 20 ticks equals 50 @@ -97,6 +101,8 @@ public class CooldownUtils { removeTitlePacket.setType(SetTitlePacket.Type.SUBTITLE); } removeTitlePacket.setText(" "); + removeTitlePacket.setXuid(""); + removeTitlePacket.setPlatformOnlineId(""); session.sendUpstreamPacket(removeTitlePacket); } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/EffectUtils.java b/connector/src/main/java/org/geysermc/connector/utils/EffectUtils.java new file mode 100644 index 000000000..8d69fa691 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/utils/EffectUtils.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2019-2021 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.connector.utils; + +import com.github.steveice10.mc.protocol.data.game.world.particle.ParticleType; +import com.nukkitx.protocol.bedrock.data.LevelEventType; +import lombok.NonNull; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.registry.Registries; + +/** + * Util for particles and effects. + */ +public class EffectUtils { + + /** + * Used for area effect clouds. + * + * @param type the Java particle to search for + * @return the Bedrock integer ID of the particle, or -1 if it does not exist + */ + public static int getParticleId(GeyserSession session, @NonNull ParticleType type) { + LevelEventType levelEventType = Registries.PARTICLES.get(type).getLevelEventType(); + if (levelEventType == null) { + return -1; + } + + // Remove the legacy bit applied to particles for LevelEventType serialization + return session.getUpstream().getSession().getPacketCodec().getHelper().getLevelEventId(levelEventType) & ~0x4000; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/utils/InteractiveTagManager.java b/connector/src/main/java/org/geysermc/connector/utils/InteractiveTagManager.java index ce72c5d93..228a8d448 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/InteractiveTagManager.java +++ b/connector/src/main/java/org/geysermc/connector/utils/InteractiveTagManager.java @@ -34,7 +34,7 @@ import org.geysermc.connector.entity.living.animal.AnimalEntity; import org.geysermc.connector.entity.living.animal.horse.HorseEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.registry.type.ItemMapping; import java.util.EnumSet; import java.util.Set; @@ -61,8 +61,8 @@ public class InteractiveTagManager { */ public static void updateTag(GeyserSession session, Entity interactEntity) { EntityDataMap entityMetadata = interactEntity.getMetadata(); - ItemEntry itemEntry = session.getPlayerInventory().getItemInHand().getItemEntry(); - String javaIdentifierStripped = itemEntry.getJavaIdentifier().replace("minecraft:", ""); + ItemMapping mapping = session.getPlayerInventory().getItemInHand().getMapping(session); + String javaIdentifierStripped = mapping.getJavaIdentifier().replace("minecraft:", ""); InteractiveTag interactiveTag = InteractiveTag.NONE; @@ -83,7 +83,7 @@ public class InteractiveTagManager { // Holding a leash and the mob is leashable for sure // (Plugins can change this behavior so that's something to look into in the far far future) interactiveTag = InteractiveTag.LEASH; - } else if (interactEntity instanceof AnimalEntity && ((AnimalEntity) interactEntity).canEat(session, javaIdentifierStripped, itemEntry)) { + } else if (interactEntity instanceof AnimalEntity && ((AnimalEntity) interactEntity).canEat(session, javaIdentifierStripped, mapping)) { // This animal can be fed interactiveTag = InteractiveTag.FEED; } else { @@ -148,7 +148,7 @@ public class InteractiveTagManager { // Can't ride a baby if (tamed) { interactiveTag = InteractiveTag.RIDE_HORSE; - } else if (itemEntry.getJavaId() == 0) { + } else if (mapping.getJavaId() == 0) { // Can't hide an untamed entity without having your hand empty interactiveTag = InteractiveTag.MOUNT; } diff --git a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java index d9480d466..c9ddd8ed9 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java @@ -47,14 +47,21 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.inventory.translators.LecternInventoryTranslator; import org.geysermc.connector.network.translators.inventory.translators.chest.DoubleChestInventoryTranslator; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; +import org.geysermc.connector.registry.Registries; +import org.geysermc.connector.registry.type.ItemMapping; import java.util.Collections; import java.util.Objects; import java.util.concurrent.TimeUnit; +import java.util.function.IntFunction; public class InventoryUtils { + /** + * Stores the last used recipe network ID. Since 1.16.200 (and for server-authoritative inventories), + * each recipe needs a unique network ID (or else in .200 the client crashes). + */ + public static int LAST_RECIPE_NET_ID; + public static final ItemStack REFRESH_ITEM = new ItemStack(1, 127, new CompoundTag("")); public static void openInventory(GeyserSession session, Inventory inventory) { @@ -155,7 +162,7 @@ public class InventoryUtils { * @param description the description * @return the unusable space block */ - public static ItemData createUnusableSpaceBlock(String description) { + public static IntFunction createUnusableSpaceBlock(String description) { NbtMapBuilder root = NbtMap.builder(); NbtMapBuilder display = NbtMap.builder(); @@ -164,8 +171,8 @@ public class InventoryUtils { display.putList("Lore", NbtType.STRING, Collections.singletonList(ChatColor.RESET + ChatColor.DARK_PURPLE + description)); root.put("display", display.build()); - return ItemData.builder() - .id(ItemRegistry.ITEM_ENTRIES.get(ItemRegistry.BARRIER_INDEX).getBedrockId()) + return protocolVersion -> ItemData.builder() + .id(Registries.ITEMS.forVersion(protocolVersion).getStoredItems().barrier().getBedrockId()) .count(1) .tag(root.build()).build(); } @@ -250,7 +257,7 @@ public class InventoryUtils { continue; } // If this isn't the item we're looking for - if (!geyserItem.getItemEntry().getJavaIdentifier().equals(itemName)) { + if (!geyserItem.getMapping(session).getJavaIdentifier().equals(itemName)) { continue; } @@ -266,7 +273,7 @@ public class InventoryUtils { continue; } // If this isn't the item we're looking for - if (!geyserItem.getItemEntry().getJavaIdentifier().equals(itemName)) { + if (!geyserItem.getMapping(session).getJavaIdentifier().equals(itemName)) { continue; } @@ -279,10 +286,10 @@ public class InventoryUtils { if (session.getGameMode() == GameMode.CREATIVE) { int slot = findEmptyHotbarSlot(inventory); - ItemEntry entry = ItemRegistry.getItemEntry(itemName); - if (entry != null) { + ItemMapping mapping = session.getItemMappings().getMapping(itemName); + if (mapping != null) { ClientCreativeInventoryActionPacket actionPacket = new ClientCreativeInventoryActionPacket(slot, - new ItemStack(entry.getJavaId())); + new ItemStack(mapping.getJavaId())); if ((slot - 36) != inventory.getHeldItemSlot()) { setHotbarItem(session, slot); } diff --git a/connector/src/main/java/org/geysermc/connector/utils/ItemUtils.java b/connector/src/main/java/org/geysermc/connector/utils/ItemUtils.java index dd4543f61..db4e9e2e1 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/ItemUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/ItemUtils.java @@ -26,7 +26,7 @@ package org.geysermc.connector.utils; import com.github.steveice10.opennbt.tag.builtin.*; -import org.geysermc.connector.network.translators.item.ItemRegistry; +import org.geysermc.connector.network.session.GeyserSession; public class ItemUtils { @@ -49,8 +49,8 @@ public class ItemUtils { /** * @return the correct Bedrock durability for this item. */ - public static int getCorrectBedrockDurability(int javaId, int original) { - if (javaId == ItemRegistry.FISHING_ROD.getJavaId()) { + public static int getCorrectBedrockDurability(GeyserSession session, int javaId, int original) { + if (javaId == session.getItemMappings().getStoredItems().fishingRod().getJavaId()) { // Java durability: 64 // Bedrock durability : 384 // 384 / 64 = 6 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ToolItemEntry.java b/connector/src/main/java/org/geysermc/connector/utils/SoundUtils.java similarity index 65% rename from connector/src/main/java/org/geysermc/connector/network/translators/item/ToolItemEntry.java rename to connector/src/main/java/org/geysermc/connector/utils/SoundUtils.java index 2e93811c0..5abd9ff57 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ToolItemEntry.java +++ b/connector/src/main/java/org/geysermc/connector/utils/SoundUtils.java @@ -1,41 +1,46 @@ -/* - * Copyright (c) 2019-2021 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.connector.network.translators.item; - -import lombok.Getter; - -@Getter -public class ToolItemEntry extends ItemEntry { - private final String toolType; - private final String toolTier; - - public ToolItemEntry(String javaIdentifier, String bedrockIdentifier, int javaId, int bedrockId, int bedrockData, - String toolType, String toolTier, int bedrockBlockId, int stackSize) { - super(javaIdentifier, bedrockIdentifier, javaId, bedrockId, bedrockData, bedrockBlockId, stackSize); - this.toolType = toolType; - this.toolTier = toolTier; - } -} +/* + * Copyright (c) 2019-2021 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.connector.utils; + +import com.nukkitx.protocol.bedrock.data.SoundEvent; + +public class SoundUtils { + + /** + * Maps a sound name to a sound event, null if one + * does not exist. + * + * @param sound the sound name + * @return a sound event from the given sound + */ + public static SoundEvent toSoundEvent(String sound) { + try { + return SoundEvent.valueOf(sound.toUpperCase().replaceAll("\\.", "_")); + } catch (Exception ex) { + return null; + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/utils/StatisticsUtils.java b/connector/src/main/java/org/geysermc/connector/utils/StatisticsUtils.java index e59807d75..eca4f7453 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/StatisticsUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/StatisticsUtils.java @@ -29,8 +29,8 @@ import com.github.steveice10.mc.protocol.data.MagicValues; import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; import com.github.steveice10.mc.protocol.data.game.statistic.*; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemRegistry; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.registry.BlockRegistries; +import org.geysermc.connector.registry.type.ItemMappings; import org.geysermc.cumulus.SimpleForm; import org.geysermc.cumulus.response.SimpleFormResponse; import org.geysermc.cumulus.util.FormImage; @@ -76,6 +76,7 @@ public class StatisticsUtils { StringBuilder content = new StringBuilder(); + ItemMappings mappings = session.getItemMappings(); switch (response.getClickedButtonId()) { case 0: builder.title("stat.generalButton"); @@ -92,7 +93,7 @@ public class StatisticsUtils { for (Map.Entry entry : session.getStatistics().entrySet()) { if (entry.getKey() instanceof BreakBlockStatistic) { - String block = BlockTranslator.JAVA_ID_TO_JAVA_IDENTIFIER_MAP.get(((BreakBlockStatistic) entry.getKey()).getId()); + String block = BlockRegistries.JAVA_BLOCKS.get(((BreakBlockStatistic) entry.getKey()).getId()).getJavaIdentifier(); block = block.replace("minecraft:", "block.minecraft."); content.append(block).append(": ").append(entry.getValue()).append("\n"); } @@ -103,7 +104,7 @@ public class StatisticsUtils { for (Map.Entry entry : session.getStatistics().entrySet()) { if (entry.getKey() instanceof BreakItemStatistic) { - String item = ItemRegistry.ITEM_ENTRIES.get(((BreakItemStatistic) entry.getKey()).getId()).getJavaIdentifier(); + String item = mappings.getMapping(((BreakItemStatistic) entry.getKey()).getId()).getJavaIdentifier(); content.append(getItemTranslateKey(item, language)).append(": ").append(entry.getValue()).append("\n"); } } @@ -113,7 +114,7 @@ public class StatisticsUtils { for (Map.Entry entry : session.getStatistics().entrySet()) { if (entry.getKey() instanceof CraftItemStatistic) { - String item = ItemRegistry.ITEM_ENTRIES.get(((CraftItemStatistic) entry.getKey()).getId()).getJavaIdentifier(); + String item = mappings.getMapping(((CraftItemStatistic) entry.getKey()).getId()).getJavaIdentifier(); content.append(getItemTranslateKey(item, language)).append(": ").append(entry.getValue()).append("\n"); } } @@ -123,7 +124,7 @@ public class StatisticsUtils { for (Map.Entry entry : session.getStatistics().entrySet()) { if (entry.getKey() instanceof UseItemStatistic) { - String item = ItemRegistry.ITEM_ENTRIES.get(((UseItemStatistic) entry.getKey()).getId()).getJavaIdentifier(); + String item = mappings.getMapping(((UseItemStatistic) entry.getKey()).getId()).getJavaIdentifier(); content.append(getItemTranslateKey(item, language)).append(": ").append(entry.getValue()).append("\n"); } } @@ -133,7 +134,7 @@ public class StatisticsUtils { for (Map.Entry entry : session.getStatistics().entrySet()) { if (entry.getKey() instanceof PickupItemStatistic) { - String item = ItemRegistry.ITEM_ENTRIES.get(((PickupItemStatistic) entry.getKey()).getId()).getJavaIdentifier(); + String item = mappings.getMapping(((PickupItemStatistic) entry.getKey()).getId()).getJavaIdentifier(); content.append(getItemTranslateKey(item, language)).append(": ").append(entry.getValue()).append("\n"); } } @@ -143,7 +144,7 @@ public class StatisticsUtils { for (Map.Entry entry : session.getStatistics().entrySet()) { if (entry.getKey() instanceof DropItemStatistic) { - String item = ItemRegistry.ITEM_ENTRIES.get(((DropItemStatistic) entry.getKey()).getId()).getJavaIdentifier(); + String item = mappings.getMapping(((DropItemStatistic) entry.getKey()).getId()).getJavaIdentifier(); content.append(getItemTranslateKey(item, language)).append(": ").append(entry.getValue()).append("\n"); } } diff --git a/connector/src/main/resources/bedrock/block_palette.1_17_10.nbt b/connector/src/main/resources/bedrock/block_palette.1_17_10.nbt new file mode 100644 index 000000000..a32c0736e Binary files /dev/null and b/connector/src/main/resources/bedrock/block_palette.1_17_10.nbt differ diff --git a/connector/src/main/resources/bedrock/creative_items.json b/connector/src/main/resources/bedrock/creative_items.1_17_0.json similarity index 100% rename from connector/src/main/resources/bedrock/creative_items.json rename to connector/src/main/resources/bedrock/creative_items.1_17_0.json diff --git a/connector/src/main/resources/bedrock/creative_items.1_17_10.json b/connector/src/main/resources/bedrock/creative_items.1_17_10.json new file mode 100644 index 000000000..7b116e962 --- /dev/null +++ b/connector/src/main/resources/bedrock/creative_items.1_17_10.json @@ -0,0 +1,5203 @@ +{ + "items" : [ + { + "id" : "minecraft:planks", + "blockRuntimeId" : 5770 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 5771 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 5772 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 5773 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 5774 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 5775 + }, + { + "id" : "minecraft:crimson_planks", + "blockRuntimeId" : 3839 + }, + { + "id" : "minecraft:warped_planks", + "blockRuntimeId" : 7502 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1318 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1319 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1320 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1321 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1322 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1323 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1330 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1325 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1326 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1324 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1327 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1331 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1328 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1329 + }, + { + "id" : "minecraft:blackstone_wall", + "blockRuntimeId" : 507 + }, + { + "id" : "minecraft:polished_blackstone_wall", + "blockRuntimeId" : 6014 + }, + { + "id" : "minecraft:polished_blackstone_brick_wall", + "blockRuntimeId" : 5811 + }, + { + "id" : "minecraft:cobbled_deepslate_wall", + "blockRuntimeId" : 1155 + }, + { + "id" : "minecraft:deepslate_tile_wall", + "blockRuntimeId" : 4297 + }, + { + "id" : "minecraft:polished_deepslate_wall", + "blockRuntimeId" : 6189 + }, + { + "id" : "minecraft:deepslate_brick_wall", + "blockRuntimeId" : 4114 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 4773 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 4774 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 4775 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 4776 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 4777 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 4778 + }, + { + "id" : "minecraft:nether_brick_fence", + "blockRuntimeId" : 5662 + }, + { + "id" : "minecraft:crimson_fence", + "blockRuntimeId" : 3817 + }, + { + "id" : "minecraft:warped_fence", + "blockRuntimeId" : 7480 + }, + { + "id" : "minecraft:fence_gate", + "blockRuntimeId" : 4779 + }, + { + "id" : "minecraft:spruce_fence_gate", + "blockRuntimeId" : 6914 + }, + { + "id" : "minecraft:birch_fence_gate", + "blockRuntimeId" : 400 + }, + { + "id" : "minecraft:jungle_fence_gate", + "blockRuntimeId" : 5228 + }, + { + "id" : "minecraft:acacia_fence_gate", + "blockRuntimeId" : 44 + }, + { + "id" : "minecraft:dark_oak_fence_gate", + "blockRuntimeId" : 3980 + }, + { + "id" : "minecraft:crimson_fence_gate", + "blockRuntimeId" : 3818 + }, + { + "id" : "minecraft:warped_fence_gate", + "blockRuntimeId" : 7481 + }, + { + "id" : "minecraft:normal_stone_stairs", + "blockRuntimeId" : 5681 + }, + { + "id" : "minecraft:stone_stairs", + "blockRuntimeId" : 7185 + }, + { + "id" : "minecraft:mossy_cobblestone_stairs", + "blockRuntimeId" : 5643 + }, + { + "id" : "minecraft:oak_stairs", + "blockRuntimeId" : 5690 + }, + { + "id" : "minecraft:spruce_stairs", + "blockRuntimeId" : 6946 + }, + { + "id" : "minecraft:birch_stairs", + "blockRuntimeId" : 432 + }, + { + "id" : "minecraft:jungle_stairs", + "blockRuntimeId" : 5260 + }, + { + "id" : "minecraft:acacia_stairs", + "blockRuntimeId" : 76 + }, + { + "id" : "minecraft:dark_oak_stairs", + "blockRuntimeId" : 4012 + }, + { + "id" : "minecraft:stone_brick_stairs", + "blockRuntimeId" : 7091 + }, + { + "id" : "minecraft:mossy_stone_brick_stairs", + "blockRuntimeId" : 5651 + }, + { + "id" : "minecraft:sandstone_stairs", + "blockRuntimeId" : 6683 + }, + { + "id" : "minecraft:smooth_sandstone_stairs", + "blockRuntimeId" : 6807 + }, + { + "id" : "minecraft:red_sandstone_stairs", + "blockRuntimeId" : 6610 + }, + { + "id" : "minecraft:smooth_red_sandstone_stairs", + "blockRuntimeId" : 6799 + }, + { + "id" : "minecraft:granite_stairs", + "blockRuntimeId" : 4964 + }, + { + "id" : "minecraft:polished_granite_stairs", + "blockRuntimeId" : 6359 + }, + { + "id" : "minecraft:diorite_stairs", + "blockRuntimeId" : 4475 + }, + { + "id" : "minecraft:polished_diorite_stairs", + "blockRuntimeId" : 6351 + }, + { + "id" : "minecraft:andesite_stairs", + "blockRuntimeId" : 144 + }, + { + "id" : "minecraft:polished_andesite_stairs", + "blockRuntimeId" : 5787 + }, + { + "id" : "minecraft:brick_stairs", + "blockRuntimeId" : 876 + }, + { + "id" : "minecraft:nether_brick_stairs", + "blockRuntimeId" : 5663 + }, + { + "id" : "minecraft:red_nether_brick_stairs", + "blockRuntimeId" : 6598 + }, + { + "id" : "minecraft:end_brick_stairs", + "blockRuntimeId" : 4719 + }, + { + "id" : "minecraft:quartz_stairs", + "blockRuntimeId" : 6532 + }, + { + "id" : "minecraft:smooth_quartz_stairs", + "blockRuntimeId" : 6791 + }, + { + "id" : "minecraft:purpur_stairs", + "blockRuntimeId" : 6510 + }, + { + "id" : "minecraft:prismarine_stairs", + "blockRuntimeId" : 6422 + }, + { + "id" : "minecraft:dark_prismarine_stairs", + "blockRuntimeId" : 4036 + }, + { + "id" : "minecraft:prismarine_bricks_stairs", + "blockRuntimeId" : 6414 + }, + { + "id" : "minecraft:crimson_stairs", + "blockRuntimeId" : 3859 + }, + { + "id" : "minecraft:warped_stairs", + "blockRuntimeId" : 7522 + }, + { + "id" : "minecraft:blackstone_stairs", + "blockRuntimeId" : 499 + }, + { + "id" : "minecraft:polished_blackstone_stairs", + "blockRuntimeId" : 6006 + }, + { + "id" : "minecraft:polished_blackstone_brick_stairs", + "blockRuntimeId" : 5803 + }, + { + "id" : "minecraft:cut_copper_stairs", + "blockRuntimeId" : 3912 + }, + { + "id" : "minecraft:exposed_cut_copper_stairs", + "blockRuntimeId" : 4755 + }, + { + "id" : "minecraft:weathered_cut_copper_stairs", + "blockRuntimeId" : 7649 + }, + { + "id" : "minecraft:oxidized_cut_copper_stairs", + "blockRuntimeId" : 5731 + }, + { + "id" : "minecraft:waxed_cut_copper_stairs", + "blockRuntimeId" : 7593 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper_stairs", + "blockRuntimeId" : 7607 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper_stairs", + "blockRuntimeId" : 7635 + }, + { + "id" : "minecraft:waxed_oxidized_cut_copper_stairs", + "blockRuntimeId" : 7621 + }, + { + "id" : "minecraft:cobbled_deepslate_stairs", + "blockRuntimeId" : 1147 + }, + { + "id" : "minecraft:deepslate_tile_stairs", + "blockRuntimeId" : 4289 + }, + { + "id" : "minecraft:polished_deepslate_stairs", + "blockRuntimeId" : 6181 + }, + { + "id" : "minecraft:deepslate_brick_stairs", + "blockRuntimeId" : 4106 + }, + { + "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:iron_door" + }, + { + "id" : "minecraft:crimson_door" + }, + { + "id" : "minecraft:warped_door" + }, + { + "id" : "minecraft:trapdoor", + "blockRuntimeId" : 7267 + }, + { + "id" : "minecraft:spruce_trapdoor", + "blockRuntimeId" : 6970 + }, + { + "id" : "minecraft:birch_trapdoor", + "blockRuntimeId" : 456 + }, + { + "id" : "minecraft:jungle_trapdoor", + "blockRuntimeId" : 5284 + }, + { + "id" : "minecraft:acacia_trapdoor", + "blockRuntimeId" : 100 + }, + { + "id" : "minecraft:dark_oak_trapdoor", + "blockRuntimeId" : 4020 + }, + { + "id" : "minecraft:iron_trapdoor", + "blockRuntimeId" : 5143 + }, + { + "id" : "minecraft:crimson_trapdoor", + "blockRuntimeId" : 3886 + }, + { + "id" : "minecraft:warped_trapdoor", + "blockRuntimeId" : 7549 + }, + { + "id" : "minecraft:iron_bars", + "blockRuntimeId" : 5108 + }, + { + "id" : "minecraft:glass", + "blockRuntimeId" : 4870 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 6992 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 7000 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 6999 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 7007 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 7004 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 7006 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 6993 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 6996 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 6997 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 7005 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 7001 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 6995 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 7003 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 7002 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 6994 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 6998 + }, + { + "id" : "minecraft:tinted_glass", + "blockRuntimeId" : 7256 + }, + { + "id" : "minecraft:glass_pane", + "blockRuntimeId" : 4871 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7008 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7016 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7015 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7023 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7020 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7022 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7009 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7012 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7013 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7021 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7017 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7011 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7019 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7018 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7010 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7014 + }, + { + "id" : "minecraft:ladder", + "blockRuntimeId" : 5332 + }, + { + "id" : "minecraft:scaffolding", + "blockRuntimeId" : 6703 + }, + { + "id" : "minecraft:double_stone_slab", + "blockRuntimeId" : 7127 + }, + { + "id" : "minecraft:double_stone_slab4", + "blockRuntimeId" : 7177 + }, + { + "id" : "minecraft:double_stone_slab", + "blockRuntimeId" : 7130 + }, + { + "id" : "minecraft:double_stone_slab2", + "blockRuntimeId" : 7148 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 7807 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 7808 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 7809 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 7810 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 7811 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 7812 + }, + { + "id" : "minecraft:double_stone_slab", + "blockRuntimeId" : 7132 + }, + { + "id" : "minecraft:double_stone_slab4", + "blockRuntimeId" : 7175 + }, + { + "id" : "minecraft:double_stone_slab", + "blockRuntimeId" : 7128 + }, + { + "id" : "minecraft:double_stone_slab4", + "blockRuntimeId" : 7178 + }, + { + "id" : "minecraft:double_stone_slab2", + "blockRuntimeId" : 7149 + }, + { + "id" : "minecraft:double_stone_slab2", + "blockRuntimeId" : 7143 + }, + { + "id" : "minecraft:double_stone_slab4", + "blockRuntimeId" : 7179 + }, + { + "id" : "minecraft:double_stone_slab3", + "blockRuntimeId" : 7160 + }, + { + "id" : "minecraft:double_stone_slab3", + "blockRuntimeId" : 7165 + }, + { + "id" : "minecraft:double_stone_slab3", + "blockRuntimeId" : 7166 + }, + { + "id" : "minecraft:double_stone_slab3", + "blockRuntimeId" : 7163 + }, + { + "id" : "minecraft:double_stone_slab3", + "blockRuntimeId" : 7164 + }, + { + "id" : "minecraft:double_stone_slab3", + "blockRuntimeId" : 7162 + }, + { + "id" : "minecraft:double_stone_slab3", + "blockRuntimeId" : 7161 + }, + { + "id" : "minecraft:double_stone_slab", + "blockRuntimeId" : 7131 + }, + { + "id" : "minecraft:double_stone_slab", + "blockRuntimeId" : 7134 + }, + { + "id" : "minecraft:double_stone_slab2", + "blockRuntimeId" : 7150 + }, + { + "id" : "minecraft:double_stone_slab3", + "blockRuntimeId" : 7159 + }, + { + "id" : "minecraft:double_stone_slab", + "blockRuntimeId" : 7133 + }, + { + "id" : "minecraft:double_stone_slab4", + "blockRuntimeId" : 7176 + }, + { + "id" : "minecraft:double_stone_slab2", + "blockRuntimeId" : 7144 + }, + { + "id" : "minecraft:double_stone_slab2", + "blockRuntimeId" : 7145 + }, + { + "id" : "minecraft:double_stone_slab2", + "blockRuntimeId" : 7146 + }, + { + "id" : "minecraft:double_stone_slab2", + "blockRuntimeId" : 7147 + }, + { + "id" : "minecraft:crimson_slab", + "blockRuntimeId" : 3857 + }, + { + "id" : "minecraft:warped_slab", + "blockRuntimeId" : 7520 + }, + { + "id" : "minecraft:blackstone_slab", + "blockRuntimeId" : 497 + }, + { + "id" : "minecraft:polished_blackstone_slab", + "blockRuntimeId" : 6004 + }, + { + "id" : "minecraft:polished_blackstone_brick_slab", + "blockRuntimeId" : 5801 + }, + { + "id" : "minecraft:cut_copper_slab", + "blockRuntimeId" : 3910 + }, + { + "id" : "minecraft:exposed_cut_copper_slab", + "blockRuntimeId" : 4753 + }, + { + "id" : "minecraft:weathered_cut_copper_slab", + "blockRuntimeId" : 7647 + }, + { + "id" : "minecraft:oxidized_cut_copper_slab", + "blockRuntimeId" : 5729 + }, + { + "id" : "minecraft:waxed_cut_copper_slab", + "blockRuntimeId" : 7591 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper_slab", + "blockRuntimeId" : 7605 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper_slab", + "blockRuntimeId" : 7633 + }, + { + "id" : "minecraft:waxed_oxidized_cut_copper_slab", + "blockRuntimeId" : 7619 + }, + { + "id" : "minecraft:cobbled_deepslate_slab", + "blockRuntimeId" : 1145 + }, + { + "id" : "minecraft:polished_deepslate_slab", + "blockRuntimeId" : 6179 + }, + { + "id" : "minecraft:deepslate_tile_slab", + "blockRuntimeId" : 4287 + }, + { + "id" : "minecraft:deepslate_brick_slab", + "blockRuntimeId" : 4104 + }, + { + "id" : "minecraft:brick_block", + "blockRuntimeId" : 875 + }, + { + "id" : "minecraft:chiseled_nether_bricks", + "blockRuntimeId" : 1130 + }, + { + "id" : "minecraft:cracked_nether_bricks", + "blockRuntimeId" : 3768 + }, + { + "id" : "minecraft:quartz_bricks", + "blockRuntimeId" : 6530 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 7193 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 7194 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 7195 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 7196 + }, + { + "id" : "minecraft:end_bricks", + "blockRuntimeId" : 4727 + }, + { + "id" : "minecraft:prismarine", + "blockRuntimeId" : 6413 + }, + { + "id" : "minecraft:polished_blackstone_bricks", + "blockRuntimeId" : 5973 + }, + { + "id" : "minecraft:cracked_polished_blackstone_bricks", + "blockRuntimeId" : 3769 + }, + { + "id" : "minecraft:gilded_blackstone", + "blockRuntimeId" : 4869 + }, + { + "id" : "minecraft:chiseled_polished_blackstone", + "blockRuntimeId" : 1131 + }, + { + "id" : "minecraft:deepslate_tiles", + "blockRuntimeId" : 4459 + }, + { + "id" : "minecraft:cracked_deepslate_tiles", + "blockRuntimeId" : 3767 + }, + { + "id" : "minecraft:deepslate_bricks", + "blockRuntimeId" : 4276 + }, + { + "id" : "minecraft:cracked_deepslate_bricks", + "blockRuntimeId" : 3766 + }, + { + "id" : "minecraft:chiseled_deepslate", + "blockRuntimeId" : 1129 + }, + { + "id" : "minecraft:cobblestone", + "blockRuntimeId" : 1317 + }, + { + "id" : "minecraft:mossy_cobblestone", + "blockRuntimeId" : 5642 + }, + { + "id" : "minecraft:cobbled_deepslate", + "blockRuntimeId" : 1142 + }, + { + "id" : "minecraft:smooth_stone", + "blockRuntimeId" : 6815 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 6679 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 6680 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 6681 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 6682 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6606 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6607 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6608 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6609 + }, + { + "id" : "minecraft:coal_block", + "blockRuntimeId" : 1140 + }, + { + "id" : "minecraft:dried_kelp_block", + "blockRuntimeId" : 4583 + }, + { + "id" : "minecraft:gold_block", + "blockRuntimeId" : 4950 + }, + { + "id" : "minecraft:iron_block", + "blockRuntimeId" : 5109 + }, + { + "id" : "minecraft:copper_block", + "blockRuntimeId" : 3676 + }, + { + "id" : "minecraft:exposed_copper", + "blockRuntimeId" : 4751 + }, + { + "id" : "minecraft:weathered_copper", + "blockRuntimeId" : 7645 + }, + { + "id" : "minecraft:oxidized_copper", + "blockRuntimeId" : 5727 + }, + { + "id" : "minecraft:waxed_copper", + "blockRuntimeId" : 7589 + }, + { + "id" : "minecraft:waxed_exposed_copper", + "blockRuntimeId" : 7603 + }, + { + "id" : "minecraft:waxed_weathered_copper", + "blockRuntimeId" : 7631 + }, + { + "id" : "minecraft:waxed_oxidized_copper", + "blockRuntimeId" : 7617 + }, + { + "id" : "minecraft:cut_copper", + "blockRuntimeId" : 3909 + }, + { + "id" : "minecraft:exposed_cut_copper", + "blockRuntimeId" : 4752 + }, + { + "id" : "minecraft:weathered_cut_copper", + "blockRuntimeId" : 7646 + }, + { + "id" : "minecraft:oxidized_cut_copper", + "blockRuntimeId" : 5728 + }, + { + "id" : "minecraft:waxed_cut_copper", + "blockRuntimeId" : 7590 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper", + "blockRuntimeId" : 7604 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper", + "blockRuntimeId" : 7632 + }, + { + "id" : "minecraft:waxed_oxidized_cut_copper", + "blockRuntimeId" : 7618 + }, + { + "id" : "minecraft:emerald_block", + "blockRuntimeId" : 4716 + }, + { + "id" : "minecraft:diamond_block", + "blockRuntimeId" : 4473 + }, + { + "id" : "minecraft:lapis_block", + "blockRuntimeId" : 5340 + }, + { + "id" : "minecraft:raw_iron_block", + "blockRuntimeId" : 6552 + }, + { + "id" : "minecraft:raw_copper_block", + "blockRuntimeId" : 6550 + }, + { + "id" : "minecraft:raw_gold_block", + "blockRuntimeId" : 6551 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 6518 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 6520 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 6519 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 6521 + }, + { + "id" : "minecraft:prismarine", + "blockRuntimeId" : 6411 + }, + { + "id" : "minecraft:prismarine", + "blockRuntimeId" : 6412 + }, + { + "id" : "minecraft:slime", + "blockRuntimeId" : 6768 + }, + { + "id" : "minecraft:honey_block", + "blockRuntimeId" : 5087 + }, + { + "id" : "minecraft:honeycomb_block", + "blockRuntimeId" : 5088 + }, + { + "id" : "minecraft:hay_block", + "blockRuntimeId" : 5059 + }, + { + "id" : "minecraft:bone_block", + "blockRuntimeId" : 692 + }, + { + "id" : "minecraft:nether_brick", + "blockRuntimeId" : 5661 + }, + { + "id" : "minecraft:red_nether_brick", + "blockRuntimeId" : 6597 + }, + { + "id" : "minecraft:netherite_block", + "blockRuntimeId" : 5678 + }, + { + "id" : "minecraft:lodestone", + "blockRuntimeId" : 5538 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 7819 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 7827 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 7826 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 7834 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 7831 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 7833 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 7820 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 7823 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 7824 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 7832 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 7828 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 7822 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 7830 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 7829 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 7821 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 7825 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 963 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 971 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 970 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 978 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 975 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 977 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 964 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 967 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 968 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 976 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 972 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 966 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 974 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 973 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 965 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 969 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 3659 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 3667 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 3666 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 3674 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 3671 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 3673 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 3660 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 3663 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 3664 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 3672 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 3668 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 3662 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 3670 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 3669 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 3661 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 3665 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 3643 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 3651 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 3650 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 3658 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 3655 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 3657 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 3644 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 3647 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 3648 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 3656 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 3652 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 3646 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 3654 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 3653 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 3645 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 3649 + }, + { + "id" : "minecraft:clay", + "blockRuntimeId" : 1139 + }, + { + "id" : "minecraft:hardened_clay", + "blockRuntimeId" : 5058 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 7024 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 7032 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 7031 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 7039 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 7036 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 7038 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 7025 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 7028 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 7029 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 7037 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 7033 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 7027 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 7035 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 7034 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 7026 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 7030 + }, + { + "id" : "minecraft:white_glazed_terracotta", + "blockRuntimeId" : 7704 + }, + { + "id" : "minecraft:silver_glazed_terracotta", + "blockRuntimeId" : 6750 + }, + { + "id" : "minecraft:gray_glazed_terracotta", + "blockRuntimeId" : 4985 + }, + { + "id" : "minecraft:black_glazed_terracotta", + "blockRuntimeId" : 488 + }, + { + "id" : "minecraft:brown_glazed_terracotta", + "blockRuntimeId" : 894 + }, + { + "id" : "minecraft:red_glazed_terracotta", + "blockRuntimeId" : 6574 + }, + { + "id" : "minecraft:orange_glazed_terracotta", + "blockRuntimeId" : 5721 + }, + { + "id" : "minecraft:yellow_glazed_terracotta", + "blockRuntimeId" : 7846 + }, + { + "id" : "minecraft:lime_glazed_terracotta", + "blockRuntimeId" : 5507 + }, + { + "id" : "minecraft:green_glazed_terracotta", + "blockRuntimeId" : 5001 + }, + { + "id" : "minecraft:cyan_glazed_terracotta", + "blockRuntimeId" : 3930 + }, + { + "id" : "minecraft:light_blue_glazed_terracotta", + "blockRuntimeId" : 5459 + }, + { + "id" : "minecraft:blue_glazed_terracotta", + "blockRuntimeId" : 685 + }, + { + "id" : "minecraft:purple_glazed_terracotta", + "blockRuntimeId" : 6492 + }, + { + "id" : "minecraft:magenta_glazed_terracotta", + "blockRuntimeId" : 5571 + }, + { + "id" : "minecraft:pink_glazed_terracotta", + "blockRuntimeId" : 5752 + }, + { + "id" : "minecraft:purpur_block", + "blockRuntimeId" : 6498 + }, + { + "id" : "minecraft:purpur_block", + "blockRuntimeId" : 6500 + }, + { + "id" : "minecraft:nether_wart_block", + "blockRuntimeId" : 5677 + }, + { + "id" : "minecraft:warped_wart_block", + "blockRuntimeId" : 7571 + }, + { + "id" : "minecraft:shroomlight", + "blockRuntimeId" : 6733 + }, + { + "id" : "minecraft:crimson_nylium", + "blockRuntimeId" : 3838 + }, + { + "id" : "minecraft:warped_nylium", + "blockRuntimeId" : 7501 + }, + { + "id" : "minecraft:basalt", + "blockRuntimeId" : 214 + }, + { + "id" : "minecraft:polished_basalt", + "blockRuntimeId" : 5795 + }, + { + "id" : "minecraft:smooth_basalt", + "blockRuntimeId" : 6790 + }, + { + "id" : "minecraft:soul_soil", + "blockRuntimeId" : 6860 + }, + { + "id" : "minecraft:dirt", + "blockRuntimeId" : 4483 + }, + { + "id" : "minecraft:dirt", + "blockRuntimeId" : 4484 + }, + { + "id" : "minecraft:farmland", + "blockRuntimeId" : 4765 + }, + { + "id" : "minecraft:grass", + "blockRuntimeId" : 4972 + }, + { + "id" : "minecraft:grass_path", + "blockRuntimeId" : 4973 + }, + { + "id" : "minecraft:podzol", + "blockRuntimeId" : 5776 + }, + { + "id" : "minecraft:mycelium", + "blockRuntimeId" : 5660 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 7084 + }, + { + "id" : "minecraft:iron_ore", + "blockRuntimeId" : 5142 + }, + { + "id" : "minecraft:gold_ore", + "blockRuntimeId" : 4951 + }, + { + "id" : "minecraft:diamond_ore", + "blockRuntimeId" : 4474 + }, + { + "id" : "minecraft:lapis_ore", + "blockRuntimeId" : 5341 + }, + { + "id" : "minecraft:redstone_ore", + "blockRuntimeId" : 6620 + }, + { + "id" : "minecraft:coal_ore", + "blockRuntimeId" : 1141 + }, + { + "id" : "minecraft:copper_ore", + "blockRuntimeId" : 3677 + }, + { + "id" : "minecraft:emerald_ore", + "blockRuntimeId" : 4717 + }, + { + "id" : "minecraft:quartz_ore", + "blockRuntimeId" : 6531 + }, + { + "id" : "minecraft:nether_gold_ore", + "blockRuntimeId" : 5671 + }, + { + "id" : "minecraft:ancient_debris", + "blockRuntimeId" : 143 + }, + { + "id" : "minecraft:deepslate_iron_ore", + "blockRuntimeId" : 4282 + }, + { + "id" : "minecraft:deepslate_gold_ore", + "blockRuntimeId" : 4281 + }, + { + "id" : "minecraft:deepslate_diamond_ore", + "blockRuntimeId" : 4279 + }, + { + "id" : "minecraft:deepslate_lapis_ore", + "blockRuntimeId" : 4283 + }, + { + "id" : "minecraft:deepslate_redstone_ore", + "blockRuntimeId" : 4284 + }, + { + "id" : "minecraft:deepslate_emerald_ore", + "blockRuntimeId" : 4280 + }, + { + "id" : "minecraft:deepslate_coal_ore", + "blockRuntimeId" : 4277 + }, + { + "id" : "minecraft:deepslate_copper_ore", + "blockRuntimeId" : 4278 + }, + { + "id" : "minecraft:gravel", + "blockRuntimeId" : 4974 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 7085 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 7087 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 7089 + }, + { + "id" : "minecraft:blackstone", + "blockRuntimeId" : 494 + }, + { + "id" : "minecraft:deepslate", + "blockRuntimeId" : 4099 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 7086 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 7088 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 7090 + }, + { + "id" : "minecraft:polished_blackstone", + "blockRuntimeId" : 5798 + }, + { + "id" : "minecraft:polished_deepslate", + "blockRuntimeId" : 6176 + }, + { + "id" : "minecraft:sand", + "blockRuntimeId" : 6677 + }, + { + "id" : "minecraft:sand", + "blockRuntimeId" : 6678 + }, + { + "id" : "minecraft:cactus", + "blockRuntimeId" : 920 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 5539 + }, + { + "id" : "minecraft:stripped_oak_log", + "blockRuntimeId" : 7223 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 5540 + }, + { + "id" : "minecraft:stripped_spruce_log", + "blockRuntimeId" : 7226 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 5541 + }, + { + "id" : "minecraft:stripped_birch_log", + "blockRuntimeId" : 7208 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 5542 + }, + { + "id" : "minecraft:stripped_jungle_log", + "blockRuntimeId" : 7220 + }, + { + "id" : "minecraft:log2", + "blockRuntimeId" : 5551 + }, + { + "id" : "minecraft:stripped_acacia_log", + "blockRuntimeId" : 7205 + }, + { + "id" : "minecraft:log2", + "blockRuntimeId" : 5552 + }, + { + "id" : "minecraft:stripped_dark_oak_log", + "blockRuntimeId" : 7217 + }, + { + "id" : "minecraft:crimson_stem", + "blockRuntimeId" : 3883 + }, + { + "id" : "minecraft:stripped_crimson_stem", + "blockRuntimeId" : 7214 + }, + { + "id" : "minecraft:warped_stem", + "blockRuntimeId" : 7546 + }, + { + "id" : "minecraft:stripped_warped_stem", + "blockRuntimeId" : 7232 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 7711 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 7717 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 7712 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 7718 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 7713 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 7719 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 7714 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 7720 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 7715 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 7721 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 7716 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 7722 + }, + { + "id" : "minecraft:crimson_hyphae", + "blockRuntimeId" : 3835 + }, + { + "id" : "minecraft:stripped_crimson_hyphae", + "blockRuntimeId" : 7211 + }, + { + "id" : "minecraft:warped_hyphae", + "blockRuntimeId" : 7498 + }, + { + "id" : "minecraft:stripped_warped_hyphae", + "blockRuntimeId" : 7229 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 5385 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 5386 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 5387 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 5388 + }, + { + "id" : "minecraft:leaves2", + "blockRuntimeId" : 5401 + }, + { + "id" : "minecraft:leaves2", + "blockRuntimeId" : 5402 + }, + { + "id" : "minecraft:azalea_leaves", + "blockRuntimeId" : 169 + }, + { + "id" : "minecraft:azalea_leaves_flowered", + "blockRuntimeId" : 173 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 6691 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 6692 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 6693 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 6694 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 6695 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 6696 + }, + { + "id" : "minecraft:bee_nest", + "blockRuntimeId" : 236 + }, + { + "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" : 5584 + }, + { + "id" : "minecraft:melon_slice" + }, + { + "id" : "minecraft:glistering_melon_slice" + }, + { + "id" : "minecraft:sweet_berries" + }, + { + "id" : "minecraft:glow_berries" + }, + { + "id" : "minecraft:pumpkin", + "blockRuntimeId" : 6430 + }, + { + "id" : "minecraft:carved_pumpkin", + "blockRuntimeId" : 988 + }, + { + "id" : "minecraft:lit_pumpkin", + "blockRuntimeId" : 5526 + }, + { + "id" : "minecraft:honeycomb" + }, + { + "id" : "minecraft:tallgrass", + "blockRuntimeId" : 7253 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 4503 + }, + { + "id" : "minecraft:tallgrass", + "blockRuntimeId" : 7252 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 4502 + }, + { + "id" : "minecraft:nether_sprouts" + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 3681 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 3679 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 3680 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 3678 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 3682 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 3686 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 3684 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 3685 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 3683 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 3687 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 3701 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 3699 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 3700 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 3698 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 3702 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 3711 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 3709 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 3710 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 3708 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 3712 + }, + { + "id" : "minecraft:kelp" + }, + { + "id" : "minecraft:seagrass", + "blockRuntimeId" : 6729 + }, + { + "id" : "minecraft:crimson_roots", + "blockRuntimeId" : 3856 + }, + { + "id" : "minecraft:warped_roots", + "blockRuntimeId" : 7519 + }, + { + "id" : "minecraft:yellow_flower", + "blockRuntimeId" : 7845 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 6563 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 6564 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 6565 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 6566 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 6567 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 6568 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 6569 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 6570 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 6571 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 6572 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 6573 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 4500 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 4501 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 4504 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 4505 + }, + { + "id" : "minecraft:wither_rose", + "blockRuntimeId" : 7710 + }, + { + "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" : 7406 + }, + { + "id" : "minecraft:weeping_vines", + "blockRuntimeId" : 7660 + }, + { + "id" : "minecraft:twisting_vines", + "blockRuntimeId" : 7334 + }, + { + "id" : "minecraft:waterlily", + "blockRuntimeId" : 7588 + }, + { + "id" : "minecraft:deadbush", + "blockRuntimeId" : 4098 + }, + { + "id" : "minecraft:bamboo", + "blockRuntimeId" : 177 + }, + { + "id" : "minecraft:snow", + "blockRuntimeId" : 6816 + }, + { + "id" : "minecraft:ice", + "blockRuntimeId" : 5101 + }, + { + "id" : "minecraft:packed_ice", + "blockRuntimeId" : 5741 + }, + { + "id" : "minecraft:blue_ice", + "blockRuntimeId" : 691 + }, + { + "id" : "minecraft:snow_layer", + "blockRuntimeId" : 6817 + }, + { + "id" : "minecraft:pointed_dripstone", + "blockRuntimeId" : 5782 + }, + { + "id" : "minecraft:dripstone_block", + "blockRuntimeId" : 4584 + }, + { + "id" : "minecraft:moss_carpet", + "blockRuntimeId" : 5641 + }, + { + "id" : "minecraft:moss_block", + "blockRuntimeId" : 5640 + }, + { + "id" : "minecraft:dirt_with_roots", + "blockRuntimeId" : 4485 + }, + { + "id" : "minecraft:hanging_roots", + "blockRuntimeId" : 5023 + }, + { + "id" : "minecraft:big_dripleaf", + "blockRuntimeId" : 328 + }, + { + "id" : "minecraft:small_dripleaf_block", + "blockRuntimeId" : 6782 + }, + { + "id" : "minecraft:spore_blossom", + "blockRuntimeId" : 6869 + }, + { + "id" : "minecraft:azalea", + "blockRuntimeId" : 168 + }, + { + "id" : "minecraft:flowering_azalea", + "blockRuntimeId" : 4814 + }, + { + "id" : "minecraft:glow_lichen", + "blockRuntimeId" : 4947 + }, + { + "id" : "minecraft:amethyst_block", + "blockRuntimeId" : 136 + }, + { + "id" : "minecraft:budding_amethyst", + "blockRuntimeId" : 919 + }, + { + "id" : "minecraft:amethyst_cluster", + "blockRuntimeId" : 137 + }, + { + "id" : "minecraft:large_amethyst_bud", + "blockRuntimeId" : 5342 + }, + { + "id" : "minecraft:medium_amethyst_bud", + "blockRuntimeId" : 5578 + }, + { + "id" : "minecraft:small_amethyst_bud", + "blockRuntimeId" : 6769 + }, + { + "id" : "minecraft:tuff", + "blockRuntimeId" : 7321 + }, + { + "id" : "minecraft:calcite", + "blockRuntimeId" : 943 + }, + { + "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" : 900 + }, + { + "id" : "minecraft:red_mushroom", + "blockRuntimeId" : 6580 + }, + { + "id" : "minecraft:crimson_fungus", + "blockRuntimeId" : 3834 + }, + { + "id" : "minecraft:warped_fungus", + "blockRuntimeId" : 7497 + }, + { + "id" : "minecraft:brown_mushroom_block", + "blockRuntimeId" : 915 + }, + { + "id" : "minecraft:red_mushroom_block", + "blockRuntimeId" : 6595 + }, + { + "id" : "minecraft:brown_mushroom_block", + "blockRuntimeId" : 916 + }, + { + "id" : "minecraft:brown_mushroom_block", + "blockRuntimeId" : 901 + }, + { + "id" : "minecraft:egg" + }, + { + "id" : "minecraft:sugar_cane" + }, + { + "id" : "minecraft:sugar" + }, + { + "id" : "minecraft:rotten_flesh" + }, + { + "id" : "minecraft:bone" + }, + { + "id" : "minecraft:web", + "blockRuntimeId" : 7659 + }, + { + "id" : "minecraft:spider_eye" + }, + { + "id" : "minecraft:mob_spawner", + "blockRuntimeId" : 5633 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 5634 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 5635 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 5636 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 5637 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 5638 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 5639 + }, + { + "id" : "minecraft:infested_deepslate", + "blockRuntimeId" : 5102 + }, + { + "id" : "minecraft:dragon_egg", + "blockRuntimeId" : 4582 + }, + { + "id" : "minecraft:turtle_egg", + "blockRuntimeId" : 7322 + }, + { + "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: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:obsidian", + "blockRuntimeId" : 5710 + }, + { + "id" : "minecraft:crying_obsidian", + "blockRuntimeId" : 3908 + }, + { + "id" : "minecraft:bedrock", + "blockRuntimeId" : 234 + }, + { + "id" : "minecraft:soul_sand", + "blockRuntimeId" : 6859 + }, + { + "id" : "minecraft:netherrack", + "blockRuntimeId" : 5679 + }, + { + "id" : "minecraft:magma", + "blockRuntimeId" : 5577 + }, + { + "id" : "minecraft:nether_wart" + }, + { + "id" : "minecraft:end_stone", + "blockRuntimeId" : 4744 + }, + { + "id" : "minecraft:chorus_flower", + "blockRuntimeId" : 1132 + }, + { + "id" : "minecraft:chorus_plant", + "blockRuntimeId" : 1138 + }, + { + "id" : "minecraft:chorus_fruit" + }, + { + "id" : "minecraft:popped_chorus_fruit" + }, + { + "id" : "minecraft:sponge", + "blockRuntimeId" : 6867 + }, + { + "id" : "minecraft:sponge", + "blockRuntimeId" : 6868 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 3688 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 3689 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 3690 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 3691 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 3692 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 3693 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 3694 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 3695 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 3696 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 3697 + }, + { + "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: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" : 7261 + }, + { + "id" : "minecraft:soul_torch", + "blockRuntimeId" : 6861 + }, + { + "id" : "minecraft:sea_pickle", + "blockRuntimeId" : 6721 + }, + { + "id" : "minecraft:lantern", + "blockRuntimeId" : 5338 + }, + { + "id" : "minecraft:soul_lantern", + "blockRuntimeId" : 6857 + }, + { + "id" : "minecraft:candle", + "blockRuntimeId" : 953 + }, + { + "id" : "minecraft:white_candle", + "blockRuntimeId" : 7694 + }, + { + "id" : "minecraft:orange_candle", + "blockRuntimeId" : 5711 + }, + { + "id" : "minecraft:magenta_candle", + "blockRuntimeId" : 5561 + }, + { + "id" : "minecraft:light_blue_candle", + "blockRuntimeId" : 5449 + }, + { + "id" : "minecraft:yellow_candle", + "blockRuntimeId" : 7835 + }, + { + "id" : "minecraft:lime_candle", + "blockRuntimeId" : 5497 + }, + { + "id" : "minecraft:pink_candle", + "blockRuntimeId" : 5742 + }, + { + "id" : "minecraft:gray_candle", + "blockRuntimeId" : 4975 + }, + { + "id" : "minecraft:light_gray_candle", + "blockRuntimeId" : 5465 + }, + { + "id" : "minecraft:cyan_candle", + "blockRuntimeId" : 3920 + }, + { + "id" : "minecraft:purple_candle", + "blockRuntimeId" : 6482 + }, + { + "id" : "minecraft:blue_candle", + "blockRuntimeId" : 675 + }, + { + "id" : "minecraft:brown_candle", + "blockRuntimeId" : 884 + }, + { + "id" : "minecraft:green_candle", + "blockRuntimeId" : 4991 + }, + { + "id" : "minecraft:red_candle", + "blockRuntimeId" : 6553 + }, + { + "id" : "minecraft:black_candle", + "blockRuntimeId" : 478 + }, + { + "id" : "minecraft:crafting_table", + "blockRuntimeId" : 3770 + }, + { + "id" : "minecraft:cartography_table", + "blockRuntimeId" : 987 + }, + { + "id" : "minecraft:fletching_table", + "blockRuntimeId" : 4811 + }, + { + "id" : "minecraft:smithing_table", + "blockRuntimeId" : 6783 + }, + { + "id" : "minecraft:beehive", + "blockRuntimeId" : 260 + }, + { + "id" : "minecraft:campfire" + }, + { + "id" : "minecraft:soul_campfire" + }, + { + "id" : "minecraft:furnace", + "blockRuntimeId" : 4863 + }, + { + "id" : "minecraft:blast_furnace", + "blockRuntimeId" : 669 + }, + { + "id" : "minecraft:smoker", + "blockRuntimeId" : 6784 + }, + { + "id" : "minecraft:respawn_anchor", + "blockRuntimeId" : 6672 + }, + { + "id" : "minecraft:brewing_stand" + }, + { + "id" : "minecraft:anvil", + "blockRuntimeId" : 152 + }, + { + "id" : "minecraft:anvil", + "blockRuntimeId" : 156 + }, + { + "id" : "minecraft:anvil", + "blockRuntimeId" : 160 + }, + { + "id" : "minecraft:grindstone", + "blockRuntimeId" : 5007 + }, + { + "id" : "minecraft:enchanting_table", + "blockRuntimeId" : 4718 + }, + { + "id" : "minecraft:bookshelf", + "blockRuntimeId" : 704 + }, + { + "id" : "minecraft:lectern", + "blockRuntimeId" : 5409 + }, + { + "id" : "minecraft:cauldron" + }, + { + "id" : "minecraft:composter", + "blockRuntimeId" : 3634 + }, + { + "id" : "minecraft:chest", + "blockRuntimeId" : 1123 + }, + { + "id" : "minecraft:trapped_chest", + "blockRuntimeId" : 7283 + }, + { + "id" : "minecraft:ender_chest", + "blockRuntimeId" : 4745 + }, + { + "id" : "minecraft:barrel", + "blockRuntimeId" : 201 + }, + { + "id" : "minecraft:undyed_shulker_box", + "blockRuntimeId" : 7366 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 6734 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 6742 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 6741 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 6749 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 6746 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 6748 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 6735 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 6738 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 6739 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 6747 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 6743 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 6737 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 6745 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 6744 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 6736 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 6740 + }, + { + "id" : "minecraft:armor_stand" + }, + { + "id" : "minecraft:noteblock", + "blockRuntimeId" : 5689 + }, + { + "id" : "minecraft:jukebox", + "blockRuntimeId" : 5183 + }, + { + "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_pigstep" + }, + { + "id" : "minecraft:glowstone_dust" + }, + { + "id" : "minecraft:glowstone", + "blockRuntimeId" : 4949 + }, + { + "id" : "minecraft:redstone_lamp", + "blockRuntimeId" : 6619 + }, + { + "id" : "minecraft:sealantern", + "blockRuntimeId" : 6732 + }, + { + "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: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: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" : 217 + }, + { + "id" : "minecraft:bell", + "blockRuntimeId" : 292 + }, + { + "id" : "minecraft:conduit", + "blockRuntimeId" : 3675 + }, + { + "id" : "minecraft:stonecutter_block", + "blockRuntimeId" : 7199 + }, + { + "id" : "minecraft:end_portal_frame", + "blockRuntimeId" : 4730 + }, + { + "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: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" : 4738 + }, + { + "id" : "minecraft:lightning_rod", + "blockRuntimeId" : 5491 + }, + { + "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: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:rail", + "blockRuntimeId" : 6540 + }, + { + "id" : "minecraft:golden_rail", + "blockRuntimeId" : 4952 + }, + { + "id" : "minecraft:detector_rail", + "blockRuntimeId" : 4461 + }, + { + "id" : "minecraft:activator_rail", + "blockRuntimeId" : 122 + }, + { + "id" : "minecraft:minecart" + }, + { + "id" : "minecraft:chest_minecart" + }, + { + "id" : "minecraft:hopper_minecart" + }, + { + "id" : "minecraft:tnt_minecart" + }, + { + "id" : "minecraft:redstone" + }, + { + "id" : "minecraft:redstone_block", + "blockRuntimeId" : 6618 + }, + { + "id" : "minecraft:redstone_torch", + "blockRuntimeId" : 6621 + }, + { + "id" : "minecraft:lever", + "blockRuntimeId" : 5417 + }, + { + "id" : "minecraft:wooden_button", + "blockRuntimeId" : 7747 + }, + { + "id" : "minecraft:spruce_button", + "blockRuntimeId" : 6870 + }, + { + "id" : "minecraft:birch_button", + "blockRuntimeId" : 356 + }, + { + "id" : "minecraft:jungle_button", + "blockRuntimeId" : 5184 + }, + { + "id" : "minecraft:acacia_button" + }, + { + "id" : "minecraft:dark_oak_button", + "blockRuntimeId" : 3936 + }, + { + "id" : "minecraft:stone_button", + "blockRuntimeId" : 7099 + }, + { + "id" : "minecraft:crimson_button", + "blockRuntimeId" : 3771 + }, + { + "id" : "minecraft:warped_button", + "blockRuntimeId" : 7434 + }, + { + "id" : "minecraft:polished_blackstone_button", + "blockRuntimeId" : 5974 + }, + { + "id" : "minecraft:tripwire_hook", + "blockRuntimeId" : 7305 + }, + { + "id" : "minecraft:wooden_pressure_plate", + "blockRuntimeId" : 7791 + }, + { + "id" : "minecraft:spruce_pressure_plate", + "blockRuntimeId" : 6930 + }, + { + "id" : "minecraft:birch_pressure_plate", + "blockRuntimeId" : 416 + }, + { + "id" : "minecraft:jungle_pressure_plate", + "blockRuntimeId" : 5244 + }, + { + "id" : "minecraft:acacia_pressure_plate", + "blockRuntimeId" : 60 + }, + { + "id" : "minecraft:dark_oak_pressure_plate", + "blockRuntimeId" : 3996 + }, + { + "id" : "minecraft:crimson_pressure_plate", + "blockRuntimeId" : 3840 + }, + { + "id" : "minecraft:warped_pressure_plate", + "blockRuntimeId" : 7503 + }, + { + "id" : "minecraft:stone_pressure_plate", + "blockRuntimeId" : 7111 + }, + { + "id" : "minecraft:light_weighted_pressure_plate", + "blockRuntimeId" : 5475 + }, + { + "id" : "minecraft:heavy_weighted_pressure_plate", + "blockRuntimeId" : 5071 + }, + { + "id" : "minecraft:polished_blackstone_pressure_plate", + "blockRuntimeId" : 5988 + }, + { + "id" : "minecraft:observer", + "blockRuntimeId" : 5698 + }, + { + "id" : "minecraft:daylight_detector", + "blockRuntimeId" : 4066 + }, + { + "id" : "minecraft:repeater" + }, + { + "id" : "minecraft:comparator" + }, + { + "id" : "minecraft:hopper" + }, + { + "id" : "minecraft:dropper", + "blockRuntimeId" : 4588 + }, + { + "id" : "minecraft:dispenser", + "blockRuntimeId" : 4489 + }, + { + "id" : "minecraft:piston", + "blockRuntimeId" : 5759 + }, + { + "id" : "minecraft:sticky_piston", + "blockRuntimeId" : 7073 + }, + { + "id" : "minecraft:tnt", + "blockRuntimeId" : 7257 + }, + { + "id" : "minecraft:name_tag" + }, + { + "id" : "minecraft:loom", + "blockRuntimeId" : 5557 + }, + { + "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: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" : 7255 + }, + { + "id" : "minecraft:lodestone_compass" + } + ] +} \ No newline at end of file diff --git a/connector/src/main/resources/bedrock/runtime_item_states.json b/connector/src/main/resources/bedrock/runtime_item_states.1_17_0.json similarity index 100% rename from connector/src/main/resources/bedrock/runtime_item_states.json rename to connector/src/main/resources/bedrock/runtime_item_states.1_17_0.json diff --git a/connector/src/main/resources/bedrock/runtime_item_states.1_17_10.json b/connector/src/main/resources/bedrock/runtime_item_states.1_17_10.json new file mode 100644 index 000000000..45c9b5b88 --- /dev/null +++ b/connector/src/main/resources/bedrock/runtime_item_states.1_17_10.json @@ -0,0 +1,4290 @@ +[ + { + "name" : "minecraft:acacia_boat", + "id" : 379 + }, + { + "name" : "minecraft:acacia_button", + "id" : -140 + }, + { + "name" : "minecraft:acacia_door", + "id" : 556 + }, + { + "name" : "minecraft:acacia_fence_gate", + "id" : 187 + }, + { + "name" : "minecraft:acacia_pressure_plate", + "id" : -150 + }, + { + "name" : "minecraft:acacia_sign", + "id" : 579 + }, + { + "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" : 487 + }, + { + "name" : "minecraft:air", + "id" : -158 + }, + { + "name" : "minecraft:allow", + "id" : 210 + }, + { + "name" : "minecraft:amethyst_block", + "id" : -327 + }, + { + "name" : "minecraft:amethyst_cluster", + "id" : -329 + }, + { + "name" : "minecraft:amethyst_shard", + "id" : 623 + }, + { + "name" : "minecraft:ancient_debris", + "id" : -271 + }, + { + "name" : "minecraft:andesite_stairs", + "id" : -171 + }, + { + "name" : "minecraft:anvil", + "id" : 145 + }, + { + "name" : "minecraft:apple", + "id" : 257 + }, + { + "name" : "minecraft:armor_stand", + "id" : 552 + }, + { + "name" : "minecraft:arrow", + "id" : 301 + }, + { + "name" : "minecraft:axolotl_bucket", + "id" : 369 + }, + { + "name" : "minecraft:axolotl_spawn_egg", + "id" : 500 + }, + { + "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" : 597 + }, + { + "name" : "minecraft:bamboo", + "id" : -163 + }, + { + "name" : "minecraft:bamboo_sapling", + "id" : -164 + }, + { + "name" : "minecraft:banner", + "id" : 567 + }, + { + "name" : "minecraft:banner_pattern", + "id" : 627 + }, + { + "name" : "minecraft:barrel", + "id" : -203 + }, + { + "name" : "minecraft:barrier", + "id" : -161 + }, + { + "name" : "minecraft:basalt", + "id" : -234 + }, + { + "name" : "minecraft:bat_spawn_egg", + "id" : 453 + }, + { + "name" : "minecraft:beacon", + "id" : 138 + }, + { + "name" : "minecraft:bed", + "id" : 418 + }, + { + "name" : "minecraft:bedrock", + "id" : 7 + }, + { + "name" : "minecraft:bee_nest", + "id" : -218 + }, + { + "name" : "minecraft:bee_spawn_egg", + "id" : 494 + }, + { + "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" : 376 + }, + { + "name" : "minecraft:birch_button", + "id" : -141 + }, + { + "name" : "minecraft:birch_door", + "id" : 554 + }, + { + "name" : "minecraft:birch_fence_gate", + "id" : 184 + }, + { + "name" : "minecraft:birch_pressure_plate", + "id" : -151 + }, + { + "name" : "minecraft:birch_sign", + "id" : 577 + }, + { + "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" : 395 + }, + { + "name" : "minecraft:black_glazed_terracotta", + "id" : 235 + }, + { + "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" : 429 + }, + { + "name" : "minecraft:blaze_rod", + "id" : 423 + }, + { + "name" : "minecraft:blaze_spawn_egg", + "id" : 456 + }, + { + "name" : "minecraft:bleach", + "id" : 595 + }, + { + "name" : "minecraft:blue_candle", + "id" : -424 + }, + { + "name" : "minecraft:blue_candle_cake", + "id" : -441 + }, + { + "name" : "minecraft:blue_dye", + "id" : 399 + }, + { + "name" : "minecraft:blue_glazed_terracotta", + "id" : 231 + }, + { + "name" : "minecraft:blue_ice", + "id" : -11 + }, + { + "name" : "minecraft:boat", + "id" : 625 + }, + { + "name" : "minecraft:bone", + "id" : 415 + }, + { + "name" : "minecraft:bone_block", + "id" : 216 + }, + { + "name" : "minecraft:bone_meal", + "id" : 411 + }, + { + "name" : "minecraft:book", + "id" : 387 + }, + { + "name" : "minecraft:bookshelf", + "id" : 47 + }, + { + "name" : "minecraft:border_block", + "id" : 212 + }, + { + "name" : "minecraft:bordure_indented_banner_pattern", + "id" : 586 + }, + { + "name" : "minecraft:bow", + "id" : 300 + }, + { + "name" : "minecraft:bowl", + "id" : 321 + }, + { + "name" : "minecraft:bread", + "id" : 261 + }, + { + "name" : "minecraft:brewing_stand", + "id" : 431 + }, + { + "name" : "minecraft:brewingstandblock", + "id" : 117 + }, + { + "name" : "minecraft:brick", + "id" : 383 + }, + { + "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" : 398 + }, + { + "name" : "minecraft:brown_glazed_terracotta", + "id" : 232 + }, + { + "name" : "minecraft:brown_mushroom", + "id" : 39 + }, + { + "name" : "minecraft:brown_mushroom_block", + "id" : 99 + }, + { + "name" : "minecraft:bubble_column", + "id" : -160 + }, + { + "name" : "minecraft:bucket", + "id" : 360 + }, + { + "name" : "minecraft:budding_amethyst", + "id" : -328 + }, + { + "name" : "minecraft:cactus", + "id" : 81 + }, + { + "name" : "minecraft:cake", + "id" : 417 + }, + { + "name" : "minecraft:calcite", + "id" : -326 + }, + { + "name" : "minecraft:camera", + "id" : 592 + }, + { + "name" : "minecraft:campfire", + "id" : 588 + }, + { + "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" : 517 + }, + { + "name" : "minecraft:carrots", + "id" : 141 + }, + { + "name" : "minecraft:cartography_table", + "id" : -200 + }, + { + "name" : "minecraft:carved_pumpkin", + "id" : -155 + }, + { + "name" : "minecraft:cat_spawn_egg", + "id" : 488 + }, + { + "name" : "minecraft:cauldron", + "id" : 432 + }, + { + "name" : "minecraft:cave_spider_spawn_egg", + "id" : 457 + }, + { + "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" : 617 + }, + { + "name" : "minecraft:chain_command_block", + "id" : 189 + }, + { + "name" : "minecraft:chainmail_boots", + "id" : 342 + }, + { + "name" : "minecraft:chainmail_chestplate", + "id" : 340 + }, + { + "name" : "minecraft:chainmail_helmet", + "id" : 339 + }, + { + "name" : "minecraft:chainmail_leggings", + "id" : 341 + }, + { + "name" : "minecraft:charcoal", + "id" : 303 + }, + { + "name" : "minecraft:chemical_heat", + "id" : 192 + }, + { + "name" : "minecraft:chemistry_table", + "id" : 238 + }, + { + "name" : "minecraft:chest", + "id" : 54 + }, + { + "name" : "minecraft:chest_minecart", + "id" : 389 + }, + { + "name" : "minecraft:chicken", + "id" : 275 + }, + { + "name" : "minecraft:chicken_spawn_egg", + "id" : 435 + }, + { + "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" : 558 + }, + { + "name" : "minecraft:chorus_plant", + "id" : 240 + }, + { + "name" : "minecraft:clay", + "id" : 82 + }, + { + "name" : "minecraft:clay_ball", + "id" : 384 + }, + { + "name" : "minecraft:clock", + "id" : 393 + }, + { + "name" : "minecraft:coal", + "id" : 302 + }, + { + "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" : 412 + }, + { + "name" : "minecraft:cod", + "id" : 264 + }, + { + "name" : "minecraft:cod_bucket", + "id" : 364 + }, + { + "name" : "minecraft:cod_spawn_egg", + "id" : 480 + }, + { + "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" : 563 + }, + { + "name" : "minecraft:comparator", + "id" : 522 + }, + { + "name" : "minecraft:compass", + "id" : 391 + }, + { + "name" : "minecraft:composter", + "id" : -213 + }, + { + "name" : "minecraft:compound", + "id" : 593 + }, + { + "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" : 551 + }, + { + "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" : 504 + }, + { + "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" : 436 + }, + { + "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" : 582 + }, + { + "name" : "minecraft:creeper_spawn_egg", + "id" : 441 + }, + { + "name" : "minecraft:crimson_button", + "id" : -260 + }, + { + "name" : "minecraft:crimson_door", + "id" : 614 + }, + { + "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_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" : 612 + }, + { + "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" : 575 + }, + { + "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" : 401 + }, + { + "name" : "minecraft:cyan_glazed_terracotta", + "id" : 229 + }, + { + "name" : "minecraft:dark_oak_boat", + "id" : 380 + }, + { + "name" : "minecraft:dark_oak_button", + "id" : -142 + }, + { + "name" : "minecraft:dark_oak_door", + "id" : 557 + }, + { + "name" : "minecraft:dark_oak_fence_gate", + "id" : 186 + }, + { + "name" : "minecraft:dark_oak_pressure_plate", + "id" : -152 + }, + { + "name" : "minecraft:dark_oak_sign", + "id" : 580 + }, + { + "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: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" : 304 + }, + { + "name" : "minecraft:diamond_axe", + "id" : 319 + }, + { + "name" : "minecraft:diamond_block", + "id" : 57 + }, + { + "name" : "minecraft:diamond_boots", + "id" : 350 + }, + { + "name" : "minecraft:diamond_chestplate", + "id" : 348 + }, + { + "name" : "minecraft:diamond_helmet", + "id" : 347 + }, + { + "name" : "minecraft:diamond_hoe", + "id" : 332 + }, + { + "name" : "minecraft:diamond_horse_armor", + "id" : 533 + }, + { + "name" : "minecraft:diamond_leggings", + "id" : 349 + }, + { + "name" : "minecraft:diamond_ore", + "id" : 56 + }, + { + "name" : "minecraft:diamond_pickaxe", + "id" : 318 + }, + { + "name" : "minecraft:diamond_shovel", + "id" : 317 + }, + { + "name" : "minecraft:diamond_sword", + "id" : 316 + }, + { + "name" : "minecraft:diorite_stairs", + "id" : -170 + }, + { + "name" : "minecraft:dirt", + "id" : 3 + }, + { + "name" : "minecraft:dirt_with_roots", + "id" : -318 + }, + { + "name" : "minecraft:dispenser", + "id" : 23 + }, + { + "name" : "minecraft:dolphin_spawn_egg", + "id" : 484 + }, + { + "name" : "minecraft:donkey_spawn_egg", + "id" : 465 + }, + { + "name" : "minecraft:double_cut_copper_slab", + "id" : -368 + }, + { + "name" : "minecraft:double_plant", + "id" : 175 + }, + { + "name" : "minecraft:double_stone_slab", + "id" : 44 + }, + { + "name" : "minecraft:double_stone_slab2", + "id" : 182 + }, + { + "name" : "minecraft:double_stone_slab3", + "id" : -162 + }, + { + "name" : "minecraft:double_stone_slab4", + "id" : -166 + }, + { + "name" : "minecraft:double_wooden_slab", + "id" : 157 + }, + { + "name" : "minecraft:dragon_breath", + "id" : 560 + }, + { + "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" : 483 + }, + { + "name" : "minecraft:dye", + "id" : 626 + }, + { + "name" : "minecraft:egg", + "id" : 390 + }, + { + "name" : "minecraft:elder_guardian_spawn_egg", + "id" : 471 + }, + { + "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" : 564 + }, + { + "name" : "minecraft:emerald", + "id" : 512 + }, + { + "name" : "minecraft:emerald_block", + "id" : 133 + }, + { + "name" : "minecraft:emerald_ore", + "id" : 129 + }, + { + "name" : "minecraft:empty_map", + "id" : 515 + }, + { + "name" : "minecraft:enchanted_book", + "id" : 521 + }, + { + "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" : 629 + }, + { + "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_eye", + "id" : 433 + }, + { + "name" : "minecraft:ender_pearl", + "id" : 422 + }, + { + "name" : "minecraft:enderman_spawn_egg", + "id" : 442 + }, + { + "name" : "minecraft:endermite_spawn_egg", + "id" : 460 + }, + { + "name" : "minecraft:evoker_spawn_egg", + "id" : 475 + }, + { + "name" : "minecraft:experience_bottle", + "id" : 508 + }, + { + "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" : 327 + }, + { + "name" : "minecraft:fence", + "id" : 85 + }, + { + "name" : "minecraft:fence_gate", + "id" : 107 + }, + { + "name" : "minecraft:fermented_spider_eye", + "id" : 428 + }, + { + "name" : "minecraft:field_masoned_banner_pattern", + "id" : 585 + }, + { + "name" : "minecraft:filled_map", + "id" : 420 + }, + { + "name" : "minecraft:fire", + "id" : 51 + }, + { + "name" : "minecraft:fire_charge", + "id" : 509 + }, + { + "name" : "minecraft:firework_rocket", + "id" : 519 + }, + { + "name" : "minecraft:firework_star", + "id" : 520 + }, + { + "name" : "minecraft:fishing_rod", + "id" : 392 + }, + { + "name" : "minecraft:fletching_table", + "id" : -201 + }, + { + "name" : "minecraft:flint", + "id" : 356 + }, + { + "name" : "minecraft:flint_and_steel", + "id" : 299 + }, + { + "name" : "minecraft:flower_banner_pattern", + "id" : 581 + }, + { + "name" : "minecraft:flower_pot", + "id" : 514 + }, + { + "name" : "minecraft:flowering_azalea", + "id" : -338 + }, + { + "name" : "minecraft:flowing_lava", + "id" : 10 + }, + { + "name" : "minecraft:flowing_water", + "id" : 8 + }, + { + "name" : "minecraft:fox_spawn_egg", + "id" : 490 + }, + { + "name" : "minecraft:frame", + "id" : 513 + }, + { + "name" : "minecraft:frosted_ice", + "id" : 207 + }, + { + "name" : "minecraft:furnace", + "id" : 61 + }, + { + "name" : "minecraft:ghast_spawn_egg", + "id" : 454 + }, + { + "name" : "minecraft:ghast_tear", + "id" : 424 + }, + { + "name" : "minecraft:gilded_blackstone", + "id" : -281 + }, + { + "name" : "minecraft:glass", + "id" : 20 + }, + { + "name" : "minecraft:glass_bottle", + "id" : 427 + }, + { + "name" : "minecraft:glass_pane", + "id" : 102 + }, + { + "name" : "minecraft:glistering_melon_slice", + "id" : 434 + }, + { + "name" : "minecraft:glow_berries", + "id" : 630 + }, + { + "name" : "minecraft:glow_frame", + "id" : 621 + }, + { + "name" : "minecraft:glow_ink_sac", + "id" : 503 + }, + { + "name" : "minecraft:glow_lichen", + "id" : -411 + }, + { + "name" : "minecraft:glow_squid_spawn_egg", + "id" : 502 + }, + { + "name" : "minecraft:glow_stick", + "id" : 166 + }, + { + "name" : "minecraft:glowingobsidian", + "id" : 246 + }, + { + "name" : "minecraft:glowstone", + "id" : 89 + }, + { + "name" : "minecraft:glowstone_dust", + "id" : 394 + }, + { + "name" : "minecraft:goat_horn", + "id" : 622 + }, + { + "name" : "minecraft:goat_spawn_egg", + "id" : 501 + }, + { + "name" : "minecraft:gold_block", + "id" : 41 + }, + { + "name" : "minecraft:gold_ingot", + "id" : 306 + }, + { + "name" : "minecraft:gold_nugget", + "id" : 425 + }, + { + "name" : "minecraft:gold_ore", + "id" : 14 + }, + { + "name" : "minecraft:golden_apple", + "id" : 258 + }, + { + "name" : "minecraft:golden_axe", + "id" : 325 + }, + { + "name" : "minecraft:golden_boots", + "id" : 354 + }, + { + "name" : "minecraft:golden_carrot", + "id" : 283 + }, + { + "name" : "minecraft:golden_chestplate", + "id" : 352 + }, + { + "name" : "minecraft:golden_helmet", + "id" : 351 + }, + { + "name" : "minecraft:golden_hoe", + "id" : 333 + }, + { + "name" : "minecraft:golden_horse_armor", + "id" : 532 + }, + { + "name" : "minecraft:golden_leggings", + "id" : 353 + }, + { + "name" : "minecraft:golden_pickaxe", + "id" : 324 + }, + { + "name" : "minecraft:golden_rail", + "id" : 27 + }, + { + "name" : "minecraft:golden_shovel", + "id" : 323 + }, + { + "name" : "minecraft:golden_sword", + "id" : 322 + }, + { + "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" : 403 + }, + { + "name" : "minecraft:gray_glazed_terracotta", + "id" : 227 + }, + { + "name" : "minecraft:green_candle", + "id" : -426 + }, + { + "name" : "minecraft:green_candle_cake", + "id" : -443 + }, + { + "name" : "minecraft:green_dye", + "id" : 397 + }, + { + "name" : "minecraft:green_glazed_terracotta", + "id" : 233 + }, + { + "name" : "minecraft:grindstone", + "id" : -195 + }, + { + "name" : "minecraft:guardian_spawn_egg", + "id" : 461 + }, + { + "name" : "minecraft:gunpowder", + "id" : 328 + }, + { + "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" : 571 + }, + { + "name" : "minecraft:heavy_weighted_pressure_plate", + "id" : 148 + }, + { + "name" : "minecraft:hoglin_spawn_egg", + "id" : 496 + }, + { + "name" : "minecraft:honey_block", + "id" : -220 + }, + { + "name" : "minecraft:honey_bottle", + "id" : 591 + }, + { + "name" : "minecraft:honeycomb", + "id" : 590 + }, + { + "name" : "minecraft:honeycomb_block", + "id" : -221 + }, + { + "name" : "minecraft:hopper", + "id" : 527 + }, + { + "name" : "minecraft:hopper_minecart", + "id" : 526 + }, + { + "name" : "minecraft:horse_spawn_egg", + "id" : 458 + }, + { + "name" : "minecraft:husk_spawn_egg", + "id" : 463 + }, + { + "name" : "minecraft:ice", + "id" : 79 + }, + { + "name" : "minecraft:ice_bomb", + "id" : 594 + }, + { + "name" : "minecraft:infested_deepslate", + "id" : -454 + }, + { + "name" : "minecraft:info_update", + "id" : 248 + }, + { + "name" : "minecraft:info_update2", + "id" : 249 + }, + { + "name" : "minecraft:ink_sac", + "id" : 413 + }, + { + "name" : "minecraft:invisiblebedrock", + "id" : 95 + }, + { + "name" : "minecraft:iron_axe", + "id" : 298 + }, + { + "name" : "minecraft:iron_bars", + "id" : 101 + }, + { + "name" : "minecraft:iron_block", + "id" : 42 + }, + { + "name" : "minecraft:iron_boots", + "id" : 346 + }, + { + "name" : "minecraft:iron_chestplate", + "id" : 344 + }, + { + "name" : "minecraft:iron_door", + "id" : 372 + }, + { + "name" : "minecraft:iron_helmet", + "id" : 343 + }, + { + "name" : "minecraft:iron_hoe", + "id" : 331 + }, + { + "name" : "minecraft:iron_horse_armor", + "id" : 531 + }, + { + "name" : "minecraft:iron_ingot", + "id" : 305 + }, + { + "name" : "minecraft:iron_leggings", + "id" : 345 + }, + { + "name" : "minecraft:iron_nugget", + "id" : 569 + }, + { + "name" : "minecraft:iron_ore", + "id" : 15 + }, + { + "name" : "minecraft:iron_pickaxe", + "id" : 297 + }, + { + "name" : "minecraft:iron_shovel", + "id" : 296 + }, + { + "name" : "minecraft:iron_sword", + "id" : 307 + }, + { + "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.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.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" : 377 + }, + { + "name" : "minecraft:jungle_button", + "id" : -143 + }, + { + "name" : "minecraft:jungle_door", + "id" : 555 + }, + { + "name" : "minecraft:jungle_fence_gate", + "id" : 185 + }, + { + "name" : "minecraft:jungle_pressure_plate", + "id" : -153 + }, + { + "name" : "minecraft:jungle_sign", + "id" : 578 + }, + { + "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" : 382 + }, + { + "name" : "minecraft:ladder", + "id" : 65 + }, + { + "name" : "minecraft:lantern", + "id" : -208 + }, + { + "name" : "minecraft:lapis_block", + "id" : 22 + }, + { + "name" : "minecraft:lapis_lazuli", + "id" : 414 + }, + { + "name" : "minecraft:lapis_ore", + "id" : 21 + }, + { + "name" : "minecraft:large_amethyst_bud", + "id" : -330 + }, + { + "name" : "minecraft:lava", + "id" : 11 + }, + { + "name" : "minecraft:lava_bucket", + "id" : 363 + }, + { + "name" : "minecraft:lava_cauldron", + "id" : -210 + }, + { + "name" : "minecraft:lead", + "id" : 547 + }, + { + "name" : "minecraft:leather", + "id" : 381 + }, + { + "name" : "minecraft:leather_boots", + "id" : 338 + }, + { + "name" : "minecraft:leather_chestplate", + "id" : 336 + }, + { + "name" : "minecraft:leather_helmet", + "id" : 335 + }, + { + "name" : "minecraft:leather_horse_armor", + "id" : 530 + }, + { + "name" : "minecraft:leather_leggings", + "id" : 337 + }, + { + "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" : 407 + }, + { + "name" : "minecraft:light_blue_glazed_terracotta", + "id" : 223 + }, + { + "name" : "minecraft:light_gray_candle", + "id" : -421 + }, + { + "name" : "minecraft:light_gray_candle_cake", + "id" : -438 + }, + { + "name" : "minecraft:light_gray_dye", + "id" : 402 + }, + { + "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" : 405 + }, + { + "name" : "minecraft:lime_glazed_terracotta", + "id" : 225 + }, + { + "name" : "minecraft:lingering_potion", + "id" : 562 + }, + { + "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" : 473 + }, + { + "name" : "minecraft:lodestone", + "id" : -222 + }, + { + "name" : "minecraft:lodestone_compass", + "id" : 600 + }, + { + "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" : 408 + }, + { + "name" : "minecraft:magenta_glazed_terracotta", + "id" : 222 + }, + { + "name" : "minecraft:magma", + "id" : 213 + }, + { + "name" : "minecraft:magma_cream", + "id" : 430 + }, + { + "name" : "minecraft:magma_cube_spawn_egg", + "id" : 455 + }, + { + "name" : "minecraft:medicine", + "id" : 598 + }, + { + "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" : 361 + }, + { + "name" : "minecraft:minecart", + "id" : 370 + }, + { + "name" : "minecraft:mob_spawner", + "id" : 52 + }, + { + "name" : "minecraft:mojang_banner_pattern", + "id" : 584 + }, + { + "name" : "minecraft:monster_egg", + "id" : 97 + }, + { + "name" : "minecraft:mooshroom_spawn_egg", + "id" : 440 + }, + { + "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:movingblock", + "id" : 250 + }, + { + "name" : "minecraft:mule_spawn_egg", + "id" : 466 + }, + { + "name" : "minecraft:mushroom_stew", + "id" : 260 + }, + { + "name" : "minecraft:music_disc_11", + "id" : 544 + }, + { + "name" : "minecraft:music_disc_13", + "id" : 534 + }, + { + "name" : "minecraft:music_disc_blocks", + "id" : 536 + }, + { + "name" : "minecraft:music_disc_cat", + "id" : 535 + }, + { + "name" : "minecraft:music_disc_chirp", + "id" : 537 + }, + { + "name" : "minecraft:music_disc_far", + "id" : 538 + }, + { + "name" : "minecraft:music_disc_mall", + "id" : 539 + }, + { + "name" : "minecraft:music_disc_mellohi", + "id" : 540 + }, + { + "name" : "minecraft:music_disc_pigstep", + "id" : 618 + }, + { + "name" : "minecraft:music_disc_stal", + "id" : 541 + }, + { + "name" : "minecraft:music_disc_strad", + "id" : 542 + }, + { + "name" : "minecraft:music_disc_wait", + "id" : 545 + }, + { + "name" : "minecraft:music_disc_ward", + "id" : 543 + }, + { + "name" : "minecraft:mutton", + "id" : 550 + }, + { + "name" : "minecraft:mycelium", + "id" : 110 + }, + { + "name" : "minecraft:name_tag", + "id" : 548 + }, + { + "name" : "minecraft:nautilus_shell", + "id" : 570 + }, + { + "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" : 619 + }, + { + "name" : "minecraft:nether_star", + "id" : 518 + }, + { + "name" : "minecraft:nether_wart", + "id" : 294 + }, + { + "name" : "minecraft:nether_wart_block", + "id" : 214 + }, + { + "name" : "minecraft:netherbrick", + "id" : 523 + }, + { + "name" : "minecraft:netherite_axe", + "id" : 605 + }, + { + "name" : "minecraft:netherite_block", + "id" : -270 + }, + { + "name" : "minecraft:netherite_boots", + "id" : 610 + }, + { + "name" : "minecraft:netherite_chestplate", + "id" : 608 + }, + { + "name" : "minecraft:netherite_helmet", + "id" : 607 + }, + { + "name" : "minecraft:netherite_hoe", + "id" : 606 + }, + { + "name" : "minecraft:netherite_ingot", + "id" : 601 + }, + { + "name" : "minecraft:netherite_leggings", + "id" : 609 + }, + { + "name" : "minecraft:netherite_pickaxe", + "id" : 604 + }, + { + "name" : "minecraft:netherite_scrap", + "id" : 611 + }, + { + "name" : "minecraft:netherite_shovel", + "id" : 603 + }, + { + "name" : "minecraft:netherite_sword", + "id" : 602 + }, + { + "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" : 470 + }, + { + "name" : "minecraft:oak_boat", + "id" : 375 + }, + { + "name" : "minecraft:oak_sign", + "id" : 358 + }, + { + "name" : "minecraft:oak_stairs", + "id" : 53 + }, + { + "name" : "minecraft:observer", + "id" : 251 + }, + { + "name" : "minecraft:obsidian", + "id" : 49 + }, + { + "name" : "minecraft:ocelot_spawn_egg", + "id" : 451 + }, + { + "name" : "minecraft:orange_candle", + "id" : -414 + }, + { + "name" : "minecraft:orange_candle_cake", + "id" : -431 + }, + { + "name" : "minecraft:orange_dye", + "id" : 409 + }, + { + "name" : "minecraft:orange_glazed_terracotta", + "id" : 221 + }, + { + "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:painting", + "id" : 357 + }, + { + "name" : "minecraft:panda_spawn_egg", + "id" : 489 + }, + { + "name" : "minecraft:paper", + "id" : 386 + }, + { + "name" : "minecraft:parrot_spawn_egg", + "id" : 478 + }, + { + "name" : "minecraft:phantom_membrane", + "id" : 574 + }, + { + "name" : "minecraft:phantom_spawn_egg", + "id" : 486 + }, + { + "name" : "minecraft:pig_spawn_egg", + "id" : 437 + }, + { + "name" : "minecraft:piglin_banner_pattern", + "id" : 587 + }, + { + "name" : "minecraft:piglin_brute_spawn_egg", + "id" : 499 + }, + { + "name" : "minecraft:piglin_spawn_egg", + "id" : 497 + }, + { + "name" : "minecraft:pillager_spawn_egg", + "id" : 491 + }, + { + "name" : "minecraft:pink_candle", + "id" : -419 + }, + { + "name" : "minecraft:pink_candle_cake", + "id" : -436 + }, + { + "name" : "minecraft:pink_dye", + "id" : 404 + }, + { + "name" : "minecraft:pink_glazed_terracotta", + "id" : 226 + }, + { + "name" : "minecraft:piston", + "id" : 33 + }, + { + "name" : "minecraft:pistonarmcollision", + "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" : 472 + }, + { + "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" : 559 + }, + { + "name" : "minecraft:porkchop", + "id" : 262 + }, + { + "name" : "minecraft:portal", + "id" : 90 + }, + { + "name" : "minecraft:potato", + "id" : 280 + }, + { + "name" : "minecraft:potatoes", + "id" : 142 + }, + { + "name" : "minecraft:potion", + "id" : 426 + }, + { + "name" : "minecraft:powder_snow", + "id" : -306 + }, + { + "name" : "minecraft:powder_snow_bucket", + "id" : 368 + }, + { + "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" : 549 + }, + { + "name" : "minecraft:prismarine_shard", + "id" : 565 + }, + { + "name" : "minecraft:prismarine_stairs", + "id" : -2 + }, + { + "name" : "minecraft:pufferfish", + "id" : 267 + }, + { + "name" : "minecraft:pufferfish_bucket", + "id" : 367 + }, + { + "name" : "minecraft:pufferfish_spawn_egg", + "id" : 481 + }, + { + "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" : 400 + }, + { + "name" : "minecraft:purple_glazed_terracotta", + "id" : 219 + }, + { + "name" : "minecraft:purpur_block", + "id" : 201 + }, + { + "name" : "minecraft:purpur_stairs", + "id" : 203 + }, + { + "name" : "minecraft:quartz", + "id" : 524 + }, + { + "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" : 528 + }, + { + "name" : "minecraft:rabbit_hide", + "id" : 529 + }, + { + "name" : "minecraft:rabbit_spawn_egg", + "id" : 459 + }, + { + "name" : "minecraft:rabbit_stew", + "id" : 290 + }, + { + "name" : "minecraft:rail", + "id" : 66 + }, + { + "name" : "minecraft:rapid_fertilizer", + "id" : 596 + }, + { + "name" : "minecraft:ravager_spawn_egg", + "id" : 493 + }, + { + "name" : "minecraft:raw_copper", + "id" : 507 + }, + { + "name" : "minecraft:raw_copper_block", + "id" : -452 + }, + { + "name" : "minecraft:raw_gold", + "id" : 506 + }, + { + "name" : "minecraft:raw_gold_block", + "id" : -453 + }, + { + "name" : "minecraft:raw_iron", + "id" : 505 + }, + { + "name" : "minecraft:raw_iron_block", + "id" : -451 + }, + { + "name" : "minecraft:real_double_stone_slab", + "id" : 43 + }, + { + "name" : "minecraft:real_double_stone_slab2", + "id" : 181 + }, + { + "name" : "minecraft:real_double_stone_slab3", + "id" : -167 + }, + { + "name" : "minecraft:real_double_stone_slab4", + "id" : -168 + }, + { + "name" : "minecraft:red_candle", + "id" : -427 + }, + { + "name" : "minecraft:red_candle_cake", + "id" : -444 + }, + { + "name" : "minecraft:red_dye", + "id" : 396 + }, + { + "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:redstone", + "id" : 373 + }, + { + "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:repeater", + "id" : 419 + }, + { + "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" : 371 + }, + { + "name" : "minecraft:salmon", + "id" : 265 + }, + { + "name" : "minecraft:salmon_bucket", + "id" : 365 + }, + { + "name" : "minecraft:salmon_spawn_egg", + "id" : 482 + }, + { + "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_sensor", + "id" : -307 + }, + { + "name" : "minecraft:scute", + "id" : 572 + }, + { + "name" : "minecraft:sea_pickle", + "id" : -156 + }, + { + "name" : "minecraft:seagrass", + "id" : -130 + }, + { + "name" : "minecraft:sealantern", + "id" : 169 + }, + { + "name" : "minecraft:shears", + "id" : 421 + }, + { + "name" : "minecraft:sheep_spawn_egg", + "id" : 438 + }, + { + "name" : "minecraft:shield", + "id" : 355 + }, + { + "name" : "minecraft:shroomlight", + "id" : -230 + }, + { + "name" : "minecraft:shulker_box", + "id" : 218 + }, + { + "name" : "minecraft:shulker_shell", + "id" : 566 + }, + { + "name" : "minecraft:shulker_spawn_egg", + "id" : 469 + }, + { + "name" : "minecraft:silver_glazed_terracotta", + "id" : 228 + }, + { + "name" : "minecraft:silverfish_spawn_egg", + "id" : 443 + }, + { + "name" : "minecraft:skeleton_horse_spawn_egg", + "id" : 467 + }, + { + "name" : "minecraft:skeleton_spawn_egg", + "id" : 444 + }, + { + "name" : "minecraft:skull", + "id" : 516 + }, + { + "name" : "minecraft:skull_banner_pattern", + "id" : 583 + }, + { + "name" : "minecraft:slime", + "id" : 165 + }, + { + "name" : "minecraft:slime_ball", + "id" : 388 + }, + { + "name" : "minecraft:slime_spawn_egg", + "id" : 445 + }, + { + "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:snow", + "id" : 80 + }, + { + "name" : "minecraft:snow_layer", + "id" : 78 + }, + { + "name" : "minecraft:snowball", + "id" : 374 + }, + { + "name" : "minecraft:soul_campfire", + "id" : 620 + }, + { + "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" : 599 + }, + { + "name" : "minecraft:spawn_egg", + "id" : 628 + }, + { + "name" : "minecraft:spider_eye", + "id" : 278 + }, + { + "name" : "minecraft:spider_spawn_egg", + "id" : 446 + }, + { + "name" : "minecraft:splash_potion", + "id" : 561 + }, + { + "name" : "minecraft:sponge", + "id" : 19 + }, + { + "name" : "minecraft:spore_blossom", + "id" : -321 + }, + { + "name" : "minecraft:spruce_boat", + "id" : 378 + }, + { + "name" : "minecraft:spruce_button", + "id" : -144 + }, + { + "name" : "minecraft:spruce_door", + "id" : 553 + }, + { + "name" : "minecraft:spruce_fence_gate", + "id" : 183 + }, + { + "name" : "minecraft:spruce_pressure_plate", + "id" : -154 + }, + { + "name" : "minecraft:spruce_sign", + "id" : 576 + }, + { + "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" : 624 + }, + { + "name" : "minecraft:squid_spawn_egg", + "id" : 450 + }, + { + "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" : 320 + }, + { + "name" : "minecraft:sticky_piston", + "id" : 29 + }, + { + "name" : "minecraft:stickypistonarmcollision", + "id" : -217 + }, + { + "name" : "minecraft:stone", + "id" : 1 + }, + { + "name" : "minecraft:stone_axe", + "id" : 315 + }, + { + "name" : "minecraft:stone_brick_stairs", + "id" : 109 + }, + { + "name" : "minecraft:stone_button", + "id" : 77 + }, + { + "name" : "minecraft:stone_hoe", + "id" : 330 + }, + { + "name" : "minecraft:stone_pickaxe", + "id" : 314 + }, + { + "name" : "minecraft:stone_pressure_plate", + "id" : 70 + }, + { + "name" : "minecraft:stone_shovel", + "id" : 313 + }, + { + "name" : "minecraft:stone_stairs", + "id" : 67 + }, + { + "name" : "minecraft:stone_sword", + "id" : 312 + }, + { + "name" : "minecraft:stonebrick", + "id" : 98 + }, + { + "name" : "minecraft:stonecutter", + "id" : 245 + }, + { + "name" : "minecraft:stonecutter_block", + "id" : -197 + }, + { + "name" : "minecraft:stray_spawn_egg", + "id" : 462 + }, + { + "name" : "minecraft:strider_spawn_egg", + "id" : 495 + }, + { + "name" : "minecraft:string", + "id" : 326 + }, + { + "name" : "minecraft:stripped_acacia_log", + "id" : -8 + }, + { + "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_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" : 416 + }, + { + "name" : "minecraft:sugar_cane", + "id" : 385 + }, + { + "name" : "minecraft:suspicious_stew", + "id" : 589 + }, + { + "name" : "minecraft:sweet_berries", + "id" : 287 + }, + { + "name" : "minecraft:sweet_berry_bush", + "id" : -207 + }, + { + "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" : 525 + }, + { + "name" : "minecraft:torch", + "id" : 50 + }, + { + "name" : "minecraft:totem_of_undying", + "id" : 568 + }, + { + "name" : "minecraft:trapdoor", + "id" : 96 + }, + { + "name" : "minecraft:trapped_chest", + "id" : 146 + }, + { + "name" : "minecraft:trident", + "id" : 546 + }, + { + "name" : "minecraft:tripwire", + "id" : 132 + }, + { + "name" : "minecraft:tripwire_hook", + "id" : 131 + }, + { + "name" : "minecraft:tropical_fish", + "id" : 266 + }, + { + "name" : "minecraft:tropical_fish_bucket", + "id" : 366 + }, + { + "name" : "minecraft:tropical_fish_spawn_egg", + "id" : 479 + }, + { + "name" : "minecraft:tuff", + "id" : -333 + }, + { + "name" : "minecraft:turtle_egg", + "id" : -159 + }, + { + "name" : "minecraft:turtle_helmet", + "id" : 573 + }, + { + "name" : "minecraft:turtle_spawn_egg", + "id" : 485 + }, + { + "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:vex_spawn_egg", + "id" : 476 + }, + { + "name" : "minecraft:villager_spawn_egg", + "id" : 449 + }, + { + "name" : "minecraft:vindicator_spawn_egg", + "id" : 474 + }, + { + "name" : "minecraft:vine", + "id" : 106 + }, + { + "name" : "minecraft:wall_banner", + "id" : 177 + }, + { + "name" : "minecraft:wall_sign", + "id" : 68 + }, + { + "name" : "minecraft:wandering_trader_spawn_egg", + "id" : 492 + }, + { + "name" : "minecraft:warped_button", + "id" : -261 + }, + { + "name" : "minecraft:warped_door", + "id" : 615 + }, + { + "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" : 616 + }, + { + "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" : 613 + }, + { + "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" : 362 + }, + { + "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" : 334 + }, + { + "name" : "minecraft:wheat_seeds", + "id" : 291 + }, + { + "name" : "minecraft:white_candle", + "id" : -413 + }, + { + "name" : "minecraft:white_candle_cake", + "id" : -430 + }, + { + "name" : "minecraft:white_dye", + "id" : 410 + }, + { + "name" : "minecraft:white_glazed_terracotta", + "id" : 220 + }, + { + "name" : "minecraft:witch_spawn_egg", + "id" : 452 + }, + { + "name" : "minecraft:wither_rose", + "id" : -216 + }, + { + "name" : "minecraft:wither_skeleton_spawn_egg", + "id" : 464 + }, + { + "name" : "minecraft:wolf_spawn_egg", + "id" : 439 + }, + { + "name" : "minecraft:wood", + "id" : -212 + }, + { + "name" : "minecraft:wooden_axe", + "id" : 311 + }, + { + "name" : "minecraft:wooden_button", + "id" : 143 + }, + { + "name" : "minecraft:wooden_door", + "id" : 359 + }, + { + "name" : "minecraft:wooden_hoe", + "id" : 329 + }, + { + "name" : "minecraft:wooden_pickaxe", + "id" : 310 + }, + { + "name" : "minecraft:wooden_pressure_plate", + "id" : 72 + }, + { + "name" : "minecraft:wooden_shovel", + "id" : 309 + }, + { + "name" : "minecraft:wooden_slab", + "id" : 158 + }, + { + "name" : "minecraft:wooden_sword", + "id" : 308 + }, + { + "name" : "minecraft:wool", + "id" : 35 + }, + { + "name" : "minecraft:writable_book", + "id" : 510 + }, + { + "name" : "minecraft:written_book", + "id" : 511 + }, + { + "name" : "minecraft:yellow_candle", + "id" : -417 + }, + { + "name" : "minecraft:yellow_candle_cake", + "id" : -434 + }, + { + "name" : "minecraft:yellow_dye", + "id" : 406 + }, + { + "name" : "minecraft:yellow_flower", + "id" : 37 + }, + { + "name" : "minecraft:yellow_glazed_terracotta", + "id" : 224 + }, + { + "name" : "minecraft:zoglin_spawn_egg", + "id" : 498 + }, + { + "name" : "minecraft:zombie_horse_spawn_egg", + "id" : 468 + }, + { + "name" : "minecraft:zombie_pigman_spawn_egg", + "id" : 448 + }, + { + "name" : "minecraft:zombie_spawn_egg", + "id" : 447 + }, + { + "name" : "minecraft:zombie_villager_spawn_egg", + "id" : 477 + } +] \ No newline at end of file diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index 0a38d4f40..7a67fa9ff 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 0a38d4f40cd6dac182f4b8fa66b0c2befa299851 +Subproject commit 7a67fa9ff78496f4fc30b8f72d0eff451f1771e2 diff --git a/pom.xml b/pom.xml index 5b3e5a5f2..c03efb782 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.geysermc geyser-parent - 1.4.0-SNAPSHOT + 1.4.1-SNAPSHOT pom Geyser Allows for players from Minecraft Bedrock Edition to join Minecraft Java Edition servers.