From 1c0014c67b2bbf669c557e64f7cde40936c71e32 Mon Sep 17 00:00:00 2001 From: Mirco Kroon <23699979+mircokroon@users.noreply.github.com> Date: Sat, 29 May 2021 17:52:46 +0200 Subject: [PATCH 01/11] Rename packets to official mapping names --- src/main/java/game/data/chunk/Chunk.java | 2 +- .../game/data/chunk/version/Chunk_1_14.java | 2 +- .../java/packets/builder/PacketBuilder.java | 2 +- .../handler/ClientBoundGamePacketHandler.java | 42 +-- .../handler/ServerBoundGamePacketHandler.java | 12 +- .../ClientBoundGamePacketHandler_1_14.java | 6 +- .../ClientBoundGamePacketHandler_1_15.java | 4 +- .../ClientBoundGamePacketHandler_1_16.java | 8 +- src/main/resources/protocol-versions.json | 248 +++++++++--------- 9 files changed, 163 insertions(+), 163 deletions(-) diff --git a/src/main/java/game/data/chunk/Chunk.java b/src/main/java/game/data/chunk/Chunk.java index fcf22eff..51fe26dc 100644 --- a/src/main/java/game/data/chunk/Chunk.java +++ b/src/main/java/game/data/chunk/Chunk.java @@ -309,7 +309,7 @@ public BlockState getBlockStateAt(int x, int y, int z) { public PacketBuilder toPacket() { Protocol p = Config.versionReporter().getProtocol(); PacketBuilder packet = new PacketBuilder(); - packet.writeVarInt(p.clientBound("chunk_data")); + packet.writeVarInt(p.clientBound("LevelChunk")); packet.writeInt(location.getX()); packet.writeInt(location.getZ()); diff --git a/src/main/java/game/data/chunk/version/Chunk_1_14.java b/src/main/java/game/data/chunk/version/Chunk_1_14.java index 8d804bcf..f8941abc 100644 --- a/src/main/java/game/data/chunk/version/Chunk_1_14.java +++ b/src/main/java/game/data/chunk/version/Chunk_1_14.java @@ -148,7 +148,7 @@ private void parseLightArray(int mask, int emptyMask, DataTypeProvider provider, protected PacketBuilder buildLightPacket() { Protocol p = Config.versionReporter().getProtocol(); PacketBuilder packet = new PacketBuilder(); - packet.writeVarInt(p.clientBound("chunk_update_light")); + packet.writeVarInt(p.clientBound("LightUpdate")); packet.writeVarInt(location.getX()); packet.writeVarInt(location.getZ()); diff --git a/src/main/java/packets/builder/PacketBuilder.java b/src/main/java/packets/builder/PacketBuilder.java index 27d66aef..8bd62e52 100644 --- a/src/main/java/packets/builder/PacketBuilder.java +++ b/src/main/java/packets/builder/PacketBuilder.java @@ -47,7 +47,7 @@ public static PacketBuilder constructClientMessage(String message, MessageTarget */ public static PacketBuilder constructClientMessage(Chat message, MessageTarget target) { Protocol protocol = Config.versionReporter().getProtocol(); - PacketBuilder builder = new PacketBuilder(protocol.clientBound("message")); + PacketBuilder builder = new PacketBuilder(protocol.clientBound("Chat")); builder.writeString(message.toJson()); builder.writeByte(target.getIdentifier()); diff --git a/src/main/java/packets/handler/ClientBoundGamePacketHandler.java b/src/main/java/packets/handler/ClientBoundGamePacketHandler.java index 4926363c..83ffb765 100644 --- a/src/main/java/packets/handler/ClientBoundGamePacketHandler.java +++ b/src/main/java/packets/handler/ClientBoundGamePacketHandler.java @@ -28,55 +28,55 @@ public ClientBoundGamePacketHandler(ConnectionManager connectionManager) { WorldManager worldManager = WorldManager.getInstance(); EntityRegistry entityRegistry = WorldManager.getInstance().getEntityRegistry(); - operations.put("entity_data", provider -> { + operations.put("SetEntityData", provider -> { entityRegistry.addMetadata(provider); return true; }); - operations.put("entity_equipment", provider -> { + operations.put("SetEquipment", provider -> { entityRegistry.addEquipment(provider); return true; }); - operations.put("spawn_mob", provider -> { + operations.put("AddMob", provider -> { entityRegistry.addEntity(provider, MobEntity::parse); return true; }); - operations.put("spawn_object", provider -> { + operations.put("AddEntity", provider -> { entityRegistry.addEntity(provider, ObjectEntity::parse); return true; }); - operations.put("spawn_player", provider -> { + operations.put("AddPlayer", provider -> { entityRegistry.addPlayer(provider); return true; }); - operations.put("destroy_entities", provider -> { + operations.put("RemoveEntities", provider -> { entityRegistry.destroyEntities(provider); return true; }); - operations.put("entity_position", provider -> { + operations.put("MoveEntityPos", provider -> { entityRegistry.updatePositionRelative(provider); return true; }); - operations.put("entity_position_rotation", provider -> { + operations.put("MoveEntityPosRot", provider -> { entityRegistry.updatePositionRelative(provider); return true; }); - operations.put("entity_teleport", provider -> { + operations.put("TeleportEntity", provider -> { entityRegistry.updatePositionAbsolute(provider); return true; }); - operations.put("map_data", provider -> { + operations.put("MapItemData", provider -> { worldManager.getMapRegistry().readMap(provider); return true; }); - operations.put("join_game", provider -> { + operations.put("Login", provider -> { provider.readInt(); provider.readNext(); int dimensionEnum = provider.readInt(); @@ -86,14 +86,14 @@ public ClientBoundGamePacketHandler(ConnectionManager connectionManager) { return true; }); - operations.put("respawn", provider -> { + operations.put("Respawn", provider -> { int dimensionEnum = provider.readInt(); worldManager.setDimension(Dimension.fromId(dimensionEnum)); worldManager.getEntityRegistry().reset(); return true; }); - operations.put("chunk_data", provider -> { + operations.put("LevelChunk", provider -> { try { worldManager.getChunkFactory().addChunk(provider); } catch (Exception ex) { @@ -102,17 +102,17 @@ public ClientBoundGamePacketHandler(ConnectionManager connectionManager) { return true; }); - operations.put("chunk_update_light", provider -> { + operations.put("LightUpdate", provider -> { worldManager.updateLight(provider); return true; }); - operations.put("chunk_block_change", provider -> { + operations.put("BlockUpdate", provider -> { WorldManager.getInstance().blockChange(provider); return true; }); - operations.put("chunk_multi_block_change", provider -> { + operations.put("SectionBlocksUpdate", provider -> { int x = provider.readInt(); int z = provider.readInt(); worldManager.multiBlockChange(new Coordinate3D(x, 0, z), provider); @@ -120,13 +120,13 @@ public ClientBoundGamePacketHandler(ConnectionManager connectionManager) { return true; }); - operations.put("chunk_unload", provider -> { + operations.put("ForgetLevelChunk", provider -> { CoordinateDim2D co = new CoordinateDim2D(provider.readInt(), provider.readInt(), WorldManager.getInstance().getDimension()); worldManager.unloadChunk(co); return Config.getExtendedRenderDistance() == 0; }); - operations.put("update_block_entity", provider -> { + operations.put("BlockEntityData", provider -> { Coordinate3D position = provider.readCoordinates(); byte action = provider.readNext(); SpecificTag entityData = provider.readNbtTag(); @@ -135,7 +135,7 @@ public ClientBoundGamePacketHandler(ConnectionManager connectionManager) { return true; }); - operations.put("open_window", provider -> { + operations.put("OpenScreen", provider -> { int windowId = provider.readNext(); String windowType = provider.readString(); String windowTitle = provider.readChat(); @@ -146,12 +146,12 @@ public ClientBoundGamePacketHandler(ConnectionManager connectionManager) { return true; }); - operations.put("close_window", provider -> { + operations.put("ContainerClose", provider -> { worldManager.getContainerManager().closeWindow(provider.readNext()); return true; }); - operations.put("window_items", provider -> { + operations.put("ContainerSetContent", provider -> { int windowId = provider.readNext(); worldManager.getContainerManager().items(windowId, provider); diff --git a/src/main/java/packets/handler/ServerBoundGamePacketHandler.java b/src/main/java/packets/handler/ServerBoundGamePacketHandler.java index 91de99cf..d1a1effe 100644 --- a/src/main/java/packets/handler/ServerBoundGamePacketHandler.java +++ b/src/main/java/packets/handler/ServerBoundGamePacketHandler.java @@ -30,16 +30,16 @@ public ServerBoundGamePacketHandler(ConnectionManager connectionManager) { return true; }; - operations.put("player_position", updatePlayerPosition); - operations.put("player_look", updatePlayerRotation); - operations.put("player_position_look", (provider) -> { + operations.put("MovePlayerPos", updatePlayerPosition); + operations.put("MovePlayerRot", updatePlayerRotation); + operations.put("MovePlayerPosRot", (provider) -> { updatePlayerPosition.apply(provider); updatePlayerRotation.apply(provider); return true; }); - operations.put("player_vehicle_move", updatePlayerPosition); + operations.put("MoveVehicle", updatePlayerPosition); - operations.put("right_click", provider -> { + operations.put("UseItem", provider -> { // newer versions first include a VarInt with the hand if (Config.versionReporter().isAtLeast1_14()) { provider.readVarInt(); @@ -49,7 +49,7 @@ public ServerBoundGamePacketHandler(ConnectionManager connectionManager) { return true; }); - operations.put("close_window", provider -> { + operations.put("ContainerClose", provider -> { WorldManager.getInstance().getContainerManager().closeWindow(provider.readNext()); return true; }); diff --git a/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_14.java b/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_14.java index 02b3d354..cce5cc47 100644 --- a/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_14.java +++ b/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_14.java @@ -21,8 +21,8 @@ public ClientBoundGamePacketHandler_1_14(ConnectionManager connectionManager) { Protocol protocol = Config.versionReporter().getProtocol(); Map operators = getOperators(); - operators.put("join_game", provider -> { - PacketBuilder replacement = new PacketBuilder(protocol.clientBound("join_game")); + operators.put("Login", provider -> { + PacketBuilder replacement = new PacketBuilder(protocol.clientBound("Login")); replacement.copy(provider, INT, BYTE); // current dimension @@ -43,7 +43,7 @@ public ClientBoundGamePacketHandler_1_14(ConnectionManager connectionManager) { return false; }); - operators.put("open_window", provider -> { + operators.put("OpenScreen", provider -> { int windowId = provider.readNext(); int windowType = provider.readVarInt(); diff --git a/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_15.java b/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_15.java index 29a50a76..27d57243 100644 --- a/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_15.java +++ b/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_15.java @@ -20,8 +20,8 @@ public ClientBoundGamePacketHandler_1_15(ConnectionManager connectionManager) { Protocol protocol = Config.versionReporter().getProtocol(); Map operators = getOperators(); - operators.put("join_game", provider -> { - PacketBuilder replacement = new PacketBuilder(protocol.clientBound("join_game")); + operators.put("Login", provider -> { + PacketBuilder replacement = new PacketBuilder(protocol.clientBound("Login")); replacement.copy(provider, INT, BYTE); // current dimension diff --git a/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_16.java b/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_16.java index b9540d12..94b4d36b 100644 --- a/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_16.java +++ b/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_16.java @@ -23,8 +23,8 @@ public ClientBoundGamePacketHandler_1_16(ConnectionManager connectionManager) { Protocol protocol = Config.versionReporter().getProtocol(); Map operators = getOperators(); - operators.put("join_game", provider -> { - PacketBuilder replacement = new PacketBuilder(protocol.clientBound("join_game")); + operators.put("Login", provider -> { + PacketBuilder replacement = new PacketBuilder(protocol.clientBound("Login")); replacement.copy(provider, INT, BOOL, BYTE, BYTE); @@ -62,7 +62,7 @@ public ClientBoundGamePacketHandler_1_16(ConnectionManager connectionManager) { return false; }); - operators.put("respawn", provider -> { + operators.put("Respawn", provider -> { SpecificTag dimensionNbt = provider.readNbtTag(); Dimension dimension = Dimension.fromString(provider.readString()); dimension.registerType(dimensionNbt); @@ -72,7 +72,7 @@ public ClientBoundGamePacketHandler_1_16(ConnectionManager connectionManager) { return true; }); - operators.put("chunk_multi_block_change", provider -> { + operators.put("SectionBlocksUpdate", provider -> { Coordinate3D pos = provider.readSectionCoordinates(); WorldManager.getInstance().multiBlockChange(pos, provider); diff --git a/src/main/resources/protocol-versions.json b/src/main/resources/protocol-versions.json index 8ab45166..67f3c3f4 100644 --- a/src/main/resources/protocol-versions.json +++ b/src/main/resources/protocol-versions.json @@ -4,171 +4,171 @@ "version": "1.12.2", "dataVersion": 1343, "clientBound": { - "0x20": "chunk_data", - "0x0B": "chunk_block_change", - "0x10": "chunk_multi_block_change", - "0x1D": "chunk_unload", - "0x09": "update_block_entity", - "0x23": "join_game", - "0x35": "respawn", - "0x13": "open_window", - "0x12": "close_window", - "0x14": "window_items", - "0x24": "map_data", - "0x0F": "message", + "0x20": "LevelChunk", + "0x0B": "BlockUpdate", + "0x10": "SectionBlocksUpdate", + "0x1D": "ForgetLevelChunk", + "0x09": "BlockEntityData", + "0x23": "Login", + "0x35": "Respawn", + "0x13": "OpenScreen", + "0x12": "ContainerClose", + "0x14": "ContainerSetContent", + "0x24": "MapItemData", + "0x0F": "Chat", - "0x00": "spawn_object", - "0x03": "spawn_mob", - "0x05": "spawn_player", - "0x3C": "entity_data", - "0x3F": "entity_equipment", - "0x26": "entity_position", - "0x4C": "entity_teleport", - "0x32": "destroy_entities" + "0x00": "AddEntity", + "0x03": "AddMob", + "0x05": "AddPlayer", + "0x3C": "SetEntityData", + "0x3F": "SetEquipment", + "0x26": "MoveEntityPos", + "0x4C": "TeleportEntity", + "0x32": "RemoveEntities" }, "serverBound": { - "0x0D": "player_position", - "0x0E": "player_position_look", - "0x0F": "player_look", + "0x0D": "MovePlayerPos", + "0x0E": "MovePlayerPosRot", + "0x0F": "MovePlayerRot", "0x10": "vehicle_move", - "0x1F": "right_click", - "0x08": "close_window" + "0x1F": "UseItem", + "0x08": "ContainerClose" } }, "404": { "version": "1.13.2", "dataVersion": 1631, "clientBound": { - "0x22": "chunk_data", - "0x0B": "chunk_block_change", - "0x0F": "chunk_multi_block_change", - "0x1F": "chunk_unload", - "0x09": "update_block_entity", - "0x25": "join_game", - "0x38": "respawn", - "0x03": "spawn_mob", - "0x00": "spawn_object", - "0x3F": "entity_data", - "0x0E": "message" + "0x22": "LevelChunk", + "0x0B": "BlockUpdate", + "0x0F": "SectionBlocksUpdate", + "0x1F": "ForgetLevelChunk", + "0x09": "BlockEntityData", + "0x25": "Login", + "0x38": "Respawn", + "0x03": "AddMob", + "0x00": "AddEntity", + "0x3F": "SetEntityData", + "0x0E": "Chat" }, "serverBound": { - "0x10": "player_position", - "0x11": "player_position_look", - "0x12": "player_look", + "0x10": "MovePlayerPos", + "0x11": "MovePlayerPosRot", + "0x12": "MovePlayerRot", "0x13": "vehicle_move", - "0x29": "right_click" + "0x29": "UseItem" } }, "498": { "version": "1.14.4", "dataVersion": 1976, "clientBound": { - "0x21": "chunk_data", - "0x0B": "chunk_block_change", - "0x0F": "chunk_multi_block_change", - "0x1D": "chunk_unload", - "0x24": "chunk_update_light", - "0x09": "update_block_entity", - "0x25": "join_game", - "0x3A": "respawn", - "0x2E": "open_window", - "0x13": "close_window", - "0x14": "window_items", - "0x27": "map_data", - "0x0E": "message", + "0x21": "LevelChunk", + "0x0B": "BlockUpdate", + "0x0F": "SectionBlocksUpdate", + "0x1D": "ForgetLevelChunk", + "0x24": "LightUpdate", + "0x09": "BlockEntityData", + "0x25": "Login", + "0x3A": "Respawn", + "0x2E": "OpenScreen", + "0x13": "ContainerClose", + "0x14": "ContainerSetContent", + "0x27": "MapItemData", + "0x0E": "Chat", - "0x00": "spawn_object", - "0x03": "spawn_mob", - "0x05": "spawn_player", - "0x43": "entity_data", - "0x46": "entity_equipment", - "0x28": "entity_position", - "0x29": "entity_position_rotation", - "0x56": "entity_teleport", - "0x37": "destroy_entities" + "0x00": "AddEntity", + "0x03": "AddMob", + "0x05": "AddPlayer", + "0x43": "SetEntityData", + "0x46": "SetEquipment", + "0x28": "MoveEntityPos", + "0x29": "MoveEntityPosRot", + "0x56": "TeleportEntity", + "0x37": "RemoveEntities" }, "serverBound": { - "0x11": "player_position", - "0x12": "player_position_look", - "0x13": "player_look", - "0x15": "player_vehicle_move", - "0x2C": "right_click", - "0x0A": "close_window" + "0x11": "MovePlayerPos", + "0x12": "MovePlayerPosRot", + "0x13": "MovePlayerRot", + "0x15": "MoveVehicle", + "0x2C": "UseItem", + "0x0A": "ContainerClose" } }, "578": { "version": "1.15.2", "dataVersion": 2225, "clientBound": { - "0x22": "chunk_data", - "0x0C": "chunk_block_change", - "0x10": "chunk_multi_block_change", - "0x1E": "chunk_unload", - "0x25": "chunk_update_light", - "0x0A": "update_block_entity", - "0x26": "join_game", - "0x3B": "respawn", - "0x2F": "open_window", - "0x14": "close_window", - "0x15": "window_items", - "0x27": "map_data", - "0x0F": "message", + "0x22": "LevelChunk", + "0x0C": "BlockUpdate", + "0x10": "SectionBlocksUpdate", + "0x1E": "ForgetLevelChunk", + "0x25": "LightUpdate", + "0x0A": "BlockEntityData", + "0x26": "Login", + "0x3B": "Respawn", + "0x2F": "OpenScreen", + "0x14": "ContainerClose", + "0x15": "ContainerSetContent", + "0x27": "MapItemData", + "0x0F": "Chat", - "0x00": "spawn_object", - "0x03": "spawn_mob", - "0x05": "spawn_player", - "0x44": "entity_data", - "0x47": "entity_equipment", - "0x29": "entity_position", - "0x2A": "entity_position_rotation", - "0x57": "entity_teleport", - "0x38": "destroy_entities" + "0x00": "AddEntity", + "0x03": "AddMob", + "0x05": "AddPlayer", + "0x44": "SetEntityData", + "0x47": "SetEquipment", + "0x29": "MoveEntityPos", + "0x2A": "MoveEntityPosRot", + "0x57": "TeleportEntity", + "0x38": "RemoveEntities" }, "serverBound": { - "0x11": "player_position", - "0x12": "player_position_look", - "0x13": "player_look", - "0x15": "player_vehicle_move", - "0x2C": "right_click", - "0x0A": "close_window" + "0x11": "MovePlayerPos", + "0x12": "MovePlayerPosRot", + "0x13": "MovePlayerRot", + "0x15": "MoveVehicle", + "0x2C": "UseItem", + "0x0A": "ContainerClose" } }, "754": { "version": "1.16.2", "dataVersion": 2578, "clientBound": { - "0x20": "chunk_data", - "0x0B": "chunk_block_change", - "0x3B": "chunk_multi_block_change", - "0x1C": "chunk_unload", - "0x23": "chunk_update_light", - "0x09": "update_block_entity", - "0x24": "join_game", - "0x39": "respawn", - "0x2D": "open_window", - "0x12": "close_window", - "0x13": "window_items", - "0x25": "map_data", - "0x0E": "message", + "0x20": "LevelChunk", + "0x0B": "BlockUpdate", + "0x3B": "SectionBlocksUpdate", + "0x1C": "ForgetLevelChunk", + "0x23": "LightUpdate", + "0x09": "BlockEntityData", + "0x24": "Login", + "0x39": "Respawn", + "0x2D": "OpenScreen", + "0x12": "ContainerClose", + "0x13": "ContainerSetContent", + "0x25": "MapItemData", + "0x0E": "Chat", - "0x00": "spawn_object", - "0x02": "spawn_mob", - "0x04": "spawn_player", - "0x44": "entity_data", - "0x47": "entity_equipment", - "0x27": "entity_position", - "0x28": "entity_position_rotation", - "0x56": "entity_teleport", - "0x36": "destroy_entities" + "0x00": "AddEntity", + "0x02": "AddMob", + "0x04": "AddPlayer", + "0x44": "SetEntityData", + "0x47": "SetEquipment", + "0x27": "MoveEntityPos", + "0x28": "MoveEntityPosRot", + "0x56": "TeleportEntity", + "0x36": "RemoveEntities" }, "serverBound": { - "0x12": "player_position", - "0x13": "player_position_look", - "0x14": "player_look", - "0x16": "player_vehicle_move", - "0x2E": "right_click", - "0x0A": "close_window" + "0x12": "MovePlayerPos", + "0x13": "MovePlayerPosRot", + "0x14": "MovePlayerRot", + "0x16": "MoveVehicle", + "0x2E": "UseItem", + "0x0A": "ContainerClose" } } From 189f480e81a3491d7cf5b0315195ba12b78680d0 Mon Sep 17 00:00:00 2001 From: Mirco Kroon <23699979+mircokroon@users.noreply.github.com> Date: Mon, 7 Jun 2021 21:07:59 +0200 Subject: [PATCH 02/11] Added support for 1.17 Mostly --- src/main/java/config/Config.java | 3 +- src/main/java/config/Version.java | 23 +- src/main/java/config/VersionReporter.java | 51 +- src/main/java/game/data/WorldManager.java | 1 + src/main/java/game/data/chunk/Chunk.java | 29 +- .../java/game/data/chunk/ChunkFactory.java | 16 +- .../data/chunk/version/ChunkSection_1_12.java | 9 +- .../data/chunk/version/ChunkSection_1_13.java | 4 +- .../data/chunk/version/ChunkSection_1_14.java | 12 +- .../data/chunk/version/ChunkSection_1_15.java | 11 +- .../data/chunk/version/ChunkSection_1_16.java | 12 +- .../data/chunk/version/ChunkSection_1_17.java | 21 + .../game/data/chunk/version/Chunk_1_12.java | 9 +- .../game/data/chunk/version/Chunk_1_13.java | 8 +- .../game/data/chunk/version/Chunk_1_14.java | 9 +- .../game/data/chunk/version/Chunk_1_15.java | 9 +- .../game/data/chunk/version/Chunk_1_16.java | 9 +- .../game/data/chunk/version/Chunk_1_17.java | 82 +++ .../java/game/data/dimension/Dimension.java | 7 +- .../game/data/registries/RegistryLoader.java | 60 +- .../registries/VersionManifestHandler.java | 68 ++ src/main/java/packets/DataTypeProvider.java | 7 + .../java/packets/builder/PacketBuilder.java | 8 + src/main/resources/block-colors.json | 641 ++++++++++-------- src/main/resources/protocol-versions.json | 35 + src/main/resources/server.json | 19 - 26 files changed, 759 insertions(+), 404 deletions(-) create mode 100644 src/main/java/game/data/chunk/version/ChunkSection_1_17.java create mode 100644 src/main/java/game/data/chunk/version/Chunk_1_17.java create mode 100644 src/main/java/game/data/registries/VersionManifestHandler.java delete mode 100644 src/main/resources/server.json diff --git a/src/main/java/config/Config.java b/src/main/java/config/Config.java index 29da49f7..9bc873eb 100644 --- a/src/main/java/config/Config.java +++ b/src/main/java/config/Config.java @@ -4,7 +4,6 @@ import com.google.gson.GsonBuilder; import com.google.gson.stream.JsonReader; import game.data.WorldManager; -import game.data.chunk.ChunkFactory; import game.data.registries.RegistryLoader; import game.protocol.Protocol; import game.protocol.ProtocolVersionHandler; @@ -257,6 +256,7 @@ public static Protocol getGameProtocol() { private static void loadVersionRegistries(Protocol p) { try { RegistryLoader loader = RegistryLoader.forVersion(p.getVersion()); + if (loader == null) { return; } WorldManager.getInstance().setEntityMap(loader.generateEntityNames()); WorldManager.getInstance().setMenuRegistry(loader.generateMenuRegistry()); @@ -267,7 +267,6 @@ private static void loadVersionRegistries(Protocol p) { loader.clean(); } catch (Exception e) { e.printStackTrace(); - System.exit(1); } } diff --git a/src/main/java/config/Version.java b/src/main/java/config/Version.java index a1fe9b0c..4805fff4 100644 --- a/src/main/java/config/Version.java +++ b/src/main/java/config/Version.java @@ -1,12 +1,21 @@ package config; public enum Version { - V1_12, - V1_13, - V1_14, - V1_15, - V1_16, - ANY; + V1_12(317, 1022), + V1_13(341, 1444), + V1_14(440, 1901), + V1_15(550, 2200), + V1_16(701, 2504), + V1_17(0x4000001D, 2716), + ANY(0, 0); + + public final int dataVersion; + public final int protocolVersion; + + Version(int protocolVersion, int dataVersion) { + this.protocolVersion = protocolVersion; + this.dataVersion = dataVersion; + } boolean isVersion(VersionReporter versionReporter) { switch (this) { @@ -15,6 +24,7 @@ boolean isVersion(VersionReporter versionReporter) { case V1_14: return versionReporter.isAtLeast1_14(); case V1_15: return versionReporter.isAtLeast1_15(); case V1_16: return versionReporter.isAtLeast1_16(); + case V1_17: return versionReporter.isAtLeast1_17(); case ANY: return true; default: return false; } @@ -27,6 +37,7 @@ public boolean isDataVersion(int dataVersion) { case V1_14: return VersionReporter.isAtLeast1_14(dataVersion); case V1_15: return VersionReporter.isAtLeast1_15(dataVersion); case V1_16: return VersionReporter.isAtLeast1_16(dataVersion); + case V1_17: return VersionReporter.isAtLeast1_17(dataVersion); case ANY: return true; default: return false; } diff --git a/src/main/java/config/VersionReporter.java b/src/main/java/config/VersionReporter.java index de4d8385..130c5d4e 100644 --- a/src/main/java/config/VersionReporter.java +++ b/src/main/java/config/VersionReporter.java @@ -4,18 +4,6 @@ import game.protocol.ProtocolVersionHandler; public class VersionReporter { - private final static int DATA_VERSION_1_12 = 1022; - private final static int DATA_VERSION_1_13 = 1444; - private final static int DATA_VERSION_1_14 = 1901; - private final static int DATA_VERSION_1_15 = 2200; - private final static int DATA_VERSION_1_16 = 2504; - - private final static int VERSION_1_12 = 317; - private final static int VERSION_1_13 = 341; - private final static int VERSION_1_14 = 440; - private final static int VERSION_1_15 = 550; - private final static int VERSION_1_16 = 701; - private final int protocolVersion; public VersionReporter(int version) { this.protocolVersion = version; @@ -52,50 +40,59 @@ public boolean is(Version v) { } public boolean isAtLeast1_12() { - return protocolVersion >= VERSION_1_12; + return protocolVersion >= Version.V1_12.protocolVersion; } public boolean isAtLeast1_13() { - return protocolVersion >= VERSION_1_13; + return protocolVersion >= Version.V1_13.protocolVersion; } public boolean isAtLeast1_14() { - return protocolVersion >= VERSION_1_14; + return protocolVersion >= Version.V1_14.protocolVersion; } public boolean isAtLeast1_15() { - return protocolVersion >= VERSION_1_15; + return protocolVersion >= Version.V1_15.protocolVersion; } public boolean isAtLeast1_16() { - return protocolVersion >= VERSION_1_16; + return protocolVersion >= Version.V1_16.protocolVersion; + } + public boolean isAtLeast1_17() { + return protocolVersion >= Version.V1_17.protocolVersion; } public static boolean isAtLeast1_12(int dataVersion) { - return dataVersion >= DATA_VERSION_1_12; + return dataVersion >= Version.V1_12.dataVersion; } public static boolean isAtLeast1_13(int dataVersion) { - return dataVersion >= DATA_VERSION_1_13; + return dataVersion >= Version.V1_13.dataVersion; } public static boolean isAtLeast1_14(int dataVersion) { - return dataVersion >= DATA_VERSION_1_14; + return dataVersion >= Version.V1_14.dataVersion; } public static boolean isAtLeast1_15(int dataVersion) { - return dataVersion >= DATA_VERSION_1_15; + return dataVersion >= Version.V1_15.dataVersion; } public static boolean isAtLeast1_16(int dataVersion) { - return dataVersion >= DATA_VERSION_1_16; + return dataVersion >= Version.V1_16.dataVersion; + } + public static boolean isAtLeast1_17(int dataVersion) { + return dataVersion >= Version.V1_17.dataVersion; } public boolean is1_12() { - return protocolVersion >= VERSION_1_12 && protocolVersion < VERSION_1_13; + return protocolVersion >= Version.V1_12.protocolVersion && protocolVersion < Version.V1_13.protocolVersion; } public boolean is1_13() { - return protocolVersion >= VERSION_1_13 && protocolVersion < VERSION_1_14; + return protocolVersion >= Version.V1_13.protocolVersion && protocolVersion < Version.V1_14.protocolVersion; } public boolean is1_14() { - return protocolVersion >= VERSION_1_14 && protocolVersion < VERSION_1_15; + return protocolVersion >= Version.V1_14.protocolVersion && protocolVersion < Version.V1_15.protocolVersion; } public boolean is1_15() { - return protocolVersion >= VERSION_1_15 && protocolVersion < VERSION_1_16; + return protocolVersion >= Version.V1_15.protocolVersion && protocolVersion < Version.V1_16.protocolVersion; } public boolean is1_16() { - return protocolVersion >= VERSION_1_16; + return protocolVersion >= Version.V1_16.protocolVersion && protocolVersion < Version.V1_17.protocolVersion; + } + public boolean is1_17() { + return protocolVersion >= Version.V1_17.protocolVersion; } } diff --git a/src/main/java/game/data/WorldManager.java b/src/main/java/game/data/WorldManager.java index cc346376..0c8bba56 100644 --- a/src/main/java/game/data/WorldManager.java +++ b/src/main/java/game/data/WorldManager.java @@ -74,6 +74,7 @@ public class WorldManager { protected WorldManager() { this.isStarted = false; + this.entityMap = new EntityNames(); this.entityRegistry = new EntityRegistry(this); this.chunkFactory = new ChunkFactory(); this.mapRegistry = new MapRegistry(); diff --git a/src/main/java/game/data/chunk/Chunk.java b/src/main/java/game/data/chunk/Chunk.java index 51fe26dc..2a1d49d7 100644 --- a/src/main/java/game/data/chunk/Chunk.java +++ b/src/main/java/game/data/chunk/Chunk.java @@ -108,20 +108,22 @@ public void whenParsed(Runnable r) { /** * Read a chunk column. Largely based on: https://wiki.vg/Protocol */ - public void readChunkColumn(boolean full, int mask, DataTypeProvider dataProvider) { + public void readChunkColumn(boolean full, BitSet mask, DataTypeProvider dataProvider) { // We shift the mask left each iteration and check the unit bit. If the mask is 0, there will be no more chunks // so can stop the loop early. - for (int sectionY = getMinBlockSection(); sectionY <= getMaxSection() && mask != 0; sectionY++, mask >>>= 1) { + int maskIndex = 0; + for (int sectionY = getMinBlockSection(); sectionY <= getMaxSection() && !mask.isEmpty(); sectionY++, maskIndex++) { ChunkSection section = getChunkSection(sectionY); // Mask tells us if a section is present or not - if ((mask & 1) == 0) { + if (!mask.get(maskIndex)) { if (full && section != null) { section.resetBlocks(); } continue; } + mask.set(maskIndex, false); readBlockCount(dataProvider); @@ -248,12 +250,20 @@ private List getSectionList() { * Parse the chunk data. * * @param dataProvider network input - * @param full indicates if its the full chunk or a part of it */ - void parse(DataTypeProvider dataProvider, boolean full) { + protected void parse(DataTypeProvider dataProvider) { raiseEvent("parse from packet"); - int mask = dataProvider.readVarInt(); + boolean full = dataProvider.readBoolean(); + // if we don't have the partial chunk (anymore?), just make one from scratch + if (!full) { + this.markAsNew(); + } + + // for older versions, we use a BitSet as 1.17+ does. We construct it manually by turning the single int into + // a long. + long maskLong = dataProvider.readVarInt(); + BitSet mask = BitSet.valueOf(new long[]{maskLong}); // for 1.14+ parseHeightMaps(dataProvider); @@ -265,11 +275,18 @@ void parse(DataTypeProvider dataProvider, boolean full) { int size = dataProvider.readVarInt(); readChunkColumn(full, mask, dataProvider.ofLength(size)); + parseTileEntities(dataProvider); + afterParse(); + } + + protected void parseTileEntities(DataTypeProvider dataProvider) { int tileEntityCount = dataProvider.readVarInt(); for (int i = 0; i < tileEntityCount; i++) { addTileEntity(dataProvider.readNbtTag()); } + } + protected void afterParse() { // ensure the chunk is (re)saved this.saved = false; diff --git a/src/main/java/game/data/chunk/ChunkFactory.java b/src/main/java/game/data/chunk/ChunkFactory.java index adcd6a5d..c15accfc 100644 --- a/src/main/java/game/data/chunk/ChunkFactory.java +++ b/src/main/java/game/data/chunk/ChunkFactory.java @@ -4,17 +4,13 @@ import config.Option; import config.Version; import config.VersionReporter; +import game.data.chunk.version.*; import game.data.coordinates.Coordinate2D; import game.data.coordinates.Coordinate3D; import game.data.coordinates.CoordinateDim2D; import game.data.dimension.Dimension; import game.data.WorldManager; import game.data.entity.Entity; -import game.data.chunk.version.Chunk_1_12; -import game.data.chunk.version.Chunk_1_13; -import game.data.chunk.version.Chunk_1_14; -import game.data.chunk.version.Chunk_1_15; -import game.data.chunk.version.Chunk_1_16; import packets.DataTypeProvider; import se.llbit.nbt.NamedTag; import se.llbit.nbt.SpecificTag; @@ -103,19 +99,13 @@ public static Chunk parseChunk(UnparsedChunk parser, WorldManager worldManager) DataTypeProvider dataProvider = parser.provider; CoordinateDim2D chunkPos = parser.location; - boolean full = dataProvider.readBoolean(); Chunk chunk = worldManager.getChunk(chunkPos); if (chunk == null) { chunk = getVersionedChunk(chunkPos); worldManager.loadChunk(chunk, true, true); } - if (!full) { - // if we don't have the partial chunk (anymore?), just make one from scratch - chunk.markAsNew(); - } - - chunk.parse(dataProvider, full); + chunk.parse(dataProvider); return chunk; } @@ -155,6 +145,7 @@ private boolean readChunkDataPacket(UnparsedChunk parser) { */ private static Chunk getVersionedChunk(CoordinateDim2D chunkPos) { return Config.versionReporter().select(Chunk.class, + Option.of(Version.V1_17, () -> new Chunk_1_17(chunkPos)), Option.of(Version.V1_16, () -> new Chunk_1_16(chunkPos)), Option.of(Version.V1_15, () -> new Chunk_1_15(chunkPos)), Option.of(Version.V1_14, () -> new Chunk_1_14(chunkPos)), @@ -170,6 +161,7 @@ private static Chunk getVersionedChunk(CoordinateDim2D chunkPos) { */ private static Chunk getVersionedChunk(int dataVersion, CoordinateDim2D chunkPos) { return VersionReporter.select(dataVersion, Chunk.class, + Option.of(Version.V1_17, () -> new Chunk_1_17(chunkPos)), Option.of(Version.V1_16, () -> new Chunk_1_16(chunkPos)), Option.of(Version.V1_15, () -> new Chunk_1_15(chunkPos)), Option.of(Version.V1_14, () -> new Chunk_1_14(chunkPos)), diff --git a/src/main/java/game/data/chunk/version/ChunkSection_1_12.java b/src/main/java/game/data/chunk/version/ChunkSection_1_12.java index 1805990e..8d24c14d 100644 --- a/src/main/java/game/data/chunk/version/ChunkSection_1_12.java +++ b/src/main/java/game/data/chunk/version/ChunkSection_1_12.java @@ -1,5 +1,6 @@ package game.data.chunk.version; +import config.Version; import game.data.WorldManager; import game.data.chunk.Chunk; import game.data.chunk.ChunkSection; @@ -21,13 +22,15 @@ * as the new versions do. As such this class is more lengthy than the new versions. */ public class ChunkSection_1_12 extends ChunkSection { - protected int[][][] blockStates; - + public static final Version VERSION = Version.V1_12; @Override public int getDataVersion() { - return Chunk_1_12.DATA_VERSION; + return VERSION.dataVersion; } + protected int[][][] blockStates; + + public ChunkSection_1_12(byte y, Palette palette) { super(y, palette); this.blockStates = new int[16][16][16]; diff --git a/src/main/java/game/data/chunk/version/ChunkSection_1_13.java b/src/main/java/game/data/chunk/version/ChunkSection_1_13.java index b1f2dcae..b5d6bd1a 100644 --- a/src/main/java/game/data/chunk/version/ChunkSection_1_13.java +++ b/src/main/java/game/data/chunk/version/ChunkSection_1_13.java @@ -1,5 +1,6 @@ package game.data.chunk.version; +import config.Version; import game.data.WorldManager; import game.data.chunk.ChunkSection; import game.data.chunk.palette.Palette; @@ -16,9 +17,10 @@ * convert the palette from the packet to an NBT palette. */ public class ChunkSection_1_13 extends ChunkSection { + public static final Version VERSION = Version.V1_13; @Override public int getDataVersion() { - return Chunk_1_13.DATA_VERSION; + return VERSION.dataVersion; } public ChunkSection_1_13(byte y, Palette palette) { diff --git a/src/main/java/game/data/chunk/version/ChunkSection_1_14.java b/src/main/java/game/data/chunk/version/ChunkSection_1_14.java index 89ca6178..24cfeb33 100644 --- a/src/main/java/game/data/chunk/version/ChunkSection_1_14.java +++ b/src/main/java/game/data/chunk/version/ChunkSection_1_14.java @@ -1,10 +1,17 @@ package game.data.chunk.version; +import config.Version; import game.data.chunk.palette.Palette; import packets.builder.PacketBuilder; import se.llbit.nbt.Tag; public class ChunkSection_1_14 extends ChunkSection_1_13 { + public static final Version VERSION = Version.V1_14; + @Override + public int getDataVersion() { + return VERSION.dataVersion; + } + public ChunkSection_1_14(byte y, Palette palette) { super(y, palette); } @@ -13,11 +20,6 @@ public ChunkSection_1_14(int sectionY, Tag nbt) { super(sectionY, nbt); } - @Override - public int getDataVersion() { - return Chunk_1_14.DATA_VERSION; - } - @Override public void write(PacketBuilder packet) { packet.writeShort(4096); diff --git a/src/main/java/game/data/chunk/version/ChunkSection_1_15.java b/src/main/java/game/data/chunk/version/ChunkSection_1_15.java index 2b8929b3..72290179 100644 --- a/src/main/java/game/data/chunk/version/ChunkSection_1_15.java +++ b/src/main/java/game/data/chunk/version/ChunkSection_1_15.java @@ -1,10 +1,17 @@ package game.data.chunk.version; +import config.Version; import game.data.chunk.palette.Palette; import packets.builder.PacketBuilder; import se.llbit.nbt.Tag; public class ChunkSection_1_15 extends ChunkSection_1_14 { + public static final Version VERSION = Version.V1_15; + @Override + public int getDataVersion() { + return VERSION.dataVersion; + } + public ChunkSection_1_15(byte y, Palette palette) { super(y, palette); } @@ -13,10 +20,6 @@ public ChunkSection_1_15(int sectionY, Tag nbt) { super(sectionY, nbt); } - @Override - public int getDataVersion() { - return Chunk_1_15.DATA_VERSION; - } @Override public void write(PacketBuilder packet) { diff --git a/src/main/java/game/data/chunk/version/ChunkSection_1_16.java b/src/main/java/game/data/chunk/version/ChunkSection_1_16.java index 34c5e176..8ab7bc03 100644 --- a/src/main/java/game/data/chunk/version/ChunkSection_1_16.java +++ b/src/main/java/game/data/chunk/version/ChunkSection_1_16.java @@ -1,5 +1,6 @@ package game.data.chunk.version; +import config.Version; import game.data.chunk.version.encoder.BlockLocationEncoder; import game.data.chunk.Chunk; import game.data.chunk.palette.Palette; @@ -7,6 +8,12 @@ import se.llbit.nbt.Tag; public class ChunkSection_1_16 extends ChunkSection_1_15 { + public static final Version VERSION = Version.V1_16; + @Override + public int getDataVersion() { + return VERSION.dataVersion; + } + private final BlockLocationEncoder blockLocationEncoder = new BlockLocationEncoder_1_16(); @Override @@ -22,11 +29,6 @@ public ChunkSection_1_16(int sectionY, Tag nbt) { super(sectionY, nbt); } - @Override - public int getDataVersion() { - return Chunk_1_16.DATA_VERSION; - } - /** * When the bits per block increases, we must rewrite the blocks array. */ diff --git a/src/main/java/game/data/chunk/version/ChunkSection_1_17.java b/src/main/java/game/data/chunk/version/ChunkSection_1_17.java new file mode 100644 index 00000000..c76785d3 --- /dev/null +++ b/src/main/java/game/data/chunk/version/ChunkSection_1_17.java @@ -0,0 +1,21 @@ +package game.data.chunk.version; + +import config.Version; +import game.data.chunk.palette.Palette; +import se.llbit.nbt.Tag; + +public class ChunkSection_1_17 extends ChunkSection_1_16 { + public static final Version VERSION = Version.V1_17; + @Override + public int getDataVersion() { + return VERSION.dataVersion; + } + + public ChunkSection_1_17(byte y, Palette palette) { + super(y, palette); + } + + public ChunkSection_1_17(int sectionY, Tag nbt) { + super(sectionY, nbt); + } +} diff --git a/src/main/java/game/data/chunk/version/Chunk_1_12.java b/src/main/java/game/data/chunk/version/Chunk_1_12.java index 3d4e828b..8be55de0 100644 --- a/src/main/java/game/data/chunk/version/Chunk_1_12.java +++ b/src/main/java/game/data/chunk/version/Chunk_1_12.java @@ -1,5 +1,6 @@ package game.data.chunk.version; +import config.Version; import game.data.coordinates.CoordinateDim2D; import game.data.chunk.Chunk; import game.data.chunk.ChunkSection; @@ -15,7 +16,10 @@ * Chunks in the 1.12(.2) format. Biomes were a byte array in this version. */ public class Chunk_1_12 extends Chunk { - public static final int DATA_VERSION = 1132; + public static final Version VERSION = Version.V1_12; + + @Override + public int getDataVersion() { return VERSION.dataVersion; } private byte[] biomes; @@ -25,9 +29,6 @@ public Chunk_1_12(CoordinateDim2D location) { this.biomes = new byte[256]; } - @Override - public int getDataVersion() { return DATA_VERSION; } - @Override protected ChunkSection createNewChunkSection(byte y, Palette palette) { return new ChunkSection_1_12(y, palette); diff --git a/src/main/java/game/data/chunk/version/Chunk_1_13.java b/src/main/java/game/data/chunk/version/Chunk_1_13.java index a80d9506..7650bb0a 100644 --- a/src/main/java/game/data/chunk/version/Chunk_1_13.java +++ b/src/main/java/game/data/chunk/version/Chunk_1_13.java @@ -1,5 +1,6 @@ package game.data.chunk.version; +import config.Version; import game.data.chunk.IncompleteChunkException; import game.data.coordinates.CoordinateDim2D; import game.data.chunk.Chunk; @@ -15,7 +16,10 @@ * Chunk format for 1.13+. Now includes a status tag and the biomes are integers. */ public class Chunk_1_13 extends Chunk { - public static final int DATA_VERSION = 1444; + public static final Version VERSION = Version.V1_13; + + @Override + public int getDataVersion() { return VERSION.dataVersion; } private int[] biomes; @@ -23,8 +27,6 @@ public Chunk_1_13(CoordinateDim2D location) { super(location); } - @Override - public int getDataVersion() { return DATA_VERSION; } @Override protected ChunkSection createNewChunkSection(byte y, Palette palette) { diff --git a/src/main/java/game/data/chunk/version/Chunk_1_14.java b/src/main/java/game/data/chunk/version/Chunk_1_14.java index f8941abc..12f119a2 100644 --- a/src/main/java/game/data/chunk/version/Chunk_1_14.java +++ b/src/main/java/game/data/chunk/version/Chunk_1_14.java @@ -1,6 +1,7 @@ package game.data.chunk.version; import config.Config; +import config.Version; import game.data.coordinates.CoordinateDim2D; import game.data.chunk.ChunkSection; import game.data.chunk.palette.Palette; @@ -24,7 +25,10 @@ * this was moved to a different packet. Also, a block count? */ public class Chunk_1_14 extends Chunk_1_13 { - public static final int DATA_VERSION = 1901; + public static final Version VERSION = Version.V1_14; + + @Override + public int getDataVersion() { return VERSION.dataVersion; } SpecificTag heightMap; @@ -32,9 +36,6 @@ public Chunk_1_14(CoordinateDim2D location) { super(location); } - @Override - public int getDataVersion() { return DATA_VERSION; } - @Override protected void addLevelNbtTags(CompoundTag map) { super.addLevelNbtTags(map); diff --git a/src/main/java/game/data/chunk/version/Chunk_1_15.java b/src/main/java/game/data/chunk/version/Chunk_1_15.java index b078ae78..b74127a1 100644 --- a/src/main/java/game/data/chunk/version/Chunk_1_15.java +++ b/src/main/java/game/data/chunk/version/Chunk_1_15.java @@ -1,5 +1,6 @@ package game.data.chunk.version; +import config.Version; import game.data.coordinates.CoordinateDim2D; import game.data.chunk.ChunkSection; import game.data.chunk.palette.Palette; @@ -8,15 +9,15 @@ import se.llbit.nbt.SpecificTag; public class Chunk_1_15 extends Chunk_1_14 { - public static final int DATA_VERSION = 2200; + public static final Version VERSION = Version.V1_15; + + @Override + public int getDataVersion() { return VERSION.dataVersion; } public Chunk_1_15(CoordinateDim2D location) { super(location); } - @Override - public int getDataVersion() { return DATA_VERSION; } - @Override protected void parse2DBiomeData(DataTypeProvider dataProvider) { } diff --git a/src/main/java/game/data/chunk/version/Chunk_1_16.java b/src/main/java/game/data/chunk/version/Chunk_1_16.java index 09963358..9e85ffd0 100644 --- a/src/main/java/game/data/chunk/version/Chunk_1_16.java +++ b/src/main/java/game/data/chunk/version/Chunk_1_16.java @@ -1,6 +1,7 @@ package game.data.chunk.version; import config.Config; +import config.Version; import game.data.coordinates.Coordinate3D; import game.data.coordinates.CoordinateDim2D; import game.data.chunk.ChunkSection; @@ -22,15 +23,15 @@ * Support for chunks of version 1.16.2+. 1.16.0 and 1.16.1 are not supported. */ public class Chunk_1_16 extends Chunk_1_15 { - public static final int DATA_VERSION = 2578; + public static final Version VERSION = Version.V1_16; + + @Override + public int getDataVersion() { return VERSION.dataVersion; } public Chunk_1_16(CoordinateDim2D location) { super(location); } - @Override - public int getDataVersion() { return DATA_VERSION; } - // 1.16.2 changes biomes from int[1024] to varint[given length] @Override diff --git a/src/main/java/game/data/chunk/version/Chunk_1_17.java b/src/main/java/game/data/chunk/version/Chunk_1_17.java new file mode 100644 index 00000000..2a10c141 --- /dev/null +++ b/src/main/java/game/data/chunk/version/Chunk_1_17.java @@ -0,0 +1,82 @@ +package game.data.chunk.version; + +import config.Version; +import game.data.WorldManager; +import game.data.chunk.ChunkSection; +import game.data.chunk.palette.Palette; +import game.data.coordinates.CoordinateDim2D; +import packets.DataTypeProvider; +import se.llbit.nbt.SpecificTag; + +import java.util.BitSet; + +public class Chunk_1_17 extends Chunk_1_16 { + public static final Version VERSION = Version.V1_17; + + @Override + public int getDataVersion() { return VERSION.dataVersion; } + + static int minSectionY = 0; + static int minBlockSectionY = -1; + static int maxBlockSectionY = 15; + static int fullHeight; + + public Chunk_1_17(CoordinateDim2D location) { + super(location); + } + + public static void setWorldHeight(int min_y, int height) { + fullHeight = height; + minBlockSectionY = min_y >> 4; + minSectionY = minBlockSectionY - 1; + maxBlockSectionY = minBlockSectionY + (height >> 4) - 1; + } + + + @Override + protected ChunkSection createNewChunkSection(byte y, Palette palette) { + return new ChunkSection_1_17(y, palette); + } + + @Override + protected ChunkSection parseSection(int sectionY, SpecificTag section) { + return new ChunkSection_1_17(sectionY, section); + } + + /** + * Parse the chunk data. + * + * @param dataProvider network input + */ + @Override + protected void parse(DataTypeProvider dataProvider) { + raiseEvent("parse from packet"); + + BitSet mask = dataProvider.readBitSet(); + + parseHeightMaps(dataProvider); + + int biomeSize = dataProvider.readVarInt(); + setBiomes(dataProvider.readVarIntArray(biomeSize)); + + int size = dataProvider.readVarInt(); + readChunkColumn(true, mask, dataProvider.ofLength(size)); + + parseTileEntities(dataProvider); + afterParse(); + } + + @Override + protected int getMinSection() { + return minSectionY; + } + @Override + protected int getMinBlockSection() { + return minBlockSectionY; + } + @Override + protected int getMaxSection() { + return maxBlockSectionY; + } + +} diff --git a/src/main/java/game/data/dimension/Dimension.java b/src/main/java/game/data/dimension/Dimension.java index 07f6b57c..15067a19 100644 --- a/src/main/java/game/data/dimension/Dimension.java +++ b/src/main/java/game/data/dimension/Dimension.java @@ -3,6 +3,7 @@ import com.google.gson.Gson; import config.Config; import game.data.WorldManager; +import game.data.chunk.version.Chunk_1_17; import se.llbit.nbt.SpecificTag; import util.PathUtils; @@ -111,9 +112,13 @@ public void write(Path prefix) throws IOException { /** * When we join a dimension, we can use the dimension type information to try and link this to the registered - * type in the codec. + * type in the codec. For 1.17+ we need to give the world height/depth information to the chunk. */ public void registerType(SpecificTag dimensionNbt) { + if (Config.versionReporter().isAtLeast1_17()) { + Chunk_1_17.setWorldHeight(dimensionNbt.get("min_y").intValue(), dimensionNbt.get("height").intValue()); + } + if (this.type != null) { return; } diff --git a/src/main/java/game/data/registries/RegistryLoader.java b/src/main/java/game/data/registries/RegistryLoader.java index e7361736..9ef68390 100644 --- a/src/main/java/game/data/registries/RegistryLoader.java +++ b/src/main/java/game/data/registries/RegistryLoader.java @@ -2,6 +2,8 @@ import com.google.gson.Gson; +import config.Config; +import config.Version; import game.UnsupportedMinecraftVersionException; import game.data.entity.EntityNames; import game.data.chunk.palette.GlobalPalette; @@ -77,26 +79,43 @@ private boolean hasExistingReports() { return version.equals("1.12.2") || blocksPath.toFile().exists(); } + /** + * Get the current major java version. + * Source: https://stackoverflow.com/a/2591122 + */ + private static int getJavaVersion() { + String version = System.getProperty("java.version"); + if (version.startsWith("1.")) { + version = version.substring(2, 3); + } else { + int dot = version.indexOf("."); + if (dot != -1) { + version = version.substring(0, dot); + } + } + return Integer.parseInt(version); + } + /** * If we don't have the report, we'll have to download the relevant server.jar and generate them. We'll print some * helpful messages as well to put the user at ease about the delay. */ private void getReportsFromServerJar() throws IOException, InterruptedException { System.out.println("Looks like we have not run in version " + version + " before."); - String file = "server.json"; - InputStream input = EntityNames.class.getClassLoader().getResourceAsStream(file); - - if (input == null) { - throw new FileNotFoundException("Version.json not found"); - } - VersionMap map = new Gson().fromJson(new InputStreamReader(input), VersionMap.class); + String serverUrl = VersionManifestHandler.findServerUrl(version); - if (!map.containsKey(version)) { - throw new IllegalArgumentException("Cannot find given version: " + version + ". Are you using the latest world downloader version?"); + /* + * Since newer Minecraft versions use Java 1.16, we can't generate reports if the user is still using an older + * version of Java. To maintain support for older Java versions, this check is only done at this stage. + */ + if (Config.versionReporter().isAtLeast1_17() && getJavaVersion() < 16) { + System.err.println("Cannot run Minecraft version 1.17+ with a Java version below 16. You are currently using Java version " + getJavaVersion() + "."); + System.err.println("Please consider upgrading your Java version to at least version 16.\n"); + throw new UnsupportedMinecraftVersionException("Minecraft version 1.17 is not supported for java version " + getJavaVersion()); } - downloadServerJar(map.get(version)); + downloadServerJar(serverUrl); generateReports(); moveReports(); clean(); @@ -137,7 +156,16 @@ private void generateReports() throws IOException, InterruptedException { // instead of directly forwarding the output, we handle it manually. This way we can indent it and get rid // of the annoying teleport command spam. - BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); + printStream(p.getInputStream()); + printStream(p.getErrorStream()); + + p.waitFor(); + + System.out.println("Completed generating reports!"); + } + + private void printStream(InputStream str) throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(str)); String line; while ((line = reader.readLine()) != null) { if (line.contains("Ambiguity between arguments")) { @@ -145,10 +173,6 @@ private void generateReports() throws IOException, InterruptedException { } System.out.println("\t" + line); } - - p.waitFor(); - - System.out.println("Completed generating reports!"); } /** @@ -157,10 +181,10 @@ private void generateReports() throws IOException, InterruptedException { private void moveReports() throws IOException { Files.createDirectories(destinationPath); - if (versionSupportsGenerators()) { + if (versionSupportsGenerators() && Files.exists(registriesGeneratedPath)) { Files.move(registriesGeneratedPath, registryPath, StandardCopyOption.REPLACE_EXISTING); } - if (versionSupportsBlockGenerator()) { + if (versionSupportsBlockGenerator() && Files.exists(blocksGeneratedPath)) { Files.move(blocksGeneratedPath, blocksPath, StandardCopyOption.REPLACE_EXISTING); } } @@ -221,5 +245,3 @@ public boolean versionSupportsGenerators() { return versionSupportsBlockGenerator() && !version.startsWith("1.13"); } } - -class VersionMap extends HashMap { } diff --git a/src/main/java/game/data/registries/VersionManifestHandler.java b/src/main/java/game/data/registries/VersionManifestHandler.java new file mode 100644 index 00000000..d83f3d9a --- /dev/null +++ b/src/main/java/game/data/registries/VersionManifestHandler.java @@ -0,0 +1,68 @@ +package game.data.registries; + +import com.google.gson.Gson; +import game.UnsupportedMinecraftVersionException; +import kong.unirest.Unirest; + +import java.util.HashMap; +import java.util.List; + +/** + * Class to handle loading data from the Mojang version manifest. + */ +public class VersionManifestHandler { + private static final String manifestUrl = "https://launchermeta.mojang.com/mc/game/version_manifest_v2.json"; + + public static String findServerUrl(String desiredVersion) { + Gson g = new Gson(); + + String manifestResponse = Unirest.get(manifestUrl).asString().getBody(); + JsonManifest manifest = g.fromJson(manifestResponse, JsonManifest.class); + + String versionUrl = manifest.findUrl(desiredVersion); + if (versionUrl == null) { + throw new UnsupportedMinecraftVersionException("Cannot find version " + desiredVersion + " in version manifest"); + } + + String versionResponse = Unirest.get(versionUrl).asString().getBody(); + String finalUrl = g.fromJson(versionResponse, JsonSpecificVersion.class).getServerUrl(); + if (finalUrl == null || finalUrl.length() < 16) { + throw new UnsupportedMinecraftVersionException("No valid URL found for version " + desiredVersion); + } + + return finalUrl; + } + + class JsonManifest { + List versions; + + String findUrl(String version) { + for (JsonManifestVersion jmv : versions) { + if (jmv.id.equals(version)) { + return jmv.url; + } + } + return null; + } + class JsonManifestVersion { + String id; + String url; + } + } + + class JsonSpecificVersion { + HashMap downloads; + + String getServerUrl() { + return downloads.get("server").url; + } + + class JsonDownload { + String url; + } + } +} + + + + diff --git a/src/main/java/packets/DataTypeProvider.java b/src/main/java/packets/DataTypeProvider.java index 2eae9b8a..538a1ac0 100644 --- a/src/main/java/packets/DataTypeProvider.java +++ b/src/main/java/packets/DataTypeProvider.java @@ -18,6 +18,7 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; +import java.util.BitSet; import java.util.List; /** @@ -264,6 +265,12 @@ public String[] readStringArray(int size) { return res; } + public BitSet readBitSet() { + int numLongs = readVarInt(); + long[] longs = readLongArray(numLongs); + return BitSet.valueOf(longs); + } + public CoordinateDouble3D readDoubleCoordinates() { return new CoordinateDouble3D(readDouble(), readDouble(), readDouble()); } diff --git a/src/main/java/packets/builder/PacketBuilder.java b/src/main/java/packets/builder/PacketBuilder.java index 8bd62e52..8315c5de 100644 --- a/src/main/java/packets/builder/PacketBuilder.java +++ b/src/main/java/packets/builder/PacketBuilder.java @@ -15,6 +15,7 @@ import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.util.BitSet; public class PacketBuilder { ByteQueue bytes; @@ -259,6 +260,13 @@ public void writeFloat(float val) { writeByteArray(buffer.array()); } + public void writeBitSet(BitSet bits) { + long[] longs = bits.toLongArray(); + writeVarInt(longs.length); + writeLongArray(longs); + } + + public void copyRemainder(DataTypeProvider provider) { writeByteArray(provider.readByteArray(provider.remaining())); } diff --git a/src/main/resources/block-colors.json b/src/main/resources/block-colors.json index da815155..14eb6753 100644 --- a/src/main/resources/block-colors.json +++ b/src/main/resources/block-colors.json @@ -1,306 +1,397 @@ { "colors": { - "minecraft:chest": 15394270, - "minecraft:yellow_glazed_terracotta": 15517037, - "minecraft:yellow_wool": 16303657, - "minecraft:shulker_box": 9134475, - "minecraft:brown_concrete": 6306591, - "minecraft:sandstone_wall": 14208157, - "minecraft:polished_blackstone_wall": 3551803, - "minecraft:cyan_concrete": 1406856, - "minecraft:andesite_wall": 9013641, - "minecraft:smooth_stone": 10461087, - "minecraft:quartz_bricks": 15394270, - "minecraft:brown_concrete_powder": 8213814, - "minecraft:black_shulker_box": 1645086, - "minecraft:red_sand": 12478241, - "minecraft:comparator": 11184550, - "minecraft:lime_concrete": 6203416, - "minecraft:cyan_concrete_powder": 2397341, - "minecraft:warped_wart_block": 1472890, - "minecraft:stone_bricks": 8092539, - "minecraft:stonecutter": 8157300, - "minecraft:polished_blackstone_bricks": 3222581, - "minecraft:enchanting_table": 8877938, - "minecraft:light_gray_wool": 9342599, - "minecraft:light_gray_terracotta": 8874593, - "minecraft:observer": 6908265, - "minecraft:granite": 9922904, - "minecraft:pink_wool": 15634349, - "minecraft:cobblestone_wall": 8618626, - "minecraft:light_gray_shulker_box": 8224116, - "minecraft:polished_diorite": 12895173, - "minecraft:stone": 8289918, - "minecraft:orange_concrete_powder": 14910498, - "minecraft:sand": 14405539, - "minecraft:white_shulker_box": 14212573, - "minecraft:redstone_ore": 8942708, - "minecraft:white_concrete": 13620694, - "minecraft:chiseled_polished_blackstone": 3683389, - "minecraft:mushroom_stem": 13354169, - "minecraft:warped_planks": 2976871, - "minecraft:fire_coral_block": 10888239, - "minecraft:blue_ice": 7645181, - "minecraft:cyan_wool": 1411729, - "minecraft:hay_block": 10980365, - "minecraft:birch_door": 14603703, - "minecraft:purpur_pillar": 11305900, - "minecraft:fletching_table": 13088394, - "minecraft:light_blue_glazed_terracotta": 8040915, - "minecraft:loom": 9994601, - "minecraft:stripped_jungle_log": 11306069, - "minecraft:jukebox": 6636336, - "minecraft:cyan_terracotta": 5659483, - "minecraft:lime_shulker_box": 6597911, - "minecraft:dark_prismarine": 3432014, + "minecraft:acacia_leaves": 6775064, + "minecraft:acacia_log": 6840663, + "minecraft:acacia_planks": 11098930, + "minecraft:amethyst_block": 9070273, "minecraft:ancient_debris": 6639175, - "minecraft:pink_terracotta": 10571342, - "minecraft:chorus_flower": 10850214, - "minecraft:ice": 7841271, + "minecraft:andesite": 9013641, + "minecraft:andesite_slab": 9013641, + "minecraft:andesite_stairs": 9013641, + "minecraft:andesite_wall": 9013641, + "minecraft:anvil": 4539717, + "minecraft:azalea": 6716719, + "minecraft:azalea_leaves": 6716719, + "minecraft:barrel": 8873275, + "minecraft:basalt": 5592408, "minecraft:beacon": 9363160, - "minecraft:stripped_crimson_stem": 8993114, - "minecraft:snow_block": 16383742, - "minecraft:white_terracotta": 13742753, - "minecraft:magenta_concrete": 11088031, - "minecraft:red_wool": 10561314, - "minecraft:crimson_planks": 6828360, - "minecraft:grass_path": 9730625, - "minecraft:lectern": 11438676, - "minecraft:sea_lantern": 11979970, - "minecraft:pumpkin_stem": 13138205, - "minecraft:mossy_cobblestone_wall": 7370853, - "minecraft:white_wool": 15396077, - "minecraft:blue_concrete": 2895503, - "minecraft:structure_block": 7627125, - "minecraft:stripped_acacia_log": 11492411, - "minecraft:nether_quartz_ore": 8148303, - "minecraft:chiseled_quartz_block": 15196890, - "minecraft:diorite_wall": 12566464, - "minecraft:lime_terracotta": 6780212, - "minecraft:magenta_wool": 12404148, - "minecraft:prismarine_bricks": 6663584, - "minecraft:brown_glazed_terracotta": 8875358, - "minecraft:crafting_table": 8605999, - "minecraft:nether_gold_ore": 8145199, - "minecraft:red_concrete_powder": 11023922, - "minecraft:warped_stem": 4080208, - "minecraft:brown_wool": 7489320, - "minecraft:lodestone": 9738139, - "minecraft:mossy_stone_bricks": 7699053, - "minecraft:green_shulker_box": 5203231, - "minecraft:tnt": 10439493, - "minecraft:yellow_concrete_powder": 15255352, - "minecraft:green_concrete": 4807460, - "minecraft:jigsaw": 7233647, - "minecraft:podzol": 6176792, - "minecraft:white_concrete_powder": 14803939, - "minecraft:quartz_pillar": 15460064, + "minecraft:bedrock": 6118749, + "minecraft:bee_nest": 13740624, + "minecraft:birch_door": 14603703, + "minecraft:birch_leaves": 4347179, "minecraft:birch_log": 14605785, - "minecraft:orange_shulker_box": 15362571, - "minecraft:gray_terracotta": 3746339, - "minecraft:dried_kelp_block": 4080433, - "minecraft:end_stone_bricks": 14410147, + "minecraft:birch_planks": 12693626, "minecraft:birch_trapdoor": 13813670, - "minecraft:brown_mushroom_block": 9793361, - "minecraft:target": 14924974, - "minecraft:warped_nylium": 3306599, - "minecraft:red_sandstone": 12280863, - "minecraft:dark_oak_leaves": 4220199, - "minecraft:purple_wool": 8006572, - "minecraft:pumpkin": 13138205, - "minecraft:barrel": 8873275, - "minecraft:bookshelf": 8546891, - "minecraft:orange_glazed_terracotta": 12294266, - "minecraft:melon": 7770654, - "minecraft:end_portal_frame": 7702635, - "minecraft:diamond_ore": 8361106, - "minecraft:magma_block": 10373923, - "minecraft:diorite": 12566464, - "minecraft:polished_blackstone_button": 3551803, - "minecraft:red_nether_bricks": 4721164, - "minecraft:gray_wool": 4080711, - "minecraft:cracked_nether_bricks": 2757913, - "minecraft:terracotta": 9985603, - "minecraft:dead_tube_coral_block": 8682617, - "minecraft:dead_fire_coral_block": 8682873, - "minecraft:chiseled_red_sandstone": 12083742, - "minecraft:nether_bricks": 3020315, - "minecraft:blue_terracotta": 4864859, - "minecraft:dirt": 9003589, - "minecraft:stripped_dark_oak_log": 6376497, - "minecraft:polished_basalt": 6710631, - "minecraft:green_concrete_powder": 6387500, - "minecraft:magenta_glazed_terracotta": 13725120, - "minecraft:stone_button": 8289918, + "minecraft:black_concrete": 526863, + "minecraft:black_concrete_powder": 1710880, "minecraft:black_glazed_terracotta": 5644580, - "minecraft:dark_oak_trapdoor": 5059352, - "minecraft:pink_concrete_powder": 14981813, - "minecraft:blackstone_wall": 2893357, - "minecraft:oak_planks": 10782032, - "minecraft:orange_wool": 15758870, - "minecraft:gold_block": 16175683, - "minecraft:cut_sandstone": 14340001, - "minecraft:spruce_leaves": 3231281, + "minecraft:black_shulker_box": 1645086, "minecraft:black_terracotta": 2430480, - "minecraft:end_stone": 14409631, - "minecraft:jungle_log": 5653785, - "minecraft:yellow_terracotta": 12223779, - "minecraft:piston": 10388835, - "minecraft:birch_leaves": 4347179, - "minecraft:tube_coral_block": 3299792, - "minecraft:jack_o_lantern": 14262598, - "minecraft:spruce_trapdoor": 6901809, - "minecraft:magenta_shulker_box": 11417252, - "minecraft:iron_ore": 9143424, - "minecraft:pink_shulker_box": 15104926, - "minecraft:crimson_door": 7681872, - "minecraft:gilded_blackstone": 4601388, - "minecraft:netherrack": 6498344, - "minecraft:acacia_planks": 11098930, - "minecraft:bone_block": 13815476, - "minecraft:oak_log": 7362356, - "minecraft:carved_pumpkin": 10839321, + "minecraft:black_wool": 1447450, + "minecraft:blackstone": 2893357, + "minecraft:blackstone_slab": 2893357, + "minecraft:blackstone_stairs": 2893357, + "minecraft:blackstone_wall": 2893357, + "minecraft:blast_furnace": 5394770, + "minecraft:blue_concrete": 2895503, + "minecraft:blue_concrete_powder": 4606375, "minecraft:blue_glazed_terracotta": 3230358, - "minecraft:yellow_shulker_box": 16301342, + "minecraft:blue_ice": 7645181, + "minecraft:blue_shulker_box": 2895501, + "minecraft:blue_terracotta": 4864859, + "minecraft:blue_wool": 3488157, + "minecraft:bone_block": 13815476, + "minecraft:bookshelf": 8546891, "minecraft:brain_coral_block": 13655712, - "minecraft:white_glazed_terracotta": 13752789, - "minecraft:pink_glazed_terracotta": 15441334, - "minecraft:blue_concrete_powder": 4606375, - "minecraft:mossy_cobblestone": 7370853, - "minecraft:red_glazed_terracotta": 12009786, - "minecraft:smoker": 5921111, - "minecraft:furnace": 7434609, - "minecraft:bee_nest": 13740624, - "minecraft:smithing_table": 3816264, - "minecraft:blackstone": 2893357, - "minecraft:purple_terracotta": 7751254, - "minecraft:green_glazed_terracotta": 8164189, - "minecraft:orange_concrete": 14704897, - "minecraft:chiseled_nether_bricks": 3217437, - "minecraft:lime_wool": 7387418, - "minecraft:note_block": 6307371, - "minecraft:light_blue_concrete": 2329030, - "minecraft:redstone_lamp": 6896929, "minecraft:bricks": 9987159, + "minecraft:brown_concrete": 6306591, + "minecraft:brown_concrete_powder": 8213814, + "minecraft:brown_glazed_terracotta": 8875358, + "minecraft:brown_mushroom_block": 9793361, + "minecraft:brown_shulker_box": 6963748, + "minecraft:brown_terracotta": 5059363, + "minecraft:brown_wool": 7489320, + "minecraft:bubble_coral_block": 10952099, + "minecraft:budding_amethyst": 9201598, + "minecraft:calcite": 14737885, + "minecraft:cartography_table": 8220775, + "minecraft:carved_pumpkin": 10839321, + "minecraft:chest": 15394270, + "minecraft:chiseled_deepslate": 3684409, + "minecraft:chiseled_nether_bricks": 3217437, + "minecraft:chiseled_polished_blackstone": 3683389, + "minecraft:chiseled_quartz_block": 15196890, + "minecraft:chiseled_red_sandstone": 12083742, + "minecraft:chiseled_sandstone": 14207901, + "minecraft:chiseled_stone_bricks": 7960697, + "minecraft:chorus_flower": 10850214, "minecraft:chorus_plant": 6373217, + "minecraft:clay": 10528435, + "minecraft:coal_block": 1184274, + "minecraft:coal_ore": 7171437, + "minecraft:coarse_dirt": 8083774, + "minecraft:cobbled_deepslate": 5263442, + "minecraft:cobbled_deepslate_slab": 5263442, + "minecraft:cobbled_deepslate_stairs": 5263442, + "minecraft:cobbled_deepslate_wall": 5263442, + "minecraft:cobblestone": 8618626, + "minecraft:cobblestone_slab": 8618626, + "minecraft:cobblestone_stairs": 8618626, + "minecraft:cobblestone_wall": 8618626, + "minecraft:comparator": 11184550, + "minecraft:copper_block": 12676177, + "minecraft:copper_ore": 8421241, + "minecraft:cracked_deepslate_bricks": 4473925, + "minecraft:cracked_deepslate_tiles": 3552822, + "minecraft:cracked_nether_bricks": 2757913, + "minecraft:cracked_polished_blackstone_bricks": 3025201, + "minecraft:cracked_stone_bricks": 7829367, + "minecraft:crafting_table": 8605999, + "minecraft:crimson_door": 7681872, + "minecraft:crimson_nylium": 8660518, + "minecraft:crimson_planks": 6828360, + "minecraft:crimson_stem": 6298660, + "minecraft:crying_obsidian": 3084119, + "minecraft:cut_copper": 12610642, + "minecraft:cut_copper_slab": 12610642, + "minecraft:cut_copper_stairs": 12610642, + "minecraft:cut_red_sandstone": 12412449, + "minecraft:cut_red_sandstone_slab": 12412449, + "minecraft:cut_sandstone": 14340001, + "minecraft:cut_sandstone_slab": 14340001, + "minecraft:cyan_concrete": 1406856, + "minecraft:cyan_concrete_powder": 2397341, + "minecraft:cyan_glazed_terracotta": 4817030, + "minecraft:cyan_shulker_box": 1342087, + "minecraft:cyan_terracotta": 5659483, + "minecraft:cyan_wool": 1411729, "minecraft:dark_oak_door": 5256987, - "minecraft:oak_leaves": 3367963, + "minecraft:dark_oak_leaves": 4220199, + "minecraft:dark_oak_log": 4009754, + "minecraft:dark_oak_planks": 4467732, + "minecraft:dark_oak_trapdoor": 5059352, + "minecraft:dark_prismarine": 3432014, + "minecraft:dark_prismarine_slab": 3432014, + "minecraft:dark_prismarine_stairs": 3432014, + "minecraft:daylight_detector": 9667954, + "minecraft:dead_brain_coral_block": 8288115, + "minecraft:dead_bubble_coral_block": 8748408, + "minecraft:dead_fire_coral_block": 8682873, + "minecraft:dead_horn_coral_block": 8880252, + "minecraft:dead_tube_coral_block": 8682617, + "minecraft:deepslate": 5395028, + "minecraft:deepslate_bricks": 4868682, + "minecraft:deepslate_coal_ore": 5263441, + "minecraft:deepslate_copper_ore": 6512988, + "minecraft:deepslate_diamond_ore": 5862772, + "minecraft:deepslate_emerald_ore": 5731422, + "minecraft:deepslate_gold_ore": 8482901, + "minecraft:deepslate_iron_ore": 7563618, + "minecraft:deepslate_lapis_ore": 5660285, + "minecraft:deepslate_redstone_ore": 7688016, + "minecraft:deepslate_tiles": 3684409, + "minecraft:diamond_block": 7269860, + "minecraft:diamond_ore": 8229264, + "minecraft:diorite": 12566464, + "minecraft:diorite_slab": 12566464, + "minecraft:diorite_stairs": 12566464, + "minecraft:diorite_wall": 12566464, + "minecraft:dirt": 9003589, + "minecraft:dirt_path": 9730625, "minecraft:dragon_egg": 985618, - "minecraft:soul_soil": 5061167, - "minecraft:red_concrete": 9314336, - "minecraft:acacia_log": 6840663, + "minecraft:dried_kelp_block": 4080433, + "minecraft:dripstone_block": 8875357, + "minecraft:emerald_block": 3591521, + "minecraft:emerald_ore": 7638393, + "minecraft:enchanting_table": 8877938, + "minecraft:end_portal_frame": 7702635, + "minecraft:end_stone": 14409631, + "minecraft:end_stone_bricks": 14410147, + "minecraft:exposed_copper": 10714728, + "minecraft:exposed_cut_copper": 10320486, + "minecraft:exposed_cut_copper_slab": 10320486, + "minecraft:exposed_cut_copper_stairs": 10320486, + "minecraft:farmland": 9595208, + "minecraft:fire_coral_block": 10888239, + "minecraft:fletching_table": 13088394, + "minecraft:flowering_azalea": 7568208, + "minecraft:flowering_azalea_leaves": 7568208, + "minecraft:furnace": 7434609, + "minecraft:gilded_blackstone": 4470060, + "minecraft:glowstone": 11899497, + "minecraft:gold_block": 16175683, + "minecraft:gold_ore": 9931123, + "minecraft:granite": 9922904, + "minecraft:granite_slab": 9922904, + "minecraft:granite_stairs": 9922904, "minecraft:granite_wall": 9922904, - "minecraft:cracked_polished_blackstone_bricks": 3025457, - "minecraft:snow": 16383742, + "minecraft:grass_block": 3241252, + "minecraft:grass_path": 9730625, + "minecraft:gravel": 8683647, + "minecraft:gray_concrete": 3553597, + "minecraft:gray_concrete_powder": 5067093, + "minecraft:gray_glazed_terracotta": 5857379, + "minecraft:gray_shulker_box": 3619647, + "minecraft:gray_terracotta": 3746339, + "minecraft:gray_wool": 4080711, + "minecraft:green_concrete": 4807460, + "minecraft:green_concrete_powder": 6387500, + "minecraft:green_glazed_terracotta": 8164189, + "minecraft:green_shulker_box": 5203231, + "minecraft:green_terracotta": 5002026, + "minecraft:green_wool": 5598747, + "minecraft:hay_block": 10980365, + "minecraft:honeycomb_block": 15112497, + "minecraft:horn_coral_block": 14207298, + "minecraft:ice": 7841271, + "minecraft:iron_block": 14474460, + "minecraft:iron_ore": 9142908, + "minecraft:jack_o_lantern": 14262598, + "minecraft:jigsaw": 7233647, + "minecraft:jukebox": 6636336, + "minecraft:jungle_leaves": 1929734, + "minecraft:jungle_log": 5653785, "minecraft:jungle_planks": 10646867, - "minecraft:basalt": 5592408, - "minecraft:cyan_shulker_box": 1342087, - "minecraft:crimson_nylium": 8660518, - "minecraft:diamond_block": 7269860, "minecraft:lapis_block": 2049164, - "minecraft:prismarine": 6856602, - "minecraft:farmland": 9595208, - "minecraft:bedrock": 6118749, - "minecraft:iron_block": 14474460, - "minecraft:purple_shulker_box": 6758557, - "minecraft:gravel": 8683647, - "minecraft:light_gray_concrete_powder": 10197908, - "minecraft:soul_sand": 5455924, + "minecraft:lapis_ore": 7501969, + "minecraft:lava": 14042123, + "minecraft:lectern": 11438676, + "minecraft:light_blue_concrete": 2329030, "minecraft:light_blue_concrete_powder": 4961749, - "minecraft:red_mushroom_block": 13121077, - "minecraft:glowstone": 11899497, - "minecraft:nether_wart_block": 7603975, - "minecraft:light_gray_glazed_terracotta": 10332844, - "minecraft:green_wool": 5598747, + "minecraft:light_blue_glazed_terracotta": 8040915, "minecraft:light_blue_shulker_box": 3318996, + "minecraft:light_blue_terracotta": 7433353, + "minecraft:light_blue_wool": 3911641, + "minecraft:light_gray_concrete": 8224115, + "minecraft:light_gray_concrete_powder": 10197908, + "minecraft:light_gray_glazed_terracotta": 10332844, + "minecraft:light_gray_shulker_box": 8224116, + "minecraft:light_gray_terracotta": 8874593, + "minecraft:light_gray_wool": 9342599, + "minecraft:lime_concrete": 6203416, + "minecraft:lime_concrete_powder": 8240426, "minecraft:lime_glazed_terracotta": 11454283, + "minecraft:lime_shulker_box": 6597911, + "minecraft:lime_terracotta": 6780212, + "minecraft:lime_wool": 7387418, + "minecraft:lodestone": 9738139, + "minecraft:loom": 9994601, + "minecraft:magenta_concrete": 11088031, + "minecraft:magenta_concrete_powder": 12604600, + "minecraft:magenta_glazed_terracotta": 13725120, + "minecraft:magenta_shulker_box": 11417252, + "minecraft:magenta_terracotta": 9787500, + "minecraft:magenta_wool": 12404148, + "minecraft:magma_block": 10373923, + "minecraft:melon": 7770654, + "minecraft:melon_stem": 7770654, + "minecraft:moss_block": 5926445, + "minecraft:mossy_cobblestone": 7370853, + "minecraft:mossy_cobblestone_slab": 7370853, + "minecraft:mossy_cobblestone_stairs": 7370853, + "minecraft:mossy_cobblestone_wall": 7370853, + "minecraft:mossy_stone_bricks": 7699053, + "minecraft:mushroom_stem": 13354169, + "minecraft:mycelium": 7299685, + "minecraft:nether_bricks": 3020315, + "minecraft:nether_gold_ore": 8145199, + "minecraft:nether_quartz_ore": 8148303, + "minecraft:nether_wart_block": 7603975, + "minecraft:netherite_block": 4472642, + "minecraft:netherrack": 6498344, + "minecraft:note_block": 6307371, + "minecraft:oak_leaves": 3367963, + "minecraft:oak_log": 7362356, + "minecraft:oak_planks": 10782032, + "minecraft:observer": 6908265, + "minecraft:obsidian": 1445923, + "minecraft:orange_concrete": 14704897, + "minecraft:orange_concrete_powder": 14910498, + "minecraft:orange_glazed_terracotta": 12294266, + "minecraft:orange_shulker_box": 15362571, "minecraft:orange_terracotta": 10572581, - "minecraft:purple_concrete": 6561692, - "minecraft:black_concrete": 526863, - "minecraft:black_concrete_powder": 1710880, + "minecraft:orange_wool": 15758870, + "minecraft:oxidized_copper": 5481606, + "minecraft:oxidized_cut_copper": 5348480, + "minecraft:oxidized_cut_copper_slab": 5348480, + "minecraft:oxidized_cut_copper_stairs": 5348480, + "minecraft:packed_ice": 9352442, + "minecraft:pink_concrete": 13985166, + "minecraft:pink_concrete_powder": 14981813, + "minecraft:pink_glazed_terracotta": 15441334, + "minecraft:pink_shulker_box": 15104926, + "minecraft:pink_terracotta": 10571342, + "minecraft:pink_wool": 15634349, + "minecraft:piston": 10388835, "minecraft:piston_head": 10388835, - "minecraft:black_wool": 1447450, + "minecraft:podzol": 6176792, + "minecraft:polished_andesite": 8816775, + "minecraft:polished_andesite_slab": 8816775, + "minecraft:polished_andesite_stairs": 8816775, + "minecraft:polished_basalt": 6710631, + "minecraft:polished_blackstone": 3551803, + "minecraft:polished_blackstone_bricks": 3288374, + "minecraft:polished_blackstone_button": 3551803, + "minecraft:polished_blackstone_slab": 3551803, + "minecraft:polished_blackstone_stairs": 3551803, + "minecraft:polished_blackstone_wall": 3551803, + "minecraft:polished_deepslate": 4934475, + "minecraft:polished_deepslate_slab": 4934475, + "minecraft:polished_deepslate_stairs": 4934475, + "minecraft:polished_deepslate_wall": 4934475, + "minecraft:polished_diorite": 12895173, + "minecraft:polished_diorite_slab": 12895173, + "minecraft:polished_diorite_stairs": 12895173, + "minecraft:polished_granite": 10251355, + "minecraft:polished_granite_slab": 10251355, + "minecraft:polished_granite_stairs": 10251355, + "minecraft:powder_snow": 16317949, + "minecraft:powder_snow_cauldron": 16317949, + "minecraft:prismarine": 6856602, + "minecraft:prismarine_bricks": 6663584, + "minecraft:prismarine_slab": 6856602, + "minecraft:prismarine_stairs": 6856602, "minecraft:prismarine_wall": 6856602, - "minecraft:lava": 14042123, - "minecraft:coarse_dirt": 8083774, - "minecraft:gold_ore": 9933185, - "minecraft:light_blue_wool": 3911641, - "minecraft:spruce_log": 3876369, - "minecraft:dark_oak_log": 4009754, - "minecraft:warped_door": 3048060, - "minecraft:cyan_glazed_terracotta": 4817030, - "minecraft:blue_shulker_box": 2895501, - "minecraft:stripped_warped_stem": 3839892, + "minecraft:pumpkin": 13138205, + "minecraft:pumpkin_stem": 13138205, + "minecraft:purple_concrete": 6561692, + "minecraft:purple_concrete_powder": 8665009, + "minecraft:purple_glazed_terracotta": 7680675, + "minecraft:purple_shulker_box": 6758557, + "minecraft:purple_terracotta": 7751254, + "minecraft:purple_wool": 8006572, "minecraft:purpur_block": 11173802, - "minecraft:daylight_detector": 9667954, - "minecraft:pink_concrete": 13985166, - "minecraft:chiseled_sandstone": 14207901, - "minecraft:polished_granite": 10251355, + "minecraft:purpur_pillar": 11305900, "minecraft:quartz_block": 15459807, - "minecraft:polished_blackstone": 3551803, - "minecraft:light_gray_concrete": 8224115, - "minecraft:grass_block": 3241252, - "minecraft:dead_brain_coral_block": 8288115, - "minecraft:coal_ore": 7829367, - "minecraft:stripped_birch_log": 12955766, - "minecraft:green_terracotta": 5002026, - "minecraft:magenta_concrete_powder": 12604600, - "minecraft:water": 1719997, - "minecraft:netherite_block": 4472642, - "minecraft:polished_andesite": 8816775, - "minecraft:crimson_stem": 6298660, - "minecraft:blue_wool": 3488157, - "minecraft:acacia_leaves": 6775064, - "minecraft:wet_sponge": 11318854, - "minecraft:cracked_stone_bricks": 7829367, - "minecraft:melon_stem": 7770654, - "minecraft:spruce_door": 7098931, - "minecraft:shroomlight": 15833690, - "minecraft:cobblestone": 8618626, - "minecraft:jungle_leaves": 1929734, + "minecraft:quartz_bricks": 15394270, + "minecraft:quartz_pillar": 15460064, + "minecraft:raw_copper_block": 10579026, + "minecraft:raw_gold_block": 14659386, + "minecraft:raw_iron_block": 11242610, + "minecraft:red_concrete": 9314336, + "minecraft:red_concrete_powder": 11023922, + "minecraft:red_glazed_terracotta": 12009786, + "minecraft:red_mushroom_block": 13121077, + "minecraft:red_nether_bricks": 4721164, + "minecraft:red_sand": 12478241, + "minecraft:red_sandstone": 12280863, + "minecraft:red_sandstone_slab": 12280863, + "minecraft:red_sandstone_stairs": 12280863, + "minecraft:red_sandstone_wall": 12280863, + "minecraft:red_shulker_box": 9248542, + "minecraft:red_terracotta": 9387310, + "minecraft:red_wool": 10561314, "minecraft:redstone_block": 11802886, - "minecraft:coal_block": 1184274, - "minecraft:stripped_spruce_log": 7625268, - "minecraft:dead_horn_coral_block": 8880252, - "minecraft:yellow_concrete": 15773461, - "minecraft:honeycomb_block": 15112497, + "minecraft:redstone_lamp": 6896929, + "minecraft:redstone_ore": 9532532, + "minecraft:repeater": 10790051, + "minecraft:rooted_dirt": 9661008, + "minecraft:sand": 14405539, "minecraft:sandstone": 14208157, - "minecraft:light_blue_terracotta": 7433353, - "minecraft:gray_concrete": 3553597, - "minecraft:packed_ice": 9352442, - "minecraft:blast_furnace": 5394770, - "minecraft:red_terracotta": 9387310, - "minecraft:emerald_block": 3591521, - "minecraft:cartography_table": 8220775, - "minecraft:lime_concrete_powder": 8240426, + "minecraft:sandstone_slab": 14208157, + "minecraft:sandstone_stairs": 14208157, + "minecraft:sandstone_wall": 14208157, + "minecraft:sculk_sensor": 1132373, + "minecraft:sea_lantern": 11979970, + "minecraft:shroomlight": 15833690, + "minecraft:shulker_box": 9134475, + "minecraft:smithing_table": 3816264, + "minecraft:smoker": 5986648, + "minecraft:smooth_basalt": 4868687, + "minecraft:smooth_stone": 10461087, + "minecraft:smooth_stone_slab": 10461087, + "minecraft:snow": 16383742, + "minecraft:snow_block": 16383742, + "minecraft:soul_sand": 5455924, + "minecraft:soul_soil": 5061167, "minecraft:sponge": 12894538, - "minecraft:lapis_ore": 7172742, - "minecraft:mycelium": 7299685, - "minecraft:cut_red_sandstone": 12412449, - "minecraft:gray_shulker_box": 3619647, - "minecraft:anvil": 4539717, - "minecraft:stripped_oak_log": 11636822, - "minecraft:obsidian": 1445923, - "minecraft:red_shulker_box": 9248542, - "minecraft:red_sandstone_wall": 12280863, - "minecraft:brown_shulker_box": 6963748, - "minecraft:purple_concrete_powder": 8665009, + "minecraft:spruce_door": 7098931, + "minecraft:spruce_leaves": 3231281, + "minecraft:spruce_log": 3876369, "minecraft:spruce_planks": 7623985, - "minecraft:repeater": 10790051, - "minecraft:andesite": 9013641, - "minecraft:dark_oak_planks": 4467732, - "minecraft:purple_glazed_terracotta": 7680675, - "minecraft:magenta_terracotta": 9787500, - "minecraft:birch_planks": 12693626, - "minecraft:chiseled_stone_bricks": 7960697, - "minecraft:bubble_coral_block": 10952099, - "minecraft:gray_glazed_terracotta": 5857379, - "minecraft:horn_coral_block": 14207298, - "minecraft:clay": 10528435, - "minecraft:brown_terracotta": 5059363, - "minecraft:gray_concrete_powder": 5067093, - "minecraft:emerald_ore": 8162688, - "minecraft:crying_obsidian": 3084119, - "minecraft:dead_bubble_coral_block": 8748408 + "minecraft:spruce_trapdoor": 6901809, + "minecraft:stone": 8289918, + "minecraft:stone_bricks": 8092539, + "minecraft:stone_button": 8289918, + "minecraft:stone_slab": 8289918, + "minecraft:stone_stairs": 8289918, + "minecraft:stonecutter": 8157300, + "minecraft:stripped_acacia_log": 11492411, + "minecraft:stripped_birch_log": 12955766, + "minecraft:stripped_crimson_stem": 8993114, + "minecraft:stripped_dark_oak_log": 6376497, + "minecraft:stripped_jungle_log": 11306069, + "minecraft:stripped_oak_log": 11636822, + "minecraft:stripped_spruce_log": 7625268, + "minecraft:stripped_warped_stem": 3839892, + "minecraft:structure_block": 7627125, + "minecraft:target": 14924974, + "minecraft:terracotta": 9985603, + "minecraft:tnt": 10439493, + "minecraft:tube_coral_block": 3299792, + "minecraft:tuff": 7237224, + "minecraft:warped_door": 3048060, + "minecraft:warped_nylium": 3306599, + "minecraft:warped_planks": 2976871, + "minecraft:warped_stem": 4080208, + "minecraft:warped_wart_block": 1472890, + "minecraft:water": 1719997, + "minecraft:weathered_copper": 7182960, + "minecraft:weathered_cut_copper": 7312237, + "minecraft:weathered_cut_copper_slab": 7312237, + "minecraft:weathered_cut_copper_stairs": 7312237, + "minecraft:wet_sponge": 11318854, + "minecraft:white_concrete": 13620694, + "minecraft:white_concrete_powder": 14803939, + "minecraft:white_glazed_terracotta": 13752789, + "minecraft:white_shulker_box": 14212573, + "minecraft:white_terracotta": 13742753, + "minecraft:white_wool": 15396077, + "minecraft:yellow_concrete": 15773461, + "minecraft:yellow_concrete_powder": 15255352, + "minecraft:yellow_glazed_terracotta": 15517037, + "minecraft:yellow_shulker_box": 16301342, + "minecraft:yellow_terracotta": 12223779, + "minecraft:yellow_wool": 16303657 } } diff --git a/src/main/resources/protocol-versions.json b/src/main/resources/protocol-versions.json index 67f3c3f4..181cfe44 100644 --- a/src/main/resources/protocol-versions.json +++ b/src/main/resources/protocol-versions.json @@ -170,6 +170,41 @@ "0x2E": "UseItem", "0x0A": "ContainerClose" } + }, + "1073741859": { + "version": "1.17-rc2", + "dataVersion": 2716, + "clientBound": { + "0x00": "AddEntity", + "0x02": "AddMob", + "0x04": "AddPlayer", + "0x0a": "BlockEntityData", + "0x0c": "BlockUpdate", + "0x0f": "Chat", + "0x13": "ContainerClose", + "0x14": "ContainerSetContent", + "0x1d": "ForgetLevelChunk", + "0x22": "LevelChunk", + "0x25": "LightUpdate", + "0x26": "Login", + "0x27": "MapItemData", + "0x29": "MoveEntityPos", + "0x2a": "MoveEntityPosRot", + "0x2e": "OpenScreen", + "0x3d": "Respawn", + "0x3f": "SectionBlocksUpdate", + "0x4d": "SetEntityData", + "0x50": "SetEquipment", + "0x61": "TeleportEntity" + }, + "serverBound": { + "0x09": "ContainerClose", + "0x11": "MovePlayerPos", + "0x12": "MovePlayerPosRot", + "0x13": "MovePlayerRot", + "0x15": "MoveVehicle", + "0x2e": "UseItem" + } } } diff --git a/src/main/resources/server.json b/src/main/resources/server.json deleted file mode 100644 index f6170df2..00000000 --- a/src/main/resources/server.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "1.13.0": "https://launcher.mojang.com/v1/objects/d0caafb8438ebd206f99930cfaecfa6c9a13dca0/server.jar", - "1.13.1": "https://launcher.mojang.com/v1/objects/fe123682e9cb30031eae351764f653500b7396c9/server.jar", - "1.13.2": "https://launcher.mojang.com/v1/objects/3737db93722a9e39eeada7c27e7aca28b144ffa7/server.jar", - "1.14.0": "https://launcher.mojang.com/v1/objects/f1a0073671057f01aa843443fef34330281333ce/server.jar", - "1.14.1": "https://launcher.mojang.com/v1/objects/ed76d597a44c5266be2a7fcd77a8270f1f0bc118/server.jar", - "1.14.2": "https://launcher.mojang.com/v1/objects/808be3869e2ca6b62378f9f4b33c946621620019/server.jar", - "1.14.3": "https://launcher.mojang.com/v1/objects/d0d0fe2b1dc6ab4c65554cb734270872b72dadd6/server.jar", - "1.14.4": "https://launcher.mojang.com/v1/objects/3dc3d84a581f14691199cf6831b71ed1296a9fdf/server.jar", - "1.15.0": "https://launcher.mojang.com/v1/objects/e9f105b3c5c7e85c7b445249a93362a22f62442d/server.jar", - "1.15.1": "https://launcher.mojang.com/v1/objects/4d1826eebac84847c71a77f9349cc22afd0cf0a1/server.jar", - "1.15.2": "https://launcher.mojang.com/v1/objects/bb2b6b1aefcd70dfd1892149ac3a215f6c636b07/server.jar", - "1.16.0": "https://launcher.mojang.com/v1/objects/a0d03225615ba897619220e256a266cb33a44b6b/server.jar", - "1.16.1": "https://launcher.mojang.com/v1/objects/a412fd69db1f81db3f511c1463fd304675244077/server.jar", - "1.16.2": "https://launcher.mojang.com/v1/objects/c5f6fb23c3876461d46ec380421e42b289789530/server.jar", - "1.16.3": "https://launcher.mojang.com/v1/objects/f02f4473dbf152c23d7d484952121db0b36698cb/server.jar", - "1.16.4": "https://launcher.mojang.com/v1/objects/35139deedbd5182953cf1caa23835da59ca3d7cd/server.jar", - "1.16.5": "https://launcher.mojang.com/v1/objects/1b557e7b033b583cd9f66746b7a9ab1ec1673ced/server.jar" -} \ No newline at end of file From 139748f4e8029067cfba7c040d79083e9b69daa5 Mon Sep 17 00:00:00 2001 From: Mirco Kroon <23699979+mircokroon@users.noreply.github.com> Date: Wed, 9 Jun 2021 20:40:33 +0200 Subject: [PATCH 03/11] Fixed handling of lighting and network encoding for 1.17 --- chunkdata.bin | Bin 0 -> 8322 bytes pom.xml | 6 +- src/main/java/config/Version.java | 2 +- src/main/java/game/data/WorldManager.java | 2 +- src/main/java/game/data/chunk/Chunk.java | 38 +++--- .../data/chunk/version/ChunkSection_1_12.java | 11 -- .../data/chunk/version/ChunkSection_1_13.java | 13 ++ .../game/data/chunk/version/Chunk_1_14.java | 27 ++-- .../game/data/chunk/version/Chunk_1_16.java | 11 +- .../game/data/chunk/version/Chunk_1_17.java | 125 +++++++++++++++++- src/main/java/packets/DataTypeProvider.java | 8 ++ src/main/resources/protocol-versions.json | 6 +- src/test/java/game/data/chunk/ChunkTest.java | 44 +++++- .../builder/PacketBuilderAndParserTest.java | 15 +++ src/test/resources/chunkdata_1_17 | Bin 0 -> 8322 bytes 15 files changed, 246 insertions(+), 62 deletions(-) create mode 100644 chunkdata.bin create mode 100644 src/test/resources/chunkdata_1_17 diff --git a/chunkdata.bin b/chunkdata.bin new file mode 100644 index 0000000000000000000000000000000000000000..7f5677e4afd1da5b89d629115ef467da8ce6ad83 GIT binary patch literal 8322 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 8 - 15 + 16 UTF-8 @@ -240,8 +240,8 @@ org.mockito - mockito-all - 1.10.19 + mockito-core + 3.11.0 test diff --git a/src/main/java/config/Version.java b/src/main/java/config/Version.java index 4805fff4..74a03734 100644 --- a/src/main/java/config/Version.java +++ b/src/main/java/config/Version.java @@ -6,7 +6,7 @@ public enum Version { V1_14(440, 1901), V1_15(550, 2200), V1_16(701, 2504), - V1_17(0x4000001D, 2716), + V1_17(755, 2724), ANY(0, 0); public final int dataVersion; diff --git a/src/main/java/game/data/WorldManager.java b/src/main/java/game/data/WorldManager.java index 0c8bba56..86dce8d5 100644 --- a/src/main/java/game/data/WorldManager.java +++ b/src/main/java/game/data/WorldManager.java @@ -72,7 +72,7 @@ public class WorldManager { private final EntityRegistry entityRegistry; private final ChunkFactory chunkFactory; - protected WorldManager() { + public WorldManager() { this.isStarted = false; this.entityMap = new EntityNames(); this.entityRegistry = new EntityRegistry(this); diff --git a/src/main/java/game/data/chunk/Chunk.java b/src/main/java/game/data/chunk/Chunk.java index 2a1d49d7..e2d47f2c 100644 --- a/src/main/java/game/data/chunk/Chunk.java +++ b/src/main/java/game/data/chunk/Chunk.java @@ -26,7 +26,6 @@ public abstract class Chunk extends ChunkEntities { public static final int SECTION_HEIGHT = 16; public static final int SECTION_WIDTH = 16; protected static final int LIGHT_SIZE = 2048; - protected static final int CHUNK_HEIGHT = 256; private final ChunkSection[] chunkSections; public CoordinateDim2D location; private Runnable afterParse; @@ -64,9 +63,11 @@ protected void setChunkSection(int y, ChunkSection section) { protected int getMinSection() { return 0; } + protected int getMinBlockSection() { return 0; } + protected int getMaxSection() { return 15; } @@ -111,19 +112,17 @@ public void whenParsed(Runnable r) { public void readChunkColumn(boolean full, BitSet mask, DataTypeProvider dataProvider) { // We shift the mask left each iteration and check the unit bit. If the mask is 0, there will be no more chunks // so can stop the loop early. - int maskIndex = 0; - for (int sectionY = getMinBlockSection(); sectionY <= getMaxSection() && !mask.isEmpty(); sectionY++, maskIndex++) { + for (int sectionY = getMinBlockSection(); sectionY <= getMaxSection() && !mask.isEmpty(); sectionY++) { ChunkSection section = getChunkSection(sectionY); // Mask tells us if a section is present or not - if (!mask.get(maskIndex)) { + if (!mask.get(sectionY - getMinBlockSection())) { if (full && section != null) { section.resetBlocks(); } - continue; } - mask.set(maskIndex, false); + mask.set(sectionY - getMinBlockSection(), false); readBlockCount(dataProvider); @@ -141,16 +140,14 @@ public void readChunkColumn(boolean full, BitSet mask, DataTypeProvider dataProv if (dataArrayLength == 0) { continue; } + // parse blocks section.setBlocks(dataProvider.readLongArray(dataArrayLength)); parseLights(section, dataProvider); - // don't set section if it only has air or nothing at all - if (!palette.isEmpty()) { - // May replace an existing section or a null one - setChunkSection(sectionY, section); - } + // May replace an existing section or a null one + setChunkSection(sectionY, section); } // biome data is only present in full chunks, for <= 1.14.4 @@ -335,16 +332,18 @@ public PacketBuilder toPacket() { writeBitMask(packet); writeHeightMaps(packet); writeBiomes(packet); + writeChunkSections(packet); - // sections + // we don't include block entities - these chunks will be far away so they shouldn't be rendered anyway + packet.writeVarInt(0); + return packet; + } + + protected void writeChunkSections(PacketBuilder packet) { PacketBuilder columns = writeSectionData(); byte[] columnArr = columns.toArray(); packet.writeVarInt(columnArr.length); packet.writeByteArray(columnArr); - - // we don't include block entities - these chunks will be far away so they shouldn't be rendered anyway - packet.writeVarInt(0); - return packet; } public PacketBuilder toLightPacket() { return null; } @@ -355,7 +354,7 @@ protected void writeHeightMaps(PacketBuilder packet) { protected PacketBuilder writeSectionData() { PacketBuilder column = new PacketBuilder(); for (ChunkSection section : getAllSections()) { - if (section.getY() >= getMinBlockSection()) { + if (section.getY() >= getMinSection()) { section.write(column); } } @@ -366,10 +365,11 @@ protected PacketBuilder writeSectionData() { private void writeBitMask(PacketBuilder packet) { int res = 0; for (ChunkSection section : getAllSections()) { - if (section.getY() >= getMinBlockSection()) { - res |= 1 << section.getY(); + if (section.getY() >= getMinSection()) { + res |= 1 << (section.getY() - getMinSection()); } } + packet.writeVarInt(res); } diff --git a/src/main/java/game/data/chunk/version/ChunkSection_1_12.java b/src/main/java/game/data/chunk/version/ChunkSection_1_12.java index 8d24c14d..7b01ed36 100644 --- a/src/main/java/game/data/chunk/version/ChunkSection_1_12.java +++ b/src/main/java/game/data/chunk/version/ChunkSection_1_12.java @@ -165,17 +165,6 @@ public int getNumericBlockStateAt(int x, int y, int z) { return blockStates[x][y][z]; } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - - ChunkSection_1_12 that = (ChunkSection_1_12) o; - - return Arrays.deepEquals(blockStates, that.blockStates); - } - @Override public int hashCode() { int result = super.hashCode(); diff --git a/src/main/java/game/data/chunk/version/ChunkSection_1_13.java b/src/main/java/game/data/chunk/version/ChunkSection_1_13.java index b5d6bd1a..1002199d 100644 --- a/src/main/java/game/data/chunk/version/ChunkSection_1_13.java +++ b/src/main/java/game/data/chunk/version/ChunkSection_1_13.java @@ -11,6 +11,8 @@ import se.llbit.nbt.LongArrayTag; import se.llbit.nbt.Tag; +import java.util.Arrays; + /** * Starting with 1.13, the chunk format requires a palette and the palette indices. This is actually * much easier for us as the packet also comes in palette indices, so we can just copy those over and @@ -57,4 +59,15 @@ protected void addNbtTags(CompoundTag map) { private ListTag createPalette() { return new ListTag(Tag.TAG_COMPOUND, palette.toNbt()); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ChunkSection_1_13 that = (ChunkSection_1_13) o; + + if (getY() != that.getY()) return false; + return Arrays.equals(blocks, that.blocks); + } } diff --git a/src/main/java/game/data/chunk/version/Chunk_1_14.java b/src/main/java/game/data/chunk/version/Chunk_1_14.java index 12f119a2..cdbc360a 100644 --- a/src/main/java/game/data/chunk/version/Chunk_1_14.java +++ b/src/main/java/game/data/chunk/version/Chunk_1_14.java @@ -14,8 +14,7 @@ import se.llbit.nbt.StringTag; import se.llbit.nbt.Tag; -import java.util.Arrays; -import java.util.Iterator; +import java.util.BitSet; import java.util.Objects; import java.util.function.BiConsumer; import java.util.function.Function; @@ -59,6 +58,11 @@ protected int getMinSection() { return -1; } + @Override + protected int getMinBlockSection() { + return -1; + } + @Override protected void parseHeightMaps(DataTypeProvider dataProvider) { heightMap = dataProvider.readNbtTag(); @@ -107,19 +111,18 @@ protected ChunkSection parseSection(int sectionY, SpecificTag section) { public void updateLight(DataTypeProvider provider) { super.updateLight(provider); - int skyLightMask = provider.readVarInt(); - int blockLightMask = provider.readVarInt(); + BitSet skyLightMask = BitSet.valueOf(new long[]{(long) provider.readVarInt()}); + BitSet blockLightMask = BitSet.valueOf(new long[]{(long) provider.readVarInt()}); - int emptySkyLightMask = provider.readVarInt(); - int emptyBlockLightMask = provider.readVarInt(); + BitSet emptySkyLightMask = BitSet.valueOf(new long[]{(long) provider.readVarInt()}); + BitSet emptyBlockLightMask = BitSet.valueOf(new long[]{(long) provider.readVarInt()}); parseLightArray(skyLightMask, emptySkyLightMask, provider, ChunkSection::setSkyLight, ChunkSection::getSkyLight); parseLightArray(blockLightMask, emptyBlockLightMask, provider, ChunkSection::setBlockLight, ChunkSection::getBlockLight); } - private void parseLightArray(int mask, int emptyMask, DataTypeProvider provider, BiConsumer c, Function get) { - for (int sectionY = getMinSection(); mask > 0 || emptyMask > 0; sectionY++, mask >>>= 1, emptyMask >>>= 1) { - + protected void parseLightArray(BitSet mask, BitSet emptyMask, DataTypeProvider provider, BiConsumer c, Function get) { + for (int sectionY = getMinSection(); sectionY <= getMaxSection() && (!mask.isEmpty() || !emptyMask.isEmpty()); sectionY++) { ChunkSection s = getChunkSection(sectionY); if (s == null) { s = createNewChunkSection((byte) sectionY, Palette.empty()); @@ -129,12 +132,14 @@ private void parseLightArray(int mask, int emptyMask, DataTypeProvider provider, } // Mask tells us if a section is present or not - if ((mask & 1) == 0) { - if ((emptyMask & 1) != 0) { + if (!mask.get(sectionY - getMinSection())) { + if (!emptyMask.get(sectionY - getMinSection())) { c.accept(s, new byte[2048]); } + emptyMask.set(sectionY - getMinSection(), false); continue; } + mask.set(sectionY - getMinSection(), false); int skyLength = provider.readVarInt(); byte[] data = provider.readByteArray(skyLength); diff --git a/src/main/java/game/data/chunk/version/Chunk_1_16.java b/src/main/java/game/data/chunk/version/Chunk_1_16.java index 9e85ffd0..e5e39f31 100644 --- a/src/main/java/game/data/chunk/version/Chunk_1_16.java +++ b/src/main/java/game/data/chunk/version/Chunk_1_16.java @@ -1,23 +1,16 @@ package game.data.chunk.version; -import config.Config; import config.Version; -import game.data.coordinates.Coordinate3D; -import game.data.coordinates.CoordinateDim2D; import game.data.chunk.ChunkSection; import game.data.chunk.palette.Palette; -import game.protocol.Protocol; -import javafx.util.Pair; +import game.data.coordinates.Coordinate3D; +import game.data.coordinates.CoordinateDim2D; import packets.DataTypeProvider; -import packets.builder.DebugPacketBuilder; import packets.builder.PacketBuilder; import se.llbit.nbt.SpecificTag; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.function.BiConsumer; -import java.util.function.Function; /** * Support for chunks of version 1.16.2+. 1.16.0 and 1.16.1 are not supported. diff --git a/src/main/java/game/data/chunk/version/Chunk_1_17.java b/src/main/java/game/data/chunk/version/Chunk_1_17.java index 2a10c141..9843693e 100644 --- a/src/main/java/game/data/chunk/version/Chunk_1_17.java +++ b/src/main/java/game/data/chunk/version/Chunk_1_17.java @@ -1,14 +1,19 @@ package game.data.chunk.version; +import config.Config; import config.Version; -import game.data.WorldManager; import game.data.chunk.ChunkSection; import game.data.chunk.palette.Palette; import game.data.coordinates.CoordinateDim2D; +import game.protocol.Protocol; +import javafx.util.Pair; import packets.DataTypeProvider; +import packets.builder.PacketBuilder; import se.llbit.nbt.SpecificTag; import java.util.BitSet; +import java.util.InputMismatchException; +import java.util.function.Function; public class Chunk_1_17 extends Chunk_1_16 { public static final Version VERSION = Version.V1_17; @@ -16,8 +21,8 @@ public class Chunk_1_17 extends Chunk_1_16 { @Override public int getDataVersion() { return VERSION.dataVersion; } - static int minSectionY = 0; - static int minBlockSectionY = -1; + static int minSectionY = -1; + static int minBlockSectionY = 0; static int maxBlockSectionY = 15; static int fullHeight; @@ -66,14 +71,128 @@ protected void parse(DataTypeProvider dataProvider) { afterParse(); } + /** + * Generate network packet for this chunk. + */ + public PacketBuilder toPacket() { + Protocol p = Config.versionReporter().getProtocol(); + PacketBuilder packet = new PacketBuilder(); + packet.writeVarInt(p.clientBound("LevelChunk")); + + packet.writeInt(location.getX()); + packet.writeInt(location.getZ()); + writeBitSet(packet); + writeHeightMaps(packet); + writeBiomes(packet); + writeChunkSections(packet); + + // we don't include block entities - these chunks will be far away so they shouldn't be rendered anyway + packet.writeVarInt(0); + return packet; + } + + protected PacketBuilder writeSectionData() { + PacketBuilder column = new PacketBuilder(); + for (ChunkSection section : getAllSections()) { + if (section.getY() >= getMinBlockSection()) { + section.write(column); + } + } + + return column; + } + + private void writeBitSet(PacketBuilder packet) { + BitSet res = new BitSet(); + for (ChunkSection section : getAllSections()) { + if (section.getY() >= getMinBlockSection()) { + res.set(section.getY() - getMinBlockSection()); + } + } + + packet.writeBitSet(res); + } + + @Override + public PacketBuilder toLightPacket() { + PacketBuilder packet = buildLightPacket(); + + Pair skyLight = writeLightToPacket(ChunkSection::getSkyLight); + Pair blockLight = writeLightToPacket(ChunkSection::getBlockLight); + + packet.writeBitSet(skyLight.getKey()); + packet.writeBitSet(blockLight.getKey()); + + // empty masks we just set to 0 + packet.writeBitSet(new BitSet()); + packet.writeBitSet(new BitSet()); + + packet.writeVarInt(skyLight.getKey().cardinality()); + packet.writeByteArray(skyLight.getValue().toArray()); + + packet.writeVarInt(blockLight.getKey().cardinality()); + packet.writeByteArray(blockLight.getValue().toArray()); + + return packet; + } + + + @Override + public void updateLight(DataTypeProvider provider) { + boolean isTrusted = provider.readBoolean(); + + BitSet skyLightMask = provider.readBitSet(); + BitSet blockLightMask = provider.readBitSet(); + + BitSet emptySkyLightMask = provider.readBitSet(); + BitSet emptyBlockLightMask = provider.readBitSet(); + + int numSkyLight = provider.readVarInt(); + if (skyLightMask.cardinality() != numSkyLight) { + throw new InputMismatchException("Number of provided skylight maps does not match provided mask: " + skyLightMask + " != " + numSkyLight); + } + + parseLightArray(skyLightMask, emptySkyLightMask, provider, ChunkSection::setSkyLight, ChunkSection::getSkyLight); + + int numBlockLight = provider.readVarInt(); + if (blockLightMask.cardinality() != numBlockLight) { + throw new InputMismatchException("Number of provided blocklight maps does not match provided mask: " + blockLightMask + " != " + numBlockLight); + } + parseLightArray(blockLightMask, emptyBlockLightMask, provider, ChunkSection::setBlockLight, ChunkSection::getBlockLight); + } + + + /** + * Write one of the light arrays to a packet, return the mask and the array itself. + */ + private Pair writeLightToPacket(Function fn) { + PacketBuilder packet = new PacketBuilder(); + BitSet mask = new BitSet(); + + for (ChunkSection section : getAllSections()) { + byte[] light = fn.apply(section); + if (light == null || light.length == 0) { continue; } + + packet.writeVarInt(light.length); + packet.writeByteArray(light); + + mask.set(section.getY() - getMinSection()); + } + + + return new Pair<>(mask, packet); + } + @Override protected int getMinSection() { return minSectionY; } + @Override protected int getMinBlockSection() { return minBlockSectionY; } + @Override protected int getMaxSection() { return maxBlockSectionY; diff --git a/src/main/java/packets/DataTypeProvider.java b/src/main/java/packets/DataTypeProvider.java index 538a1ac0..317a7b2a 100644 --- a/src/main/java/packets/DataTypeProvider.java +++ b/src/main/java/packets/DataTypeProvider.java @@ -282,4 +282,12 @@ public DataTypeProvider copy() { public int remaining() { return this.finalFullPacket.length - pos; } + + @Override + public String toString() { + return "DataTypeProvider{" + + "finalFullPacket=" + Arrays.toString(finalFullPacket) + + ", pos=" + pos + + '}'; + } } diff --git a/src/main/resources/protocol-versions.json b/src/main/resources/protocol-versions.json index 181cfe44..f211865d 100644 --- a/src/main/resources/protocol-versions.json +++ b/src/main/resources/protocol-versions.json @@ -171,9 +171,9 @@ "0x0A": "ContainerClose" } }, - "1073741859": { - "version": "1.17-rc2", - "dataVersion": 2716, + "755": { + "version": "1.17", + "dataVersion": 2724, "clientBound": { "0x00": "AddEntity", "0x02": "AddMob", diff --git a/src/test/java/game/data/chunk/ChunkTest.java b/src/test/java/game/data/chunk/ChunkTest.java index 9969f948..068cf4b6 100644 --- a/src/test/java/game/data/chunk/ChunkTest.java +++ b/src/test/java/game/data/chunk/ChunkTest.java @@ -7,7 +7,6 @@ import game.data.dimension.Dimension; import org.junit.jupiter.api.Test; import packets.DataTypeProvider; -import packets.builder.PacketBuilder; import packets.builder.PacketBuilderAndParserTest; import java.io.IOException; @@ -55,6 +54,44 @@ private void testFor(int protocolVersion, String dataFile) throws IOException, C assertThat(ChunkFactory.parseChunk(up, mock)).isEqualTo(c); } + /** + * Tests that reading in binary chunk data (as stored in MCA Files), writing it to a network packet and parsing the + * network packet leads to the same block states. Note that this does not ensure that the client is necessarily able + * to understand the chunk, just that it is internally consistent. + */ + private void testForWithLight(int protocolVersion, String dataFile) throws IOException, ClassNotFoundException { + // set up mock + WorldManager mock = mock(WorldManager.class); + when(mock.getBlockColors()).thenReturn(mock(BlockColors.class)); + when(mock.getChunkFactory()).thenReturn(new ChunkFactory()); + + WorldManager.setInstance(mock); + + Config.setInstance(new Config()); + Config.setProtocolVersion(protocolVersion); + + ObjectInputStream in = new ObjectInputStream(ChunkTest.class.getClassLoader().getResourceAsStream(dataFile)); + cb = (ChunkBinary) in.readObject(); + + Chunk c = cb.toChunk(pos); + + builder = c.toPacket(); + DataTypeProvider parser = getParser(); + + CoordinateDim2D coords = new CoordinateDim2D(parser.readInt(), parser.readInt(), pos.getDimension()); + UnparsedChunk up = new UnparsedChunk(coords); + up.provider = parser; + + builder = c.toLightPacket(); + DataTypeProvider lightParser = getParser(); + + Chunk parsed = ChunkFactory.parseChunk(up, mock); + assertThat(lightParser.readVarInt()).isEqualTo(0); + assertThat(lightParser.readVarInt()).isEqualTo(0); + parsed.updateLight(lightParser); + assertThat(parsed).isEqualTo(c); + } + @Test void chunk_1_12() throws IOException, ClassNotFoundException { testFor(340, "chunkdata_1_12"); @@ -115,5 +152,10 @@ void chunk_1_16_light() throws IOException, ClassNotFoundException { assertThat(dst.getChunkSection(0).getSkyLight()).isEqualTo(sky); } + @Test + void chunk_1_17() throws IOException, ClassNotFoundException { + testForWithLight(755, "chunkdata_1_17"); + } + } \ No newline at end of file diff --git a/src/test/java/packets/builder/PacketBuilderAndParserTest.java b/src/test/java/packets/builder/PacketBuilderAndParserTest.java index 6ae97e8c..d2f2552d 100644 --- a/src/test/java/packets/builder/PacketBuilderAndParserTest.java +++ b/src/test/java/packets/builder/PacketBuilderAndParserTest.java @@ -12,6 +12,7 @@ import se.llbit.nbt.*; import java.util.Arrays; +import java.util.BitSet; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -208,6 +209,20 @@ void parseCoordinates() { assertThat(after).isEqualTo(new Coordinate3D(x, y, z)); } + @Test + void parseBit() { + BitSet before = new BitSet(); + before.set(2); + before.set(4); + before.set(6); + before.set(9); + builder.writeBitSet(before); + + BitSet after = getParser().readBitSet(); + + assertThat(after).isEqualTo(before); + } + @Test void parseCoordinatesOther() { long x = 1000; diff --git a/src/test/resources/chunkdata_1_17 b/src/test/resources/chunkdata_1_17 new file mode 100644 index 0000000000000000000000000000000000000000..7f5677e4afd1da5b89d629115ef467da8ce6ad83 GIT binary patch literal 8322 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 Date: Wed, 9 Jun 2021 21:06:50 +0200 Subject: [PATCH 04/11] Update build.yml --- .github/workflows/build.yml | 4 ++-- pom.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 45df8ef3..07746858 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,14 +12,14 @@ jobs: java-version: '8' java-package: jdk+fx - run: | - mvn package + mvn package -DskipTests test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-java@v1 with: - java-version: '8' + java-version: '16' java-package: jdk+fx - run: | mvn test diff --git a/pom.xml b/pom.xml index 4c22aa13..5c49dc6d 100644 --- a/pom.xml +++ b/pom.xml @@ -93,7 +93,7 @@ com.akathist.maven.plugins.launch4j launch4j-maven-plugin - 1.7.25 + 2.1.1 l4j-gui From 1c55254a5c66e2800d0c4f3cb2048003667d9755 Mon Sep 17 00:00:00 2001 From: mircokroon <23699979+mircokroon@users.noreply.github.com> Date: Wed, 9 Jun 2021 21:12:48 +0200 Subject: [PATCH 05/11] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6e4c43b0..b27e0e11 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ Cross-platform jar (GUI & commandline): [world-downloader.jar](https://github.co ### Requirements -- Java 8 or higher -- Minecraft version 1.12.2+ // 1.13.2+ // 1.14.1+ // 1.15.2+ // 1.16.2+ +- Java 16 or higher (Java 8 works for versions up to 1.16.5) +- Minecraft version 1.12.2+ // 1.13.2+ // 1.14.1+ // 1.15.2+ // 1.16.2+ // 1.17+ ### Basic usage [Download](https://github.com/mircokroon/minecraft-world-downloader/releases/latest/download/world-downloader.exe) the latest release and run it. Enter the server address in the address field and press start. Instead of connecting to the server itself, connect to `localhost` in Minecraft to start downloading the world. From 1e07b81cbee793345ac63b4194111e2483298c7c Mon Sep 17 00:00:00 2001 From: Mirco Kroon <23699979+mircokroon@users.noreply.github.com> Date: Thu, 10 Jun 2021 21:30:58 +0200 Subject: [PATCH 06/11] Fixed player maps and item frames on 1.17 --- .../data/entity/metadata/MetaData_1_13.java | 1 + .../game/data/entity/specific/ItemFrame.java | 21 ++++++++++++- src/main/java/game/data/maps/PlayerMap.java | 1 + .../java/game/data/maps/PlayerMap_1_17.java | 30 +++++++++++++++++++ 4 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 src/main/java/game/data/maps/PlayerMap_1_17.java diff --git a/src/main/java/game/data/entity/metadata/MetaData_1_13.java b/src/main/java/game/data/entity/metadata/MetaData_1_13.java index 5dff8e3a..9af95ee1 100644 --- a/src/main/java/game/data/entity/metadata/MetaData_1_13.java +++ b/src/main/java/game/data/entity/metadata/MetaData_1_13.java @@ -13,6 +13,7 @@ public class MetaData_1_13 extends MetaData { private static Map> typeHandlers; static { + // network.syncher.EntityDataSerializers typeHandlers = new HashMap<>(); typeHandlers.put(0, DataTypeProvider::readNext); typeHandlers.put(1, DataTypeProvider::readVarInt); diff --git a/src/main/java/game/data/entity/specific/ItemFrame.java b/src/main/java/game/data/entity/specific/ItemFrame.java index 664a31ab..2761b2d2 100644 --- a/src/main/java/game/data/entity/specific/ItemFrame.java +++ b/src/main/java/game/data/entity/specific/ItemFrame.java @@ -1,5 +1,8 @@ package game.data.entity.specific; +import config.Config; +import config.Option; +import config.Version; import game.data.container.Slot; import game.data.entity.ObjectEntity; import game.data.entity.metadata.MetaData_1_13; @@ -51,7 +54,10 @@ protected void setData(int data) { @Override public void parseMetadata(DataTypeProvider provider) { if (metaData == null) { - metaData = new ItemFrameMetaData(); + metaData = Config.versionReporter().select(ItemFrameMetaData.class, + Option.of(Version.V1_17, ItemFrameMetaData_1_17::new), + Option.of(Version.ANY, ItemFrameMetaData::new) + ); } try { metaData.parse(provider); @@ -76,10 +82,23 @@ public void addNbtTags(CompoundTag nbt) { @Override public Consumer getIndexHandler(int i) { + System.out.println("Item frame index " + i); switch (i) { case 7: return provider -> item = provider.readSlot(); case 8: return provider -> rotation = provider.readVarInt(); } return super.getIndexHandler(i); } +} + +class ItemFrameMetaData_1_17 extends ItemFrameMetaData { + @Override + public Consumer getIndexHandler(int i) { + // order of metadata fields for item frames changed a little bit in 1.17 + switch (i) { + case 7: return provider -> rotation = provider.readVarInt(); + case 8: return provider -> item = provider.readSlot(); + } + return super.getIndexHandler(i); + } } \ No newline at end of file diff --git a/src/main/java/game/data/maps/PlayerMap.java b/src/main/java/game/data/maps/PlayerMap.java index ba0c088e..05b31ba9 100644 --- a/src/main/java/game/data/maps/PlayerMap.java +++ b/src/main/java/game/data/maps/PlayerMap.java @@ -35,6 +35,7 @@ public PlayerMap(int id) { public static PlayerMap getVersioned(int id) { return Config.versionReporter().select(PlayerMap.class, + Option.of(Version.V1_17, () -> new PlayerMap_1_17(id)), Option.of(Version.V1_14, () -> new PlayerMap_1_14(id)), Option.of(Version.V1_12, () -> new PlayerMap_1_12(id)) ); diff --git a/src/main/java/game/data/maps/PlayerMap_1_17.java b/src/main/java/game/data/maps/PlayerMap_1_17.java new file mode 100644 index 00000000..744eab70 --- /dev/null +++ b/src/main/java/game/data/maps/PlayerMap_1_17.java @@ -0,0 +1,30 @@ +package game.data.maps; + +import packets.DataTypeProvider; + +public class PlayerMap_1_17 extends PlayerMap_1_14{ + public PlayerMap_1_17(int id) { + super(id); + } + + @Override + public void parse(DataTypeProvider provider) { + byte scale = provider.readNext(); + if (scale != 0) { + this.scale = scale; + } + + this.locked = provider.readBoolean(); + + + parseIcons(provider); + parseMapImage(provider); + } + + public void parseIcons(DataTypeProvider provider) { + boolean hasIcons = provider.readBoolean(); + if (!hasIcons) { return; } + + super.parseIcons(provider); + } +} From be1bb4940452f797d8d9dcfdbbb5d0b02a373093 Mon Sep 17 00:00:00 2001 From: Mirco Kroon <23699979+mircokroon@users.noreply.github.com> Date: Fri, 11 Jun 2021 16:48:29 +0200 Subject: [PATCH 07/11] Store entities separately in 1.17 --- src/main/java/game/data/WorldManager.java | 24 +++++-- src/main/java/game/data/chunk/Chunk.java | 3 + .../java/game/data/chunk/ChunkBinary.java | 13 +++- .../java/game/data/chunk/ChunkEntities.java | 36 +++++++++- .../game/data/chunk/version/Chunk_1_17.java | 4 ++ .../game/data/entity/specific/ItemFrame.java | 1 - src/main/java/game/data/region/McaFile.java | 65 ++++++++++++------- .../java/game/data/region/McaFilePair.java | 22 +++++++ src/main/java/game/data/region/Region.java | 23 +++++-- 9 files changed, 145 insertions(+), 46 deletions(-) create mode 100644 src/main/java/game/data/region/McaFilePair.java diff --git a/src/main/java/game/data/WorldManager.java b/src/main/java/game/data/WorldManager.java index 86dce8d5..acb93434 100644 --- a/src/main/java/game/data/WorldManager.java +++ b/src/main/java/game/data/WorldManager.java @@ -17,6 +17,7 @@ import game.data.entity.EntityRegistry; import game.data.maps.MapRegistry; import game.data.region.McaFile; +import game.data.region.McaFilePair; import game.data.region.Region; import gui.GuiManager; import org.apache.commons.io.FileUtils; @@ -422,16 +423,13 @@ public void save() { // convert the values to an array first to prevent blocking any threads Region[] r = regions.values().toArray(new Region[0]); for (Region region : r) { - McaFile file = region.toFile(getPlayerPosition().globalToChunk()); - if (file == null) { + McaFilePair files = region.toFile(getPlayerPosition().globalToChunk()); + if (files == null) { continue; } - try { - file.write(); - } catch (IOException e) { - e.printStackTrace(); - } + write(files.getRegion()); + write(files.getEntities()); } } @@ -462,6 +460,18 @@ public void save() { System.gc(); } + private void write(McaFile file) { + if (file == null || file.isEmpty()) { + return; + } + + try { + file.write(); + } catch (IOException e) { + e.printStackTrace(); + } + } + public ContainerManager getContainerManager() { if (containerManager == null) { containerManager = new ContainerManager(); diff --git a/src/main/java/game/data/chunk/Chunk.java b/src/main/java/game/data/chunk/Chunk.java index e2d47f2c..7090f6e6 100644 --- a/src/main/java/game/data/chunk/Chunk.java +++ b/src/main/java/game/data/chunk/Chunk.java @@ -523,4 +523,7 @@ public ChunkState getState() { return new ChunkState(true, isSaved()); } + public boolean hasSeparateEntities() { + return false; + } } \ No newline at end of file diff --git a/src/main/java/game/data/chunk/ChunkBinary.java b/src/main/java/game/data/chunk/ChunkBinary.java index 9418006d..989eea08 100644 --- a/src/main/java/game/data/chunk/ChunkBinary.java +++ b/src/main/java/game/data/chunk/ChunkBinary.java @@ -41,9 +41,7 @@ public ChunkBinary(int timestamp, int location, int size, byte[] chunkData) { * @param chunk the chunk * @return the binary version of the chunk */ - public static ChunkBinary fromChunk(Chunk chunk) throws IOException { - NamedTag nbt = chunk.toNbt(); - + public static ChunkBinary fromChunk(Chunk chunk, NamedTag nbt) throws IOException { // this only happens for empty chunks (hopefully) if (nbt == null) { return null; @@ -89,6 +87,15 @@ public static ChunkBinary fromChunk(Chunk chunk) throws IOException { return binary; } + public static ChunkBinary fromChunk(Chunk chunk) throws IOException { + NamedTag nbt = chunk.toNbt(); + return fromChunk(chunk, nbt); + } + + public static ChunkBinary entitiesFromChunk(Chunk chunk) throws IOException { + NamedTag nbt = chunk.toEntityNbt(); + return fromChunk(chunk, nbt); + } public Chunk toChunk(CoordinateDim2D coordinate2D) { return WorldManager.getInstance().getChunkFactory().fromNbt(getNbt(), coordinate2D); diff --git a/src/main/java/game/data/chunk/ChunkEntities.java b/src/main/java/game/data/chunk/ChunkEntities.java index 9ff6f335..3f18c3ff 100644 --- a/src/main/java/game/data/chunk/ChunkEntities.java +++ b/src/main/java/game/data/chunk/ChunkEntities.java @@ -14,8 +14,8 @@ import se.llbit.nbt.*; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -76,8 +76,13 @@ private void sendInventoryMessage(InventoryWindow tileEntity) { protected void addLevelNbtTags(CompoundTag map) { map.add("TileEntities", new ListTag(Tag.TAG_COMPOUND, new ArrayList<>(tileEntities.values()))); - List entities = WorldManager.getInstance().getEntityRegistry().getEntitiesNbt(this.getLocation()); - map.add("Entities", new ListTag(Tag.TAG_COMPOUND, entities)); + if (!hasSeparateEntities()) { + map.add("Entities", getEntitiesNbt()); + } + } + + private ListTag getEntitiesNbt() { + return new ListTag(Tag.TAG_COMPOUND, WorldManager.getInstance().getEntityRegistry().getEntitiesNbt(this.getLocation())); } @@ -158,4 +163,29 @@ private CompoundTag generateTileEntity(String id, Coordinate3D containerLocation public abstract CoordinateDim2D getLocation(); public abstract BlockState getBlockStateAt(Coordinate3D location); public abstract void touch(); + public abstract boolean hasSeparateEntities(); + public abstract int getDataVersion(); + + + public NamedTag toEntityNbt() { + if (!hasSeparateEntities()) { + return null; + } + + CompoundTag root = new CompoundTag(); + + ListTag entities = new ListTag(Tag.TAG_COMPOUND, WorldManager.getInstance().getEntityRegistry().getEntitiesNbt(this.getLocation())); + if (entities.size() == 0) { + return null; + } + + root.add("Entities", entities); + root.add("DataVersion", new IntTag(getDataVersion())); + root.add("Position", new IntArrayTag(new int[]{ + getLocation().getX(), + getLocation().getZ() + })); + + return new NamedTag("", root); + } } diff --git a/src/main/java/game/data/chunk/version/Chunk_1_17.java b/src/main/java/game/data/chunk/version/Chunk_1_17.java index 9843693e..d3dfa30a 100644 --- a/src/main/java/game/data/chunk/version/Chunk_1_17.java +++ b/src/main/java/game/data/chunk/version/Chunk_1_17.java @@ -198,4 +198,8 @@ protected int getMaxSection() { return maxBlockSectionY; } + @Override + public boolean hasSeparateEntities() { + return true; + } } diff --git a/src/main/java/game/data/entity/specific/ItemFrame.java b/src/main/java/game/data/entity/specific/ItemFrame.java index 2761b2d2..aff8453d 100644 --- a/src/main/java/game/data/entity/specific/ItemFrame.java +++ b/src/main/java/game/data/entity/specific/ItemFrame.java @@ -82,7 +82,6 @@ public void addNbtTags(CompoundTag nbt) { @Override public Consumer getIndexHandler(int i) { - System.out.println("Item frame index " + i); switch (i) { case 7: return provider -> item = provider.readSlot(); case 8: return provider -> rotation = provider.readVarInt(); diff --git a/src/main/java/game/data/region/McaFile.java b/src/main/java/game/data/region/McaFile.java index 6fa97639..02ae126d 100644 --- a/src/main/java/game/data/region/McaFile.java +++ b/src/main/java/game/data/region/McaFile.java @@ -27,17 +27,52 @@ public class McaFile { private HashMap chunkMap; private final Path filePath; private final Coordinate2D regionLocation; + private final boolean isEntityFile; + /** * Parse MCA from a given file location. * @param file the MCA file to be used */ - public McaFile(File file) throws IOException { + public McaFile(File file, boolean isEntityFile) throws IOException { + this.isEntityFile = isEntityFile; + chunkMap = readFile(file); filePath = PathUtils.toPath(file.getAbsolutePath()); String[] bits = file.getName().split("\\."); regionLocation = new Coordinate2D(Integer.parseInt(bits[1]), Integer.parseInt(bits[2])); } + public McaFile(File file) throws IOException { + this(file, false); + } + + /** + * Generate an MCA file from a given map of chunk binaries. This method will try to read this MCA file to merge with + * it so that existing chunks are not deleted. + * @param pos the positon of this file + */ + public McaFile(CoordinateDim2D pos, boolean isEntityFile) { + this.isEntityFile = isEntityFile; + regionLocation = pos.offsetRegion(); + + String filename = "r." + regionLocation.getX() + "." + regionLocation.getZ() + ".mca"; + String directory = this.isEntityFile ? "entities" : "region"; + Path filePath = PathUtils.toPath(Config.getWorldOutputDir(), pos.getDimension().getPath(), directory, filename); + + this.chunkMap = new HashMap<>(); + if (filePath.toFile().exists()) { + try { + this.chunkMap = readFile(filePath.toFile()); + } catch (IOException e) { + // fail silently, we will just overwrite the file instead + } + } + + this.filePath = filePath; + } + public McaFile(CoordinateDim2D pos) { + this(pos, false); + } public static File coordinatesToFile(Path dir, Coordinate2D coords) { String name = "r." + coords.getX() + "." + coords.getZ() + ".mca"; @@ -216,29 +251,6 @@ private static int bytesToInt(byte[] arr, int start, int end) { return res; } - /** - * Generate an MCA file from a given map of chunk binaries. This method will try to read this MCA file to merge with - * it so that existing chunks are not deleted. - * @param pos the positon of this file - */ - public McaFile(CoordinateDim2D pos) { - regionLocation = pos.offsetRegion(); - - String filename = "r." + regionLocation.getX() + "." + regionLocation.getZ() + ".mca"; - Path filePath = PathUtils.toPath(Config.getWorldOutputDir(),pos.getDimension().getPath(), "region", filename); - - this.chunkMap = new HashMap<>(); - if (filePath.toFile().exists()) { - try { - this.chunkMap = readFile(filePath.toFile()); - } catch (IOException e) { - // fail silently, we will just overwrite the file instead - } - } - - this.filePath = filePath; - } - public void addChunks(Map chunkMap) { // merge new chunks into existing ones chunkMap.forEach((key, value) -> this.chunkMap.put(key, value)); @@ -270,7 +282,6 @@ public void write() throws IOException { // create directory if it doesn't already exist Files.createDirectories(filePath.getParent()); - Files.write(filePath, toWrite); } @@ -374,4 +385,8 @@ public ChunkBinary getChunkBinary(Coordinate2D coord) { public int countChunks() { return chunkMap.size(); } + + public boolean isEmpty() { + return chunkMap.isEmpty(); + } } diff --git a/src/main/java/game/data/region/McaFilePair.java b/src/main/java/game/data/region/McaFilePair.java new file mode 100644 index 00000000..8eba0cad --- /dev/null +++ b/src/main/java/game/data/region/McaFilePair.java @@ -0,0 +1,22 @@ +package game.data.region; + +/** + * Class to hold the combination of entity and region MCA files for. + */ +public class McaFilePair { + McaFile region; + McaFile entities; + + public McaFilePair(McaFile region, McaFile entities) { + this.region = region; + this.entities = entities; + } + + public McaFile getRegion() { + return region; + } + + public McaFile getEntities() { + return entities; + } +} diff --git a/src/main/java/game/data/region/Region.java b/src/main/java/game/data/region/Region.java index 2cb0b4af..51e7881e 100644 --- a/src/main/java/game/data/region/Region.java +++ b/src/main/java/game/data/region/Region.java @@ -30,6 +30,7 @@ public class Region { private final Set toDelete; private final McaFile file; + private final McaFile fileEntities; /** * Initialise the region with the given coordinates. @@ -42,6 +43,7 @@ public Region(CoordinateDim2D regionCoordinates) { this.toDelete = new HashSet<>(); this.file = new McaFile(regionCoordinates); + this.fileEntities = new McaFile(regionCoordinates, true); } /** @@ -109,7 +111,7 @@ public Chunk getChunk(Coordinate2D coordinate) { * been saved. Will update the Gui with the chunk that's about to be saved. * @return the McaFile corresponding to this region */ - public McaFile toFile(Coordinate2D playerPos) { + public McaFilePair toFile(Coordinate2D playerPos) { if (!updatedSinceLastWrite) { return null; } @@ -117,6 +119,7 @@ public McaFile toFile(Coordinate2D playerPos) { updatedSinceLastWrite = false; Map chunkBinaryMap = new HashMap<>(); + Map chunkEntityBinaryMap = new HashMap<>(); chunks.keySet().forEach(coordinate -> { try { Chunk chunk = chunks.get(coordinate); @@ -137,14 +140,19 @@ public McaFile toFile(Coordinate2D playerPos) { // get the chunk in binary format and get its coordinates as an Mca compatible integer. Then add // these to the map of chunk binaries. ChunkBinary binary = ChunkBinary.fromChunk(chunk); - - if (binary == null) { - return; + ChunkBinary entityBinary = null; + if (chunk.hasSeparateEntities()) { + entityBinary = ChunkBinary.entitiesFromChunk(chunk); } Coordinate2D localCoordinate = coordinate.toRegionLocal(); int pos = 4 * ((localCoordinate.getX() & 31) + (localCoordinate.getZ() & 31) * 32); - chunkBinaryMap.put(pos, binary); + if (binary != null) { + chunkBinaryMap.put(pos, binary); + } + if (entityBinary != null) { + chunkEntityBinaryMap.put(pos, entityBinary); + } } catch (Exception e) { e.printStackTrace(); } @@ -157,12 +165,13 @@ public McaFile toFile(Coordinate2D playerPos) { } toDelete.clear(); - if (chunkBinaryMap.isEmpty()) { + if (chunkBinaryMap.isEmpty() && chunkEntityBinaryMap.isEmpty()) { return null; } file.addChunks(chunkBinaryMap); - return file; + fileEntities.addChunks(chunkEntityBinaryMap); + return new McaFilePair(file, fileEntities); } public McaFile getFile() { From 53eea6f2156f050c73b6677009f427e07eb38421 Mon Sep 17 00:00:00 2001 From: Mirco Kroon <23699979+mircokroon@users.noreply.github.com> Date: Fri, 11 Jun 2021 20:09:47 +0200 Subject: [PATCH 08/11] Fixed issues with invalid chunks in earlier versions --- src/main/java/config/Version.java | 11 ++++++----- src/main/java/game/data/chunk/Chunk.java | 19 +++++++++++-------- .../game/data/chunk/version/Chunk_1_14.java | 2 +- .../java/game/data/region/McaFilePair.java | 2 +- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/main/java/config/Version.java b/src/main/java/config/Version.java index 74a03734..1b508023 100644 --- a/src/main/java/config/Version.java +++ b/src/main/java/config/Version.java @@ -1,11 +1,12 @@ package config; public enum Version { - V1_12(317, 1022), - V1_13(341, 1444), - V1_14(440, 1901), - V1_15(550, 2200), - V1_16(701, 2504), + // version numbers correspond to the earlier full release + V1_12(317, 1139), + V1_13(341, 1519), + V1_14(440, 1952), + V1_15(550, 2225), + V1_16(701, 2578), V1_17(755, 2724), ANY(0, 0); diff --git a/src/main/java/game/data/chunk/Chunk.java b/src/main/java/game/data/chunk/Chunk.java index 7090f6e6..b5e3dbbd 100644 --- a/src/main/java/game/data/chunk/Chunk.java +++ b/src/main/java/game/data/chunk/Chunk.java @@ -110,19 +110,22 @@ public void whenParsed(Runnable r) { * Read a chunk column. Largely based on: https://wiki.vg/Protocol */ public void readChunkColumn(boolean full, BitSet mask, DataTypeProvider dataProvider) { - // We shift the mask left each iteration and check the unit bit. If the mask is 0, there will be no more chunks - // so can stop the loop early. + // Loop through section Y values, starting from the lowest section that has blocks inside it. Compute the index + // in the mask by subtracting the minimum chunk packet section, e.g. the lowest Y value we will find in the + // mask. for (int sectionY = getMinBlockSection(); sectionY <= getMaxSection() && !mask.isEmpty(); sectionY++) { ChunkSection section = getChunkSection(sectionY); - // Mask tells us if a section is present or not - if (!mask.get(sectionY - getMinBlockSection())) { + // A 1 in the position of the mask indicates this chunk section is present in the data buffer + int maskIndex = sectionY - getMinBlockSection(); + if (!mask.get(maskIndex)) { if (full && section != null) { section.resetBlocks(); } continue; } - mask.set(sectionY - getMinBlockSection(), false); + // Set indices to 0 when read so that we can stop once the mask is empty + mask.set(maskIndex, false); readBlockCount(dataProvider); @@ -354,7 +357,7 @@ protected void writeHeightMaps(PacketBuilder packet) { protected PacketBuilder writeSectionData() { PacketBuilder column = new PacketBuilder(); for (ChunkSection section : getAllSections()) { - if (section.getY() >= getMinSection()) { + if (section.getY() >= getMinBlockSection()) { section.write(column); } } @@ -365,8 +368,8 @@ protected PacketBuilder writeSectionData() { private void writeBitMask(PacketBuilder packet) { int res = 0; for (ChunkSection section : getAllSections()) { - if (section.getY() >= getMinSection()) { - res |= 1 << (section.getY() - getMinSection()); + if (section.getY() >= getMinBlockSection()) { + res |= 1 << section.getY() - getMinBlockSection(); } } diff --git a/src/main/java/game/data/chunk/version/Chunk_1_14.java b/src/main/java/game/data/chunk/version/Chunk_1_14.java index cdbc360a..adaa1858 100644 --- a/src/main/java/game/data/chunk/version/Chunk_1_14.java +++ b/src/main/java/game/data/chunk/version/Chunk_1_14.java @@ -60,7 +60,7 @@ protected int getMinSection() { @Override protected int getMinBlockSection() { - return -1; + return 0; } @Override diff --git a/src/main/java/game/data/region/McaFilePair.java b/src/main/java/game/data/region/McaFilePair.java index 8eba0cad..067e94e2 100644 --- a/src/main/java/game/data/region/McaFilePair.java +++ b/src/main/java/game/data/region/McaFilePair.java @@ -1,7 +1,7 @@ package game.data.region; /** - * Class to hold the combination of entity and region MCA files for. + * Class to hold the combination of entity and region MCA files for. */ public class McaFilePair { McaFile region; From 5d8e458f42dc27981dbd3ee3e875a3cde579d1c0 Mon Sep 17 00:00:00 2001 From: Mirco Kroon <23699979+mircokroon@users.noreply.github.com> Date: Fri, 11 Jun 2021 20:29:56 +0200 Subject: [PATCH 09/11] Added comment --- src/main/java/game/data/chunk/ChunkEntities.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/game/data/chunk/ChunkEntities.java b/src/main/java/game/data/chunk/ChunkEntities.java index 3f18c3ff..6eeeb53d 100644 --- a/src/main/java/game/data/chunk/ChunkEntities.java +++ b/src/main/java/game/data/chunk/ChunkEntities.java @@ -167,6 +167,10 @@ private CompoundTag generateTileEntity(String id, Coordinate3D containerLocation public abstract int getDataVersion(); + /** + * For 1.17+, entities are stored separately from blocks and tile entities. This method constructs the NBT object + * of just the entity file. + */ public NamedTag toEntityNbt() { if (!hasSeparateEntities()) { return null; From ab3b0c17d4c8d89da37f321a32da4835c4dd5821 Mon Sep 17 00:00:00 2001 From: Mirco Kroon <23699979+mircokroon@users.noreply.github.com> Date: Fri, 11 Jun 2021 20:39:18 +0200 Subject: [PATCH 10/11] Fixed broken tests --- src/main/java/config/Version.java | 10 +++++----- src/test/java/game/data/chunk/ChunkTest.java | 17 ++++++++--------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/main/java/config/Version.java b/src/main/java/config/Version.java index 1b508023..98e67ee6 100644 --- a/src/main/java/config/Version.java +++ b/src/main/java/config/Version.java @@ -1,11 +1,11 @@ package config; public enum Version { - // version numbers correspond to the earlier full release - V1_12(317, 1139), - V1_13(341, 1519), - V1_14(440, 1952), - V1_15(550, 2225), + // version numbers correspond to the earliest full release + V1_12(317, 1132), + V1_13(341, 1444), + V1_14(440, 1901), + V1_15(550, 2200), V1_16(701, 2578), V1_17(755, 2724), ANY(0, 0); diff --git a/src/test/java/game/data/chunk/ChunkTest.java b/src/test/java/game/data/chunk/ChunkTest.java index 068cf4b6..8f08d5c2 100644 --- a/src/test/java/game/data/chunk/ChunkTest.java +++ b/src/test/java/game/data/chunk/ChunkTest.java @@ -1,6 +1,7 @@ package game.data.chunk; import config.Config; +import config.Version; import game.data.coordinates.CoordinateDim2D; import game.data.WorldManager; import game.data.chunk.palette.BlockColors; @@ -94,32 +95,32 @@ private void testForWithLight(int protocolVersion, String dataFile) throws IOExc @Test void chunk_1_12() throws IOException, ClassNotFoundException { - testFor(340, "chunkdata_1_12"); + testFor(Version.V1_12.protocolVersion, "chunkdata_1_12"); } @Test void chunk_1_13() throws IOException, ClassNotFoundException { - testFor(404, "chunkdata_1_13"); + testFor(Version.V1_13.protocolVersion, "chunkdata_1_13"); } @Test void chunk_1_14() throws IOException, ClassNotFoundException { - testFor(498, "chunkdata_1_14"); + testFor(Version.V1_14.protocolVersion, "chunkdata_1_14"); } @Test void chunk_1_15() throws IOException, ClassNotFoundException { - testFor(578, "chunkdata_1_15"); + testFor(Version.V1_15.protocolVersion, "chunkdata_1_15"); } @Test void chunk_1_16() throws IOException, ClassNotFoundException { - testFor(751, "chunkdata_1_16"); + testFor(Version.V1_16.protocolVersion, "chunkdata_1_16"); } @Test void chunk_1_16_light() throws IOException, ClassNotFoundException { - testFor(751, "chunkdata_1_16"); + testFor(Version.V1_16.protocolVersion, "chunkdata_1_16"); int trueX = -100; int trueZ = 100; @@ -154,8 +155,6 @@ void chunk_1_16_light() throws IOException, ClassNotFoundException { @Test void chunk_1_17() throws IOException, ClassNotFoundException { - testForWithLight(755, "chunkdata_1_17"); + testForWithLight(Version.V1_17.protocolVersion, "chunkdata_1_17"); } - - } \ No newline at end of file From 9c9161a34a0068b0cbd1de87241caa83f326d08e Mon Sep 17 00:00:00 2001 From: Mirco Kroon <23699979+mircokroon@users.noreply.github.com> Date: Fri, 11 Jun 2021 21:01:15 +0200 Subject: [PATCH 11/11] Prevent broken level.dat from spamming the console #159 --- src/main/java/game/data/LevelData.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/java/game/data/LevelData.java b/src/main/java/game/data/LevelData.java index ea8b9682..e883b4fe 100644 --- a/src/main/java/game/data/LevelData.java +++ b/src/main/java/game/data/LevelData.java @@ -24,11 +24,12 @@ import java.util.stream.Collectors; public class LevelData { - WorldManager worldManager; - Path outputDir; - File file; - Tag root; - CompoundTag data; + private final WorldManager worldManager; + private final Path outputDir; + private final File file; + private Tag root; + private CompoundTag data; + private boolean savingBroken; public LevelData(WorldManager worldManager) { this.worldManager = worldManager; @@ -91,6 +92,13 @@ private void load(boolean forceInternal) throws IOException { * the resource folder. */ public void save() throws IOException { + if (savingBroken) { return; } + if (data == null) { + savingBroken = true; + System.err.println("Unable to read in valid 'level.dat' file. Chunks will be saved, but they cannot be opened in-game without manually providing a 'level.dat' file."); + return; + } + // add the player's position if (worldManager.getPlayerPosition() != null) { Tag playerTag = data.get("Player");