diff --git a/src/main/java/config/Version.java b/src/main/java/config/Version.java index 8723162c..fcea1f89 100644 --- a/src/main/java/config/Version.java +++ b/src/main/java/config/Version.java @@ -12,6 +12,8 @@ public enum Version { V1_19(759, 3105), V1_19_3(761, 3218), V1_20(763, 3463), + V1_20_2(764, 3578), + V1_20_3(765, 3698), ANY(0, 0); public final int dataVersion; diff --git a/src/main/java/game/NetworkMode.java b/src/main/java/game/NetworkMode.java index cd264283..40fcf1da 100644 --- a/src/main/java/game/NetworkMode.java +++ b/src/main/java/game/NetworkMode.java @@ -4,20 +4,6 @@ public enum NetworkMode { HANDSHAKE, STATUS, LOGIN, - GAME; - - @Override - public String toString() { - switch (this) { - case HANDSHAKE: - return "HANDSHAKE"; - case STATUS: - return "STATUS"; - case LOGIN: - return "LOGIN"; - case GAME: - return "GAME"; - } - return ""; - } + GAME, + CONFIGURATION; } diff --git a/src/main/java/game/data/chunk/version/Chunk_1_18.java b/src/main/java/game/data/chunk/version/Chunk_1_18.java index 073b2adb..fa55e2b8 100644 --- a/src/main/java/game/data/chunk/version/Chunk_1_18.java +++ b/src/main/java/game/data/chunk/version/Chunk_1_18.java @@ -133,7 +133,7 @@ public void readChunkColumn(DataTypeProvider dataProvider) { } } - private void findBlockEntities(ChunkSection section, int sectionY) { + protected void findBlockEntities(ChunkSection section, int sectionY) { BlockEntityRegistry blockEntities = RegistryManager.getInstance().getBlockEntityRegistry(); GlobalPalette globalPalette = GlobalPaletteProvider.getGlobalPalette(getDataVersion()); @@ -151,7 +151,7 @@ private void findBlockEntities(ChunkSection section, int sectionY) { } } - private boolean containsBlockEntities(Palette p) { + protected boolean containsBlockEntities(Palette p) { BlockEntityRegistry blockEntities = RegistryManager.getInstance().getBlockEntityRegistry(); for (SpecificTag tag : p.toNbt()) { if (blockEntities.isBlockEntity(tag.get("Name").stringValue())) { diff --git a/src/main/java/game/data/dimension/DimensionCodec.java b/src/main/java/game/data/dimension/DimensionCodec.java index b0ea1e7b..5c7ea402 100644 --- a/src/main/java/game/data/dimension/DimensionCodec.java +++ b/src/main/java/game/data/dimension/DimensionCodec.java @@ -4,7 +4,7 @@ import game.data.chunk.palette.StateProvider; import se.llbit.nbt.*; -import java.io.*; +import java.io.IOException; import java.nio.file.Path; import java.util.Collection; import java.util.HashMap; @@ -16,6 +16,7 @@ */ public class DimensionCodec { public static final Gson GSON; + static { /* * To convert the properties to JSON, we need to register adapters so that GSON knows how to turn our NBT object @@ -56,6 +57,7 @@ public class DimensionCodec { private final Map dimensionTypesByHash; private final Map dimensionTypesByName; private final Map biomes; + private DimensionCodec() { this.dimensions = new HashMap<>(); this.dimensionTypesByHash = new HashMap<>(); @@ -63,16 +65,20 @@ private DimensionCodec() { this.biomes = new HashMap<>(); } - public static DimensionCodec fromNbt(String[] dimensionNames, SpecificTag tag) { + public static DimensionCodec fromNbt(SpecificTag tag) { DimensionCodec codec = new DimensionCodec(); - codec.readDimensions(dimensionNames); codec.readDimensionTypes(tag.get("minecraft:dimension_type").asCompound().get("value").asList()); codec.readBiomes(tag.get("minecraft:worldgen/biome").asCompound().get("value").asList()); return codec; } + public DimensionCodec setDimensionNames(String[] dimensionNames) { + this.readDimensions(dimensionNames); + return this; + } + public Collection getDimensions() { return dimensions.values(); } @@ -99,7 +105,7 @@ private void readDimensionTypes(ListTag dimensionList) { String[] parts = identifier.split(":"); String namespace = parts[0]; String name = parts[1]; - + DimensionType type = new DimensionType(namespace, name, d); this.dimensionTypesByHash.put(type.getSignature(), type); this.dimensionTypesByName.put(type.getName(), type); diff --git a/src/main/java/game/data/entity/EntityRegistry.java b/src/main/java/game/data/entity/EntityRegistry.java index 47f397eb..873e48c4 100644 --- a/src/main/java/game/data/entity/EntityRegistry.java +++ b/src/main/java/game/data/entity/EntityRegistry.java @@ -2,11 +2,7 @@ import static util.ExceptionHandling.attempt; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -18,11 +14,12 @@ import game.data.coordinates.CoordinateDim2D; import game.data.entity.specific.Villager; import packets.DataTypeProvider; +import packets.UUID; import se.llbit.nbt.SpecificTag; public class EntityRegistry { - private final Map players; + private final Map players; private final Map> perChunk; private final Map entities; private final WorldManager worldManager; @@ -73,7 +70,6 @@ public void addEntity(DataTypeProvider provider, Function markUnsaved(pos.globalToDimChunk())); } })); @@ -81,8 +77,64 @@ public void addEntity(DataTypeProvider provider, Function attempt(() -> { - int entId = provider.readVarInt(); - players.put(entId, PlayerEntity.parse(provider)); + PlayerEntity player = PlayerEntity.parse(provider); + players.put(player.getUUID(), player); + })); + } + + public void updatePlayerAction(DataTypeProvider provider) { + executor.execute(() -> attempt(() -> { + byte actions = provider.readNext(); + int playerCnt = provider.readVarInt(); + + for (int i = 0; i < playerCnt; i++) { + UUID uuid = provider.readUUID(); + + if ((actions & 0x01) > 0) { + PlayerEntity player = new PlayerEntity(uuid); + players.put(uuid, player); + + String name = provider.readString(); + int properties = provider.readVarInt(); + for (int j = 0; j < properties; j++) { + provider.readString(); + provider.readString(); + boolean signed = provider.readBoolean(); + if (signed) provider.readString(); + } + } + + if ((actions & 0x02) > 0) { + boolean signature = provider.readBoolean(); + if (signature) { + provider.readUUID(); + provider.readLong(); + int encKeySz = provider.readVarInt(); + provider.readByteArray(encKeySz); + int pubKeySz = provider.readVarInt(); + provider.readByteArray(pubKeySz); + } + } + + if ((actions & 0x04) > 0) { + provider.readVarInt(); + } + + if ((actions & 0x08) > 0) { + provider.readBoolean(); + } + + if ((actions & 0x10) > 0) { + provider.readVarInt(); + } + + if ((actions & 0x20) > 0) { + boolean displayName = provider.readBoolean(); + if (displayName) { + provider.readChat(); + } + } + } })); } @@ -139,12 +191,14 @@ public void updatePositionAbsolute(DataTypeProvider provider) { } public IMovableEntity getMovableEntity(int entId) { - IMovableEntity ent = players.get(entId); + Entity tmpEnt = entities.get(entId); + if (tmpEnt == null) return null; + IMovableEntity ent = players.get(tmpEnt.uuid); if (ent != null) { return ent; } - return entities.get(entId); + return tmpEnt; } public List getEntitiesNbt(CoordinateDim2D location) { @@ -183,9 +237,8 @@ public void destroyEntities(DataTypeProvider provider) { while (count-- > 0) { int id = provider.readVarInt(); if (entities.containsKey(id)) { + players.remove(entities.get(id).uuid); entities.remove(id); - } else { - players.remove(id); } } } diff --git a/src/main/java/game/data/entity/PlayerEntity.java b/src/main/java/game/data/entity/PlayerEntity.java index 7d89b005..6103d8a6 100644 --- a/src/main/java/game/data/entity/PlayerEntity.java +++ b/src/main/java/game/data/entity/PlayerEntity.java @@ -17,9 +17,12 @@ public class PlayerEntity implements IMovableEntity { private boolean hasRequestedName = false; private String name; + PlayerEntity(UUID uuid) { + this.uuid = uuid; + } + public static PlayerEntity parse(DataTypeProvider provider) { - PlayerEntity ent = new PlayerEntity(); - ent.uuid = provider.readUUID(); + PlayerEntity ent = new PlayerEntity(provider.readUUID()); ent.readPosition(provider); return ent; @@ -86,4 +89,8 @@ public String getName() { } return name; } + + public UUID getUUID() { + return uuid; + } } diff --git a/src/main/java/game/protocol/ConfigurationProtocol.java b/src/main/java/game/protocol/ConfigurationProtocol.java new file mode 100644 index 00000000..2bbfa1dd --- /dev/null +++ b/src/main/java/game/protocol/ConfigurationProtocol.java @@ -0,0 +1,35 @@ +package game.protocol; + +import config.Config; +import config.Version; + +import java.util.HashMap; +import java.util.Map; + +public class ConfigurationProtocol extends Protocol { + private final Map clientBound; + private final Map serverBound; + + public ConfigurationProtocol() { + clientBound = new HashMap<>(); + serverBound = new HashMap<>(); + + if (Config.versionReporter().isAtLeast(Version.V1_20_2)) { + serverBound.put(0x02, "FinishConfiguration"); + + clientBound.put(0x05, "RegistryData"); + } else { + serverBound.put(0x03, "FinishConfiguration"); + } + } + + @Override + protected String clientBound(int packet) { + return clientBound.getOrDefault(packet, "UNKNOWN"); + } + + @Override + protected String serverBound(int packet) { + return serverBound.getOrDefault(packet, "UNKNOWN"); + } +} diff --git a/src/main/java/game/protocol/HandshakeProtocol.java b/src/main/java/game/protocol/HandshakeProtocol.java index e08165f4..0bc169c6 100644 --- a/src/main/java/game/protocol/HandshakeProtocol.java +++ b/src/main/java/game/protocol/HandshakeProtocol.java @@ -4,12 +4,10 @@ import java.util.Map; public class HandshakeProtocol extends Protocol { - private String version; - private Map clientBound; - private Map serverBound; + private final Map clientBound; + private final Map serverBound; public HandshakeProtocol() { - version = "LOGIN"; clientBound = new HashMap<>(); serverBound = new HashMap<>(); diff --git a/src/main/java/game/protocol/LoginProtocol.java b/src/main/java/game/protocol/LoginProtocol.java index e5899bdf..ccf0e144 100644 --- a/src/main/java/game/protocol/LoginProtocol.java +++ b/src/main/java/game/protocol/LoginProtocol.java @@ -4,12 +4,10 @@ import java.util.Map; public class LoginProtocol extends Protocol { - private String version; - private Map clientBound; - private Map serverBound; + private final Map clientBound; + private final Map serverBound; public LoginProtocol() { - version = "LOGIN"; clientBound = new HashMap<>(); serverBound = new HashMap<>(); diff --git a/src/main/java/game/protocol/StatusProtocol.java b/src/main/java/game/protocol/StatusProtocol.java index b669258e..eae97023 100644 --- a/src/main/java/game/protocol/StatusProtocol.java +++ b/src/main/java/game/protocol/StatusProtocol.java @@ -4,12 +4,10 @@ import java.util.Map; public class StatusProtocol extends Protocol { - private String version; - private Map clientBound; - private Map serverBound; + private final Map clientBound; + private final Map serverBound; public StatusProtocol() { - version = "LOGIN"; clientBound = new HashMap<>(); serverBound = new HashMap<>(); } diff --git a/src/main/java/packets/DataTypeProvider.java b/src/main/java/packets/DataTypeProvider.java index 24a411dc..2a5cd7d0 100644 --- a/src/main/java/packets/DataTypeProvider.java +++ b/src/main/java/packets/DataTypeProvider.java @@ -9,6 +9,7 @@ import game.data.coordinates.CoordinateDouble3D; import packets.version.DataTypeProvider_1_13; import packets.version.DataTypeProvider_1_14; +import packets.version.DataTypeProvider_1_20_2; import se.llbit.nbt.NamedTag; import se.llbit.nbt.SpecificTag; @@ -37,6 +38,7 @@ public DataTypeProvider(byte[] finalFullPacket) { public static DataTypeProvider ofPacket(byte[] finalFullPacket) { return Config.versionReporter().select(DataTypeProvider.class, + Option.of(Version.V1_20_2, () -> new DataTypeProvider_1_20_2(finalFullPacket)), Option.of(Version.V1_14, () -> new DataTypeProvider_1_14(finalFullPacket)), Option.of(Version.V1_13, () -> new DataTypeProvider_1_13(finalFullPacket)), Option.of(Version.ANY, () -> new DataTypeProvider(finalFullPacket)) @@ -223,7 +225,7 @@ public double readDouble() { public UUID readUUID() { return new UUID(readLong(), readLong()); } - + public UUID readOptUUID() { if (readBoolean()) { return readUUID(); diff --git a/src/main/java/packets/builder/PacketBuilder.java b/src/main/java/packets/builder/PacketBuilder.java index 53e31292..c7ba2c83 100644 --- a/src/main/java/packets/builder/PacketBuilder.java +++ b/src/main/java/packets/builder/PacketBuilder.java @@ -199,6 +199,7 @@ public void writeBoolean(boolean val) { /** * Writes an NBT tag. We need to wrap this in a NamedTag, as the named tag is not written itself. + * TODO: update on 1.20.2 */ public void writeNbt(SpecificTag nbt) { try { diff --git a/src/main/java/packets/handler/ClientBoundConfigurationPacketHandler.java b/src/main/java/packets/handler/ClientBoundConfigurationPacketHandler.java new file mode 100644 index 00000000..2166ae5c --- /dev/null +++ b/src/main/java/packets/handler/ClientBoundConfigurationPacketHandler.java @@ -0,0 +1,35 @@ +package packets.handler; + +import config.Config; +import config.Option; +import config.Version; +import packets.handler.version.ClientBoundConfigurationPacketHandler_1_20_2; +import proxy.ConnectionManager; + +import java.util.HashMap; +import java.util.Map; + +public class ClientBoundConfigurationPacketHandler extends PacketHandler { + private final HashMap operations = new HashMap<>(); + + public ClientBoundConfigurationPacketHandler(ConnectionManager connectionManager) { + super(connectionManager); + } + + public static PacketHandler of(ConnectionManager connectionManager) { + return Config.versionReporter().select(PacketHandler.class, + Option.of(Version.V1_20_2, () -> new ClientBoundConfigurationPacketHandler_1_20_2(connectionManager)), + Option.of(Version.ANY, () -> new ClientBoundConfigurationPacketHandler(connectionManager)) + ); + } + + @Override + public Map getOperators() { + return operations; + } + + @Override + public boolean isClientBound() { + return true; + } +} diff --git a/src/main/java/packets/handler/ClientBoundGamePacketHandler.java b/src/main/java/packets/handler/ClientBoundGamePacketHandler.java index 74542ab9..3474e6ae 100644 --- a/src/main/java/packets/handler/ClientBoundGamePacketHandler.java +++ b/src/main/java/packets/handler/ClientBoundGamePacketHandler.java @@ -13,12 +13,7 @@ import game.data.entity.EntityRegistry; import game.data.entity.MobEntity; import game.data.entity.ObjectEntity; -import packets.handler.version.ClientBoundGamePacketHandler_1_14; -import packets.handler.version.ClientBoundGamePacketHandler_1_15; -import packets.handler.version.ClientBoundGamePacketHandler_1_16; -import packets.handler.version.ClientBoundGamePacketHandler_1_17; -import packets.handler.version.ClientBoundGamePacketHandler_1_18; -import packets.handler.version.ClientBoundGamePacketHandler_1_19; +import packets.handler.version.*; import packets.handler.plugins.PluginChannelHandler; import proxy.ConnectionManager; import se.llbit.nbt.SpecificTag; @@ -184,6 +179,7 @@ public ClientBoundGamePacketHandler(ConnectionManager connectionManager) { public static PacketHandler of(ConnectionManager connectionManager) { return Config.versionReporter().select(PacketHandler.class, + Option.of(Version.V1_20_2, () -> new ClientBoundGamePacketHandler_1_20_2(connectionManager)), Option.of(Version.V1_19, () -> new ClientBoundGamePacketHandler_1_19(connectionManager)), Option.of(Version.V1_18, () -> new ClientBoundGamePacketHandler_1_18(connectionManager)), Option.of(Version.V1_17, () -> new ClientBoundGamePacketHandler_1_17(connectionManager)), diff --git a/src/main/java/packets/handler/ClientBoundLoginPacketHandler.java b/src/main/java/packets/handler/ClientBoundLoginPacketHandler.java index 2454828e..6251c643 100644 --- a/src/main/java/packets/handler/ClientBoundLoginPacketHandler.java +++ b/src/main/java/packets/handler/ClientBoundLoginPacketHandler.java @@ -35,7 +35,12 @@ public ClientBoundLoginPacketHandler(ConnectionManager connectionManager) { String username = provider.readString(); System.out.println("Login success: " + username + " logged in with uuid " + uuid); - getConnectionManager().setMode(NetworkMode.GAME); + + if (Config.versionReporter().isAtLeast(Version.V1_20_2)) { + getConnectionManager().setMode(NetworkMode.CONFIGURATION); + } else { + getConnectionManager().setMode(NetworkMode.GAME); + } return true; }); operations.put("set_compression", provider -> { diff --git a/src/main/java/packets/handler/PacketHandler.java b/src/main/java/packets/handler/PacketHandler.java index 000bf264..faf1b645 100644 --- a/src/main/java/packets/handler/PacketHandler.java +++ b/src/main/java/packets/handler/PacketHandler.java @@ -6,8 +6,8 @@ import packets.DataTypeProvider; import proxy.ConnectionManager; -import java.util.Map; import javax.naming.SizeLimitExceededException; +import java.util.Map; /** * Family of classes to handle incoming packets and perform appropriate actions based on the packet type and contents. @@ -34,6 +34,7 @@ protected ConnectionManager getConnectionManager() { /** * Build the given packet, will generate a type provider to parse the contents of the packages to real values. Will * determine if the packet is to be forwarded using its return value. + * * @param size the size of the packet to build * @return true if the packet should be forwarded, otherwise false. */ @@ -58,6 +59,7 @@ public final boolean handle(int size) { } public abstract Map getOperators(); + public abstract boolean isClientBound(); public void setReader(DataProvider reader) { diff --git a/src/main/java/packets/handler/ServerBoundConfigurationPacketHandler.java b/src/main/java/packets/handler/ServerBoundConfigurationPacketHandler.java new file mode 100644 index 00000000..e28cd5da --- /dev/null +++ b/src/main/java/packets/handler/ServerBoundConfigurationPacketHandler.java @@ -0,0 +1,29 @@ +package packets.handler; + +import game.NetworkMode; +import java.util.HashMap; +import java.util.Map; +import proxy.ConnectionManager; + +public class ServerBoundConfigurationPacketHandler extends PacketHandler { + private HashMap operations = new HashMap<>(); + + public ServerBoundConfigurationPacketHandler(ConnectionManager connectionManager) { + super(connectionManager); + + operations.put("FinishConfiguration", provider -> { + getConnectionManager().setMode(NetworkMode.GAME); + return true; + }); + } + + @Override + public Map getOperators() { + return operations; + } + + @Override + public boolean isClientBound() { + return false; + } +} diff --git a/src/main/java/packets/handler/ServerBoundGamePacketHandler.java b/src/main/java/packets/handler/ServerBoundGamePacketHandler.java index db009495..c941c951 100644 --- a/src/main/java/packets/handler/ServerBoundGamePacketHandler.java +++ b/src/main/java/packets/handler/ServerBoundGamePacketHandler.java @@ -1,6 +1,7 @@ package packets.handler; import config.Version; +import game.NetworkMode; import java.util.HashMap; import java.util.Map; @@ -27,6 +28,8 @@ public ServerBoundGamePacketHandler(ConnectionManager connectionManager) { PacketOperator updatePlayerRotation = provider -> { double yaw = provider.readFloat() % 360; + provider.readFloat(); // pitch + provider.readBoolean(); // on ground WorldManager.getInstance().setPlayerRotation(yaw); return true; }; @@ -80,6 +83,11 @@ public ServerBoundGamePacketHandler(ConnectionManager connectionManager) { WorldManager.getInstance().getVillagerManager().lastInteractedWith(provider); return true; }); + + operations.put("ConfigurationAcknowledged", provider ->{ + getConnectionManager().setMode(NetworkMode.CONFIGURATION); + return true; + }); } @Override diff --git a/src/main/java/packets/handler/version/ClientBoundConfigurationPacketHandler_1_20_2.java b/src/main/java/packets/handler/version/ClientBoundConfigurationPacketHandler_1_20_2.java new file mode 100644 index 00000000..9bb313bc --- /dev/null +++ b/src/main/java/packets/handler/version/ClientBoundConfigurationPacketHandler_1_20_2.java @@ -0,0 +1,26 @@ +package packets.handler.version; + +import game.data.WorldManager; +import game.data.dimension.DimensionCodec; +import packets.handler.ClientBoundConfigurationPacketHandler; +import packets.handler.PacketOperator; +import proxy.ConnectionManager; +import se.llbit.nbt.SpecificTag; + +import java.util.Map; + +public class ClientBoundConfigurationPacketHandler_1_20_2 extends ClientBoundConfigurationPacketHandler { + public ClientBoundConfigurationPacketHandler_1_20_2(ConnectionManager connectionManager) { + super(connectionManager); + + Map operators = getOperators(); + WorldManager worldManager = WorldManager.getInstance(); + + operators.put("RegistryData", provider -> { + SpecificTag registryData = provider.readNbtTag(); + worldManager.setDimensionCodec(DimensionCodec.fromNbt(registryData)); + + return true; + }); + } +} 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 828c9ad3..a5426dd3 100644 --- a/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_16.java +++ b/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_16.java @@ -34,7 +34,7 @@ public ClientBoundGamePacketHandler_1_16(ConnectionManager connectionManager) { String[] dimensionNames = provider.readStringArray(numDimensions); SpecificTag dimensionCodec = provider.readNbtTag(); - WorldManager.getInstance().setDimensionCodec(DimensionCodec.fromNbt(dimensionNames, dimensionCodec)); + WorldManager.getInstance().setDimensionCodec(DimensionCodec.fromNbt(dimensionCodec).setDimensionNames(dimensionNames)); SpecificTag dimensionNbt = provider.readNbtTag(); diff --git a/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_19.java b/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_19.java index 0a011f93..f264cfae 100644 --- a/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_19.java +++ b/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_19.java @@ -35,7 +35,7 @@ public ClientBoundGamePacketHandler_1_19(ConnectionManager connectionManager) { String[] dimensionNames = provider.readStringArray(numDimensions); SpecificTag dimensionCodec = provider.readNbtTag(); - WorldManager.getInstance().setDimensionCodec(DimensionCodec.fromNbt(dimensionNames, dimensionCodec)); + WorldManager.getInstance().setDimensionCodec(DimensionCodec.fromNbt(dimensionCodec).setDimensionNames(dimensionNames)); String dimensionType = provider.readString(); // current active dimension diff --git a/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_20_2.java b/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_20_2.java new file mode 100644 index 00000000..4599deb3 --- /dev/null +++ b/src/main/java/packets/handler/version/ClientBoundGamePacketHandler_1_20_2.java @@ -0,0 +1,71 @@ +package packets.handler.version; + +import config.Config; +import game.data.WorldManager; +import game.data.dimension.Dimension; +import game.data.dimension.DimensionCodec; +import game.data.entity.EntityRegistry; +import game.protocol.Protocol; +import packets.builder.PacketBuilder; +import packets.handler.PacketOperator; +import proxy.ConnectionManager; +import se.llbit.nbt.CompoundTag; +import se.llbit.nbt.SpecificTag; + +import java.util.Map; + +import static packets.builder.NetworkType.*; + +public class ClientBoundGamePacketHandler_1_20_2 extends ClientBoundGamePacketHandler_1_19 { + public ClientBoundGamePacketHandler_1_20_2(ConnectionManager connectionManager) { + super(connectionManager); + + Protocol protocol = Config.versionReporter().getProtocol(); + EntityRegistry entityRegistry = WorldManager.getInstance().getEntityRegistry(); + + Map operators = getOperators(); + operators.put("Login", provider -> { + PacketBuilder replacement = new PacketBuilder(protocol.clientBound("Login")); + + replacement.copy(provider, INT, BOOL); + + // handle dimension codec + int numDimensions = provider.readVarInt(); + String[] dimensionNames = provider.readStringArray(numDimensions); + WorldManager.getInstance().getDimensionCodec().setDimensionNames(dimensionNames); + + replacement.writeVarInt(numDimensions); + replacement.writeStringArray(dimensionNames); + + replacement.copy(provider, VARINT); + + // extend view distance communicated to the client to the given value + int viewDist = provider.readVarInt(); + replacement.writeVarInt(Math.max(viewDist, Config.getExtendedRenderDistance())); + + replacement.copy(provider, VARINT, BOOL, BOOL, BOOL); + + // current active dimension + String dimensionType = provider.readString(); + String dimensionName = provider.readString(); + Dimension dimension = Dimension.fromString(dimensionName); + dimension.setType(dimensionType); + WorldManager.getInstance().setDimension(dimension); + + replacement.writeString(dimensionType); + replacement.writeString(dimensionName); + + replacement.copy(provider, LONG, BYTE, BYTE, BOOL, BOOL); + + replacement.copyRemainder(provider); + + getConnectionManager().getEncryptionManager().sendImmediately(replacement); + return false; + }); + + operators.put("UpdatePlayerInfo", provider -> { + entityRegistry.updatePlayerAction(provider); + return true; + }); + } +} \ No newline at end of file diff --git a/src/main/java/packets/version/DataTypeProvider_1_20_2.java b/src/main/java/packets/version/DataTypeProvider_1_20_2.java new file mode 100644 index 00000000..63213527 --- /dev/null +++ b/src/main/java/packets/version/DataTypeProvider_1_20_2.java @@ -0,0 +1,32 @@ +package packets.version; + +import packets.DataTypeProvider; +import se.llbit.nbt.SpecificTag; + +import java.io.DataInputStream; +import java.io.InputStream; + +public class DataTypeProvider_1_20_2 extends DataTypeProvider_1_14 { + public DataTypeProvider_1_20_2(byte[] finalFullPacket) { + super(finalFullPacket); + } + + public SpecificTag readNbtTag() { + try { + return (SpecificTag) SpecificTag.read(readNext(), new DataInputStream(new InputStream() { + @Override + public int read() { + return readNext() & 0xFF; + } + })).unpack(); + } catch (Exception ex) { + ex.printStackTrace(); + return null; + } + } + + @Override + public DataTypeProvider ofLength(int length) { + return new DataTypeProvider_1_20_2(this.readByteArray(length)); + } +} diff --git a/src/main/java/proxy/ConnectionManager.java b/src/main/java/proxy/ConnectionManager.java index 1f6e6fc1..9cfe5af7 100644 --- a/src/main/java/proxy/ConnectionManager.java +++ b/src/main/java/proxy/ConnectionManager.java @@ -3,6 +3,7 @@ import config.Config; import game.NetworkMode; import game.data.WorldManager; +import game.protocol.ConfigurationProtocol; import game.protocol.HandshakeProtocol; import game.protocol.LoginProtocol; import game.protocol.StatusProtocol; @@ -48,6 +49,11 @@ public void setMode(NetworkMode mode) { serverBoundDataReader.setPacketHandler(new ServerBoundHandshakePacketHandler(this)); clientBoundDataReader.setPacketHandler(new ClientBoundHandshakePacketHandler(this)); break; + case CONFIGURATION: + PacketHandler.setProtocol(new ConfigurationProtocol()); + serverBoundDataReader.setPacketHandler(new ServerBoundConfigurationPacketHandler(this)); + clientBoundDataReader.setPacketHandler(ClientBoundConfigurationPacketHandler.of(this)); + break; } } diff --git a/src/main/resources/protocol-versions.json b/src/main/resources/protocol-versions.json index 3349954d..31e9d17e 100644 --- a/src/main/resources/protocol-versions.json +++ b/src/main/resources/protocol-versions.json @@ -399,6 +399,88 @@ "0x31": "UseItemOn", "0x32": "UseItem" } + }, + "764": { + "version": "1.20.2", + "dataVersion": 3578, + "clientBound": { + "0x01": "AddEntity", + "0x07": "BlockEntityData", + "0x09": "BlockUpdate", + "0x12": "ContainerClose", + "0x13": "ContainerSetContent", + "0x1f": "ForgetLevelChunk", + "0x25": "LevelChunkWithLight", + "0x28": "LightUpdate", + "0x29": "Login", + "0x2a": "MapItemData", + "0x2b": "TradeList", + "0x2c": "MoveEntityPos", + "0x2d": "MoveEntityPosRot", + "0x31": "OpenScreen", + "0x3c": "UpdatePlayerInfo", + "0x40": "RemoveEntities", + "0x43": "Respawn", + "0x45": "SectionBlocksUpdate", + "0x51": "SetChunkCacheRadius", + "0x54": "SetEntityData", + "0x57": "SetEquipment", + "0x67": "SystemChat", + "0x6b": "TeleportEntity" + }, + "serverBound": { + "0x0b": "ConfigurationAcknowledged", + "0x0c": "ContainerClose", + "0x12": "Interact", + "0x16": "MovePlayerPos", + "0x17": "MovePlayerPosRot", + "0x18": "MovePlayerRot", + "0x1a": "MoveVehicle", + "0x2c": "SetCommandBlock", + "0x34": "UseItemOn", + "0x35": "UseItem" + } + }, + "765": { + "version": "1.20.3", + "dataVersion": 3698, + "clientBound": { + "0x01": "AddEntity", + "0x07": "BlockEntityData", + "0x09": "BlockUpdate", + "0x12": "ContainerClose", + "0x13": "ContainerSetContent", + "0x1f": "ForgetLevelChunk", + "0x25": "LevelChunkWithLight", + "0x28": "LightUpdate", + "0x29": "Login", + "0x2a": "MapItemData", + "0x2b": "TradeList", + "0x2c": "MoveEntityPos", + "0x2d": "MoveEntityPosRot", + "0x31": "OpenScreen", + "0x3c": "UpdatePlayerInfo", + "0x40": "RemoveEntities", + "0x45": "Respawn", + "0x47": "SectionBlocksUpdate", + "0x53": "SetChunkCacheRadius", + "0x56": "SetEntityData", + "0x59": "SetEquipment", + "0x69": "SystemChat", + "0x6d": "TeleportEntity" + }, + "serverBound": { + "0x0b": "ConfigurationAcknowledged", + "0x0c": "ContainerClose", + "0x12": "Interact", + "0x16": "MovePlayerPos", + "0x18": "MovePlayerPosRot", + "0x19": "MovePlayerRot", + "0x1b": "MoveVehicle", + "0x2d": "SetCommandBlock", + "0x35": "UseItemOn", + "0x36": "UseItem" + } } } } \ No newline at end of file diff --git a/src/test/java/game/protocol/ProtocolVersionHandlerTest.java b/src/test/java/game/protocol/ProtocolVersionHandlerTest.java index 824200e1..3de7aa43 100644 --- a/src/test/java/game/protocol/ProtocolVersionHandlerTest.java +++ b/src/test/java/game/protocol/ProtocolVersionHandlerTest.java @@ -25,6 +25,7 @@ void bestMatch() { versions.put(758, "1.18"); versions.put(761, "1.19.3"); versions.put(763, "1.20"); + versions.put(764, "1.20.2"); versions.forEach((k, v) -> { assertThat(pvh.getProtocolByProtocolVersion(k).getVersion()).isEqualTo(v);