diff --git a/README.md b/README.md index 07c23d70..7f9ba1cb 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,6 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set - Sounds - Block Particles - Block Entities ([`block-entities`](https://github.com/GeyserMC/Geyser/tree/block-entities)) -- Biome Colors - Some Entity Flags - Proper Movement - Support to be Ran as a Plugin ([`plugin`](https://github.com/GeyserMC/Geyser/tree/plugin)) diff --git a/connector/src/main/java/org/geysermc/connector/entity/Entity.java b/connector/src/main/java/org/geysermc/connector/entity/Entity.java index 43ce88c8..37c64db3 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/Entity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java @@ -156,6 +156,8 @@ public class Entity { } public void updateBedrockAttributes(GeyserSession session) { + if (!valid) return; + List attributes = new ArrayList<>(); for (Map.Entry entry : this.attributes.entrySet()) { if (!entry.getValue().getType().isBedrockAttribute()) @@ -182,7 +184,7 @@ public class Entity { metadata.getFlags().setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80); // metadata.getFlags().setFlag(EntityFlag.INVISIBLE, (xd & 0x20) == 0x20); if ((xd & 0x20) == 0x20) - metadata.put(EntityData.SCALE, 0.01f); + metadata.put(EntityData.SCALE, 0.0f); else metadata.put(EntityData.SCALE, scale); } @@ -193,7 +195,8 @@ public class Entity { metadata.put(EntityData.NAMETAG, MessageUtils.getBedrockMessage(name)); break; case 3: // is custom name visible - metadata.getFlags().setFlag(EntityFlag.ALWAYS_SHOW_NAME, (boolean) entityMetadata.getValue()); + if (!this.is(PlayerEntity.class)) + metadata.put(EntityData.ALWAYS_SHOW_NAMETAG, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0)); break; case 4: // silent metadata.getFlags().setFlag(EntityFlag.SILENT, (boolean) entityMetadata.getValue()); @@ -203,6 +206,12 @@ public class Entity { break; } + updateBedrockMetadata(session); + } + + public void updateBedrockMetadata(GeyserSession session) { + if (!valid) return; + SetEntityDataPacket entityDataPacket = new SetEntityDataPacket(); entityDataPacket.setRuntimeEntityId(geyserId); entityDataPacket.getMetadata().putAll(metadata); 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 50d097db..bbe72f99 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/LivingEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/LivingEntity.java @@ -27,6 +27,7 @@ package org.geysermc.connector.entity; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.ContainerId; import com.nukkitx.protocol.bedrock.data.EntityData; import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.packet.MobArmorEquipmentPacket; @@ -42,11 +43,12 @@ import org.geysermc.connector.network.session.GeyserSession; @Setter public class LivingEntity extends Entity { - protected ItemData helmet; - protected ItemData chestplate; - protected ItemData leggings; - protected ItemData boots; - protected ItemData hand = ItemData.of(0, (short) 0, 0); + protected ItemData helmet = ItemData.AIR; + protected ItemData chestplate = ItemData.AIR; + protected ItemData leggings = ItemData.AIR; + protected ItemData boots = ItemData.AIR; + protected ItemData hand = ItemData.AIR; + protected ItemData offHand = ItemData.AIR; public LivingEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); @@ -80,11 +82,22 @@ public class LivingEntity extends Entity { armorEquipmentPacket.setLeggings(leggings); armorEquipmentPacket.setBoots(boots); - MobEquipmentPacket mobEquipmentPacket = new MobEquipmentPacket(); - mobEquipmentPacket.setRuntimeEntityId(geyserId); - mobEquipmentPacket.setItem(hand); + MobEquipmentPacket handPacket = new MobEquipmentPacket(); + handPacket.setRuntimeEntityId(geyserId); + handPacket.setItem(hand); + handPacket.setHotbarSlot(-1); + handPacket.setInventorySlot(0); + handPacket.setContainerId(ContainerId.INVENTORY); + + MobEquipmentPacket offHandPacket = new MobEquipmentPacket(); + offHandPacket.setRuntimeEntityId(geyserId); + offHandPacket.setItem(offHand); + offHandPacket.setHotbarSlot(-1); + offHandPacket.setInventorySlot(0); + offHandPacket.setContainerId(ContainerId.OFFHAND); session.getUpstream().sendPacket(armorEquipmentPacket); - session.getUpstream().sendPacket(mobEquipmentPacket); + session.getUpstream().sendPacket(handPacket); + session.getUpstream().sendPacket(offHandPacket); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java index f373a354..9d8786e3 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java @@ -83,10 +83,13 @@ public class PlayerEntity extends LivingEntity { addPlayerPacket.setCustomFlags(0); addPlayerPacket.setDeviceId(""); addPlayerPacket.setPlatformChatId(""); - addPlayerPacket.getMetadata().putAll(getMetadata()); + addPlayerPacket.getMetadata().putAll(metadata); valid = true; session.getUpstream().sendPacket(addPlayerPacket); + + updateEquipment(session); + updateBedrockAttributes(session); } public void sendPlayer(GeyserSession session) { diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/ArmorStandEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/ArmorStandEntity.java index 3279b298..6dd77d73 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/ArmorStandEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/ArmorStandEntity.java @@ -43,7 +43,7 @@ public class ArmorStandEntity extends LivingEntity { public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { if (entityMetadata.getType() == MetadataType.BYTE) { byte xd = (byte) entityMetadata.getValue(); - if((xd & 0x01) == 0x01) { + if((xd & 0x01) == 0x01 && !(metadata.get(EntityData.SCALE).equals(0.0f))) { metadata.put(EntityData.SCALE, .55f); } } 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 3ddc3bd4..ab3b2c04 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 @@ -59,6 +59,7 @@ 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.Registry; +import org.geysermc.connector.network.translators.block.BlockTranslator; import org.geysermc.connector.utils.ChunkUtils; import org.geysermc.connector.utils.Toolbox; import org.geysermc.floodgate.util.BedrockData; @@ -148,9 +149,9 @@ public class GeyserSession implements CommandSender { ChunkUtils.sendEmptyChunks(this, playerEntity.getPosition().toInt(), 0, false); - BiomeDefinitionListPacket biomePacket = new BiomeDefinitionListPacket(); - biomePacket.setTag(CompoundTag.EMPTY); - upstream.sendPacket(biomePacket); + BiomeDefinitionListPacket biomeDefinitionListPacket = new BiomeDefinitionListPacket(); + biomeDefinitionListPacket.setTag(Toolbox.BIOMES); + upstream.sendPacket(biomeDefinitionListPacket); AvailableEntityIdentifiersPacket entityPacket = new AvailableEntityIdentifiersPacket(); entityPacket.setTag(CompoundTag.EMPTY); @@ -373,7 +374,7 @@ public class GeyserSession implements CommandSender { // startGamePacket.setCurrentTick(0); startGamePacket.setEnchantmentSeed(0); startGamePacket.setMultiplayerCorrelationId(""); - startGamePacket.setBlockPalette(Toolbox.BLOCKS); + startGamePacket.setBlockPalette(BlockTranslator.BLOCKS); startGamePacket.setItemEntries(Toolbox.ITEMS); startGamePacket.setVanillaVersion("*"); // startGamePacket.setMovementServerAuthoritative(true); 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 3550e8dc..5e94f3d9 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 @@ -33,7 +33,7 @@ import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket; import lombok.Getter; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.TranslatorsInit; -import org.geysermc.connector.network.translators.block.BlockEntry; +import org.geysermc.connector.network.translators.block.BlockTranslator; import org.geysermc.connector.world.chunk.ChunkPosition; import java.util.HashMap; @@ -69,20 +69,19 @@ public class ChunkCache { } } - public BlockEntry getBlockAt(Position position) { + public BlockState getBlockAt(Position position) { ChunkPosition chunkPosition = new ChunkPosition(position.getX() >> 4, position.getZ() >> 4); if (!chunks.containsKey(chunkPosition)) - return BlockEntry.AIR; + return BlockTranslator.AIR; Column column = chunks.get(chunkPosition); Chunk chunk = column.getChunks()[position.getY() >> 4]; Position blockPosition = chunkPosition.getChunkBlock(position.getX(), position.getY(), position.getZ()); if (chunk != null) { - BlockState blockState = chunk.get(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ()); - return TranslatorsInit.getBlockTranslator().getBlockEntry(blockState); + return chunk.get(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ()); } - return BlockEntry.AIR; + return BlockTranslator.AIR; } public void removeChunk(ChunkPosition position) { diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java index cba6b7b6..2834cb90 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java @@ -56,9 +56,13 @@ public class EntityCache { public void spawnEntity(Entity entity) { entity.moveAbsolute(entity.getPosition(), entity.getRotation().getX(), entity.getRotation().getY()); + cacheEntity(entity); + entity.spawnEntity(session); + } + + public void cacheEntity(Entity entity) { entityIdTranslations.put(entity.getEntityId(), entity.getGeyserId()); entities.put(entity.getGeyserId(), entity); - entity.spawnEntity(session); } public boolean removeEntity(Entity entity, boolean force) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/BiomeTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/BiomeTranslator.java new file mode 100644 index 00000000..12278841 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/BiomeTranslator.java @@ -0,0 +1,35 @@ +package org.geysermc.connector.network.translators; +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 byte[] toBedrockBiome(int[] biomeData) { + byte[] bedrockData = new byte[256]; + if(biomeData == null) { + return bedrockData; + } + + for (int z = 0; z < 16; z += 4) { + for (int x = 0; x < 16; x += 4) { + byte biomeId = biomeID(biomeData, x, z); + fillArray(z, x, bedrockData, biomeId); + fillArray(z + 1, x, bedrockData, biomeId); + fillArray(z + 2, x, bedrockData, biomeId); + fillArray(z + 3, x, bedrockData, biomeId); + } + } + return bedrockData; + } + + protected static void fillArray(int z, int x, byte[] legacyBiomeData, int biomeId) { + int offset = (z << 4) | x; + Arrays.fill(legacyBiomeData, offset, offset + 4, (byte) biomeId); + } + + protected static byte biomeID(int[] biomeData, int x, int z) { + return (byte) biomeData[((z >> 2) & 3) << 2 | ((x >> 2) & 3)]; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java index bc14ba5d..2abeebb8 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java @@ -27,7 +27,10 @@ package org.geysermc.connector.network.translators; import com.github.steveice10.mc.protocol.packet.ingame.server.*; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.*; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.*; +import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerActionAckPacket; +import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerHealthPacket; +import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerPositionRotationPacket; +import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerSetExperiencePacket; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.*; import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerDisplayScoreboardPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerScoreboardObjectivePacket; @@ -70,9 +73,6 @@ public class TranslatorsInit { @Getter private static ItemTranslator itemTranslator; - @Getter - private static BlockTranslator blockTranslator; - @Getter private static InventoryTranslator inventoryTranslator = new GenericInventoryTranslator(); @@ -161,7 +161,7 @@ public class TranslatorsInit { Registry.registerBedrock(ShowCreditsPacket.class, new BedrockShowCreditsTranslator()); itemTranslator = new ItemTranslator(); - blockTranslator = new BlockTranslator(); + BlockTranslator.init(); registerInventoryTranslators(); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java index 56e573c6..e5bec698 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java @@ -56,6 +56,14 @@ public class BedrockActionTranslator extends PacketTranslator javaIdentifierMap = new HashMap<>(); + public static final ListTag BLOCKS; + public static final BlockState AIR = new BlockState(0); + public static final int BEDROCK_WATER_ID; - public BlockEntry getBlockEntry(BlockState state) { - return Toolbox.BLOCK_ENTRIES.get(state.getId()); + private static final Int2IntMap JAVA_TO_BEDROCK_BLOCK_MAP = new Int2IntOpenHashMap(); + private static final Int2ObjectMap BEDROCK_TO_JAVA_BLOCK_MAP = new Int2ObjectOpenHashMap<>(); + private static final IntSet WATERLOGGED = new IntOpenHashSet(); + + private static final int BLOCK_STATE_VERSION = 17760256; + + static { + /* Load block palette */ + InputStream stream = Toolbox.getResource("bedrock/runtime_block_states.dat"); + + ListTag blocksTag; + try (NBTInputStream nbtInputStream = NbtUtils.createNetworkReader(stream)) { + blocksTag = (ListTag) nbtInputStream.readTag(); + } catch (Exception e) { + throw new AssertionError("Unable to get blocks from runtime block states", e); + } + + Map blockStateMap = new HashMap<>(); + + for (CompoundTag tag : blocksTag.getValue()) { + if (blockStateMap.putIfAbsent(tag.getAsCompound("block"), tag) != null) { + throw new AssertionError("Duplicate block states in Bedrock palette"); + } + } + + stream = Toolbox.getResource("mappings/blocks.json"); + JsonNode blocks; + try { + blocks = Toolbox.JSON_MAPPER.readTree(stream); + } catch (Exception e) { + throw new AssertionError("Unable to load Java block mappings", e); + } + TObjectIntMap addedStatesMap = new TObjectIntHashMap<>(512, 0.5f, -1); + List paletteList = new ArrayList<>(); + + int waterRuntimeId = -1; + int javaRuntimeId = -1; + int bedrockRuntimeId = 0; + Iterator> blocksIterator = blocks.fields(); + while (blocksIterator.hasNext()) { + javaRuntimeId++; + Map.Entry entry = blocksIterator.next(); + String javaId = entry.getKey(); + CompoundTag blockTag = buildBedrockState(entry.getValue()); + + if ("minecraft:water[level=0]".equals(javaId)) { + waterRuntimeId = bedrockRuntimeId; + } + boolean waterlogged = entry.getValue().has("waterlogged") && entry.getValue().get("waterlogged").booleanValue(); + + if (waterlogged) { + BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId | 1 << 31, new BlockState(javaRuntimeId)); + WATERLOGGED.add(javaRuntimeId); + } else { + BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId, new BlockState(javaRuntimeId)); + } + + CompoundTag runtimeTag = blockStateMap.remove(blockTag); + if (runtimeTag != null) { + addedStatesMap.put(blockTag, bedrockRuntimeId); + paletteList.add(runtimeTag); + } else { + int duplicateRuntimeId = addedStatesMap.get(blockTag); + if (duplicateRuntimeId == -1) { + GeyserConnector.getInstance().getLogger().debug("Mapping " + javaId + " was not found for bedrock edition!"); + } else { + JAVA_TO_BEDROCK_BLOCK_MAP.put(javaRuntimeId, duplicateRuntimeId); + } + continue; + } + JAVA_TO_BEDROCK_BLOCK_MAP.put(javaRuntimeId, bedrockRuntimeId); + + bedrockRuntimeId++; + } + + if (waterRuntimeId == -1) { + throw new AssertionError("Unable to find water in palette"); + } + BEDROCK_WATER_ID = waterRuntimeId; + + paletteList.addAll(blockStateMap.values()); // Add any missing mappings that could crash the client + + BLOCKS = new ListTag<>("", CompoundTag.class, paletteList); } - public BlockEntry getBlockEntry(String javaIdentifier) { - return javaIdentifierMap.computeIfAbsent(javaIdentifier, key -> Toolbox.BLOCK_ENTRIES.values() - .stream().filter(blockEntry -> blockEntry.getJavaIdentifier().equals(key)).findFirst().orElse(null)); + private BlockTranslator() { + } + + public static void init() { + // no-op + } + + private static CompoundTag buildBedrockState(JsonNode node) { + CompoundTagBuilder tagBuilder = CompoundTag.builder(); + tagBuilder.stringTag("name", node.get("bedrock_identifier").textValue()) + .intTag("version", BlockTranslator.BLOCK_STATE_VERSION); + + CompoundTagBuilder statesBuilder = CompoundTag.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.booleanTag(stateEntry.getKey(), stateValue.booleanValue()); + continue; + case STRING: + statesBuilder.stringTag(stateEntry.getKey(), stateValue.textValue()); + continue; + case NUMBER: + statesBuilder.intTag(stateEntry.getKey(), stateValue.intValue()); + } + } + } + return tagBuilder.tag(statesBuilder.build("states")).build("block"); + } + + public static int getBedrockBlockId(BlockState state) { + return JAVA_TO_BEDROCK_BLOCK_MAP.get(state.getId()); + } + + public static BlockState getJavaBlockState(int bedrockId) { + return BEDROCK_TO_JAVA_BLOCK_MAP.get(bedrockId); + } + + public static boolean isWaterlogged(BlockState state) { + return WATERLOGGED.contains(state.getId()); + } + + public static BlockState getJavaWaterloggedState(int bedrockId) { + return BEDROCK_TO_JAVA_BLOCK_MAP.get(1 << 31 | bedrockId); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityEquipmentTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityEquipmentTranslator.java index 1262664d..5efe8e4e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityEquipmentTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityEquipmentTranslator.java @@ -70,7 +70,7 @@ public class JavaEntityEquipmentTranslator extends PacketTranslator ITEMS = new ArrayList<>(); - public static ListTag BLOCKS; public static final Int2ObjectMap ITEM_ENTRIES = new Int2ObjectOpenHashMap<>(); - public static final Int2ObjectMap BLOCK_ENTRIES = new Int2ObjectOpenHashMap<>(); - public static void init() { - InputStream stream = GeyserConnector.class.getClassLoader().getResourceAsStream("bedrock/runtime_block_states.dat"); - if (stream == null) { - throw new AssertionError("Unable to find bedrock/runtime_block_states.dat"); + static { + /* Load biomes */ + InputStream biomestream = GeyserConnector.class.getClassLoader().getResourceAsStream("bedrock/biome_definitions.dat"); + if (biomestream == null) { + throw new AssertionError("Unable to find bedrock/biome_definitions.dat"); } - ListTag blocksTag; + CompoundTag biomesTag; - NBTInputStream nbtInputStream = NbtUtils.createNetworkReader(stream); - try { - blocksTag = (ListTag) nbtInputStream.readTag(); - nbtInputStream.close(); + try (NBTInputStream biomenbtInputStream = NbtUtils.createNetworkReader(biomestream)){ + biomesTag = (CompoundTag) biomenbtInputStream.readTag(); + BIOMES = biomesTag; } catch (Exception ex) { - GeyserConnector.getInstance().getLogger().warning("Failed to get blocks from runtime block states, please report this error!"); + GeyserConnector.getInstance().getLogger().warning("Failed to get biomes from biome definitions, is there something wrong with the file?"); throw new AssertionError(ex); } - BLOCKS = blocksTag; - InputStream stream2 = Toolbox.class.getClassLoader().getResourceAsStream("bedrock/items.json"); - if (stream2 == null) { - throw new AssertionError("Items Table not found"); - } + /* Load item palette */ + InputStream stream = getResource("bedrock/items.json"); - ObjectMapper startGameItemMapper = new ObjectMapper(); - List startGameItems = new ArrayList<>(); + TypeReference> itemEntriesType = new TypeReference>() { + }; + + List itemEntries; try { - startGameItems = startGameItemMapper.readValue(stream2, ArrayList.class); + itemEntries = JSON_MAPPER.readValue(stream, itemEntriesType); } catch (Exception e) { - e.printStackTrace(); + throw new AssertionError("Unable to load Bedrock runtime item IDs", e); } - for (Map entry : startGameItems) { - ITEMS.add(new StartGamePacket.ItemEntry((String) entry.get("name"), (short) ((int) entry.get("id")))); + for (JsonNode entry : itemEntries) { + ITEMS.add(new StartGamePacket.ItemEntry(entry.get("name").textValue(), (short) entry.get("id").intValue())); } - InputStream itemStream = Toolbox.class.getClassLoader().getResourceAsStream("mappings/items.json"); - ObjectMapper itemMapper = new ObjectMapper(); - Map> items = new HashMap<>(); + stream = getResource("mappings/items.json"); + JsonNode items; try { - items = itemMapper.readValue(itemStream, LinkedHashMap.class); - } catch (Exception ex) { - ex.printStackTrace(); + items = JSON_MAPPER.readTree(stream); + } catch (Exception e) { + throw new AssertionError("Unable to load Java runtime item IDs", e); } int itemIndex = 0; - for (Map.Entry> itemEntry : items.entrySet()) { - ITEM_ENTRIES.put(itemIndex, new ItemEntry(itemEntry.getKey(), itemIndex, (int) itemEntry.getValue().get("bedrock_id"), (int) itemEntry.getValue().get("bedrock_data"))); + Iterator> iterator = items.fields(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + ITEM_ENTRIES.put(itemIndex, new ItemEntry(entry.getKey(), itemIndex, + entry.getValue().get("bedrock_id").intValue(), entry.getValue().get("bedrock_data").intValue())); itemIndex++; } + } - InputStream blockStream = Toolbox.class.getClassLoader().getResourceAsStream("mappings/blocks.json"); - ObjectMapper blockMapper = new ObjectMapper(); - Map> blocks = new HashMap<>(); - - try { - blocks = blockMapper.readValue(blockStream, LinkedHashMap.class); - } catch (Exception ex) { - ex.printStackTrace(); + public static InputStream getResource(String resource) { + InputStream stream = Toolbox.class.getClassLoader().getResourceAsStream(resource); + if (stream == null) { + throw new AssertionError("Unable to find resource: " + resource); } + return stream; + } - int javaIndex = -1; - javaLoop: - for (Map.Entry> javaEntry : blocks.entrySet()) { - javaIndex++; - String wantedIdentifier = (String) javaEntry.getValue().get("bedrock_identifier"); - Map wantedStates = (Map) javaEntry.getValue().get("bedrock_states"); - - int bedrockIndex = -1; - bedrockLoop: - for (CompoundTag bedrockEntry : BLOCKS.getValue()) { - bedrockIndex++; - CompoundTag blockTag = bedrockEntry.getAsCompound("block"); - if (blockTag.getAsString("name").equals(wantedIdentifier)) { - if (wantedStates != null) { - Map> bedrockStates = blockTag.getAsCompound("states").getValue(); - for (Map.Entry stateEntry : wantedStates.entrySet()) { - Tag bedrockStateTag = bedrockStates.get(stateEntry.getKey()); - if (bedrockStateTag == null) - continue bedrockLoop; - Object bedrockStateValue = bedrockStateTag.getValue(); - if (bedrockStateValue instanceof Byte) - bedrockStateValue = ((Byte) bedrockStateValue) != 0; - if (!stateEntry.getValue().equals(bedrockStateValue)) - continue bedrockLoop; - } - } - BlockEntry blockEntry = new BlockEntry(javaEntry.getKey(), javaIndex, bedrockIndex); - BLOCK_ENTRIES.put(javaIndex, blockEntry); - continue javaLoop; - } - } - GeyserConnector.getInstance().getLogger().debug("Mapping " + javaEntry.getKey() + " was not found for bedrock edition!"); - } + public static void init() { + // no-op } } \ No newline at end of file diff --git a/connector/src/main/resources/bedrock/biome_definitions.dat b/connector/src/main/resources/bedrock/biome_definitions.dat index 015a2650..b8c6df4a 100644 Binary files a/connector/src/main/resources/bedrock/biome_definitions.dat and b/connector/src/main/resources/bedrock/biome_definitions.dat differ diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index 1ad8a194..278c7344 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 1ad8a19417391710d34d72214e3aa430f84740cd +Subproject commit 278c73449aeeb4064c7513a68f98a49a5f463f0a