diff --git a/README.rst b/README.rst index eee99ae..deb7ff2 100644 --- a/README.rst +++ b/README.rst @@ -23,7 +23,7 @@ Supported Minecraft versions ---------------------------- pyCraft is compatible with the following Minecraft releases: -* 1.8, 1.8.1, 1.8.2, 1.8.3, 1.8.4, 1.8.5, 1.8.6, 1.8.7, 1.8.8 +* 1.8, 1.8.1, 1.8.2, 1.8.3, 1.8.4, 1.8.5, 1.8.6, 1.8.7, 1.8.8, 1.8.9 * 1.9, 1.9.1, 1.9.2, 1.9.3, 1.9.4 * 1.10, 1.10.1, 1.10.2 * 1.11, 1.11.1, 1.11.2 diff --git a/minecraft/__init__.py b/minecraft/__init__.py index 9f96755..e6adbb6 100644 --- a/minecraft/__init__.py +++ b/minecraft/__init__.py @@ -15,6 +15,7 @@ SUPPORTED_MINECRAFT_VERSIONS = { '1.8.6': 47, '1.8.7': 47, '1.8.8': 47, + '1.8.9': 47, '1.9': 107, '1.9.1': 108, '1.9.2': 109, @@ -67,6 +68,19 @@ SUPPORTED_MINECRAFT_VERSIONS = { '1.12.2-pre1': 339, '1.12.2-pre2': 339, '1.12.2': 340, + '17w43a': 341, + '17w43b': 342, + '17w45a': 343, + '17w45b': 344, + '17w46a': 345, + '17w47a': 346, + '17w47b': 347, + '17w48a': 348, + '17w49a': 349, + '17w49b': 350, + '17w50a': 351, + '18w01a': 352, + '18w02a': 353, } SUPPORTED_PROTOCOL_VERSIONS = \ diff --git a/minecraft/networking/packets/clientbound/play/__init__.py b/minecraft/networking/packets/clientbound/play/__init__.py index 937bfdb..70c926d 100644 --- a/minecraft/networking/packets/clientbound/play/__init__.py +++ b/minecraft/networking/packets/clientbound/play/__init__.py @@ -1,5 +1,5 @@ from minecraft.networking.packets import ( - Packet, PacketBuffer, AbstractKeepAlivePacket, AbstractPluginMessagePacket + Packet, AbstractKeepAlivePacket, AbstractPluginMessagePacket ) from minecraft.networking.types import ( @@ -12,6 +12,7 @@ from .map_packet import MapPacket from .player_list_item_packet import PlayerListItemPacket from .player_position_and_look_packet import PlayerPositionAndLookPacket from .spawn_object_packet import SpawnObjectPacket +from .block_change_packet import BlockChangePacket, MultiBlockChangePacket # Formerly known as state_playing_clientbound. @@ -44,7 +45,8 @@ def get_packets(context): class KeepAlivePacket(AbstractKeepAlivePacket): @staticmethod def get_id(context): - return 0x1F if context.protocol_version >= 332 else \ + return 0x20 if context.protocol_version >= 345 else \ + 0x1F if context.protocol_version >= 332 else \ 0x20 if context.protocol_version >= 318 else \ 0x1F if context.protocol_version >= 107 else \ 0x00 @@ -53,7 +55,8 @@ class KeepAlivePacket(AbstractKeepAlivePacket): class JoinGamePacket(Packet): @staticmethod def get_id(context): - return 0x23 if context.protocol_version >= 332 else \ + return 0x24 if context.protocol_version >= 345 else \ + 0x23 if context.protocol_version >= 332 else \ 0x24 if context.protocol_version >= 318 else \ 0x23 if context.protocol_version >= 107 else \ 0x01 @@ -72,7 +75,8 @@ class JoinGamePacket(Packet): class ChatMessagePacket(Packet): @staticmethod def get_id(context): - return 0x0F if context.protocol_version >= 332 else \ + return 0x0E if context.protocol_version >= 343 else \ + 0x0F if context.protocol_version >= 332 else \ 0x10 if context.protocol_version >= 317 else \ 0x0F if context.protocol_version >= 107 else \ 0x02 @@ -91,7 +95,8 @@ class ChatMessagePacket(Packet): class DisconnectPacket(Packet): @staticmethod def get_id(context): - return 0x1A if context.protocol_version >= 332 else \ + return 0x1B if context.protocol_version >= 345 else \ + 0x1A if context.protocol_version >= 332 else \ 0x1B if context.protocol_version >= 318 else \ 0x1A if context.protocol_version >= 107 else \ 0x40 @@ -133,7 +138,9 @@ class SpawnPlayerPacket(Packet): class EntityVelocityPacket(Packet): @staticmethod def get_id(context): - return 0x3E if context.protocol_version >= 336 else \ + return 0x40 if context.protocol_version >= 352 else \ + 0x3F if context.protocol_version >= 345 else \ + 0x3E if context.protocol_version >= 336 else \ 0x3D if context.protocol_version >= 332 else \ 0x3B if context.protocol_version >= 86 else \ 0x3C if context.protocol_version >= 77 else \ @@ -152,7 +159,9 @@ class EntityVelocityPacket(Packet): class UpdateHealthPacket(Packet): @staticmethod def get_id(context): - return 0x41 if context.protocol_version >= 336 else \ + return 0x43 if context.protocol_version >= 352 else \ + 0x42 if context.protocol_version >= 345 else \ + 0x41 if context.protocol_version >= 336 else \ 0x40 if context.protocol_version >= 318 else \ 0x3E if context.protocol_version >= 86 else \ 0x3F if context.protocol_version >= 77 else \ @@ -170,7 +179,8 @@ class UpdateHealthPacket(Packet): class ExplosionPacket(Packet): @staticmethod def get_id(context): - return 0x1C if context.protocol_version >= 332 else \ + return 0x1D if context.protocol_version >= 345 else \ + 0x1C if context.protocol_version >= 332 else \ 0x1D if context.protocol_version >= 318 else \ 0x1C if context.protocol_version >= 80 else \ 0x1B if context.protocol_version >= 67 else \ @@ -202,81 +212,11 @@ class ExplosionPacket(Packet): raise NotImplementedError -class BlockChangePacket(Packet): - @staticmethod - def get_id(context): - return 0x0B if context.protocol_version >= 332 else \ - 0x0C if context.protocol_version >= 318 else \ - 0x0B if context.protocol_version >= 67 else \ - 0x24 if context.protocol_version >= 62 else \ - 0x23 - - packet_name = 'block change' - - def read(self, file_object): - self.location = Position.read(file_object) - blockData = VarInt.read(file_object) - self.blockId = (blockData >> 4) - self.blockMeta = (blockData & 0xF) - - def write(self, socket, compression_threshold=None): - packet_buffer = PacketBuffer() - (x, y, z) = self.location - Position.send(x, y, z, packet_buffer) - blockData = ((self.blockId << 4) | (self.blockMeta & 0xF)) - VarInt.send(blockData) - self._write_buffer(socket, packet_buffer, compression_threshold) - - -class MultiBlockChangePacket(Packet): - @staticmethod - def get_id(context): - return 0x10 if context.protocol_version >= 332 else \ - 0x11 if context.protocol_version >= 318 else \ - 0x10 if context.protocol_version >= 67 else \ - 0x22 - - packet_name = 'multi block change' - - class Record(object): - __slots__ = 'x', 'y', 'z', 'blockId', 'blockMeta' - - def __init__(self, horizontal_position, y_coordinate, blockData): - self.x = (horizontal_position & 0xF0) >> 4 - self.y = y_coordinate - self.z = (horizontal_position & 0x0F) - self.blockId = (blockData >> 4) - self.blockMeta = (blockData & 0xF) - - def __repr__(self): - return ('Record(x=%s, y=%s, z=%s, blockId=%s)' - % (self.x, self.y, self.z, self.blockId)) - - def __str__(self): - return self.__repr__() - - def read(self, file_object): - self.chunk_x = Integer.read(file_object) - self.chunk_z = Integer.read(file_object) - records_count = VarInt.read(file_object) - self.records = [] - for i in range(records_count): - rec_horizontal_position = UnsignedByte.read(file_object) - rec_y_coordinate = UnsignedByte.read(file_object) - rec_blockData = VarInt.read(file_object) - record = MultiBlockChangePacket.Record( - rec_horizontal_position, - rec_y_coordinate, rec_blockData) - self.records.append(record) - - def write(self, socket, compression_threshold=None): - raise NotImplementedError - - class PluginMessagePacket(AbstractPluginMessagePacket): @staticmethod def get_id(context): - return 0x18 if context.protocol_version >= 332 else \ + return 0x19 if context.protocol_version >= 345 else \ + 0x18 if context.protocol_version >= 332 else \ 0x19 if context.protocol_version >= 318 else \ 0x18 if context.protocol_version >= 70 else \ 0x3F diff --git a/minecraft/networking/packets/clientbound/play/block_change_packet.py b/minecraft/networking/packets/clientbound/play/block_change_packet.py new file mode 100644 index 0000000..4e40b26 --- /dev/null +++ b/minecraft/networking/packets/clientbound/play/block_change_packet.py @@ -0,0 +1,109 @@ +from minecraft.networking.packets import ( + Packet, PacketBuffer +) +from minecraft.networking.types import ( + VarInt, Integer, UnsignedByte, Position +) + + +class BlockChangePacket(Packet): + @staticmethod + def get_id(context): + return 0x0B if context.protocol_version >= 332 else \ + 0x0C if context.protocol_version >= 318 else \ + 0x0B if context.protocol_version >= 67 else \ + 0x24 if context.protocol_version >= 62 else \ + 0x23 + + packet_name = 'block change' + + def read(self, file_object): + self.location = Position.read(file_object) + blockData = VarInt.read(file_object) + if self.context.protocol_version >= 347: + # See comments on MultiBlockChangePacket.OpaqueRecord. + self.blockStateId = blockData + else: + self.blockId = (blockData >> 4) + self.blockMeta = (blockData & 0xF) + + def write(self, socket, compression_threshold=None): + packet_buffer = PacketBuffer() + (x, y, z) = self.location + Position.send(x, y, z, packet_buffer) + blockData = ((self.blockId << 4) | (self.blockMeta & 0xF)) + VarInt.send(blockData) + self._write_buffer(socket, packet_buffer, compression_threshold) + + +class MultiBlockChangePacket(Packet): + @staticmethod + def get_id(context): + return 0x0F if context.protocol_version >= 343 else \ + 0x10 if context.protocol_version >= 332 else \ + 0x11 if context.protocol_version >= 318 else \ + 0x10 if context.protocol_version >= 67 else \ + 0x22 + + packet_name = 'multi block change' + + class BaseRecord(object): + __slots__ = 'x', 'y', 'z' + + def __init__(self, horizontal_position, y_coordinate): + self.x = (horizontal_position & 0xF0) >> 4 + self.y = y_coordinate + self.z = (horizontal_position & 0x0F) + + def __str__(self): + return self.__repr__() + + @classmethod + def get_subclass(cls, context): + return MultiBlockChangePacket.OpaqueRecord \ + if context.protocol_version >= 347 else \ + MultiBlockChangePacket.Record + + class Record(BaseRecord): + __slots__ = 'blockId', 'blockMeta' + + def __init__(self, h_position, y_coordinate, blockData): + super(MultiBlockChangePacket.Record, self).__init__( + h_position, y_coordinate) + self.blockId = (blockData >> 4) + self.blockMeta = (blockData & 0xF) + + def __repr__(self): + return ('Record(x=%s, y=%s, z=%s, blockId=%s)' + % (self.x, self.y, self.z, self.blockId)) + + '''The structure of the block data changed in protocol 347 (17w47b, + between 1.12.2 and 1.13), which this class reflects: instead of a + separate blockId and blockMeta number, there is a single opaque + blockStateId whose meaning may change between minor versions.''' + class OpaqueRecord(BaseRecord): + __slots__ = 'blockStateId' + + def __init__(self, h_position, y_coordinate, blockData): + super(MultiBlockChangePacket.OpaqueRecord, self).__init__( + h_position, y_coordinate) + self.blockStateId = blockData + + def __repr__(self): + return ('OpaqueRecord(x=%s, y=%s, z=%s, blockStateId=%s)' + % (self.x, self.y, self.z, self.blockStateId)) + + def read(self, file_object): + self.chunk_x = Integer.read(file_object) + self.chunk_z = Integer.read(file_object) + records_count = VarInt.read(file_object) + record_type = self.BaseRecord.get_subclass(self.context) + self.records = [] + for i in range(records_count): + record = record_type(h_position=UnsignedByte.read(file_object), + y_coordinate=VarInt.read(file_object), + blockData=VarInt.read(file_object)) + self.records.append(record) + + def write(self, socket, compression_threshold=None): + raise NotImplementedError diff --git a/minecraft/networking/packets/clientbound/play/combat_event_packet.py b/minecraft/networking/packets/clientbound/play/combat_event_packet.py index 5d31561..1c3c9ae 100644 --- a/minecraft/networking/packets/clientbound/play/combat_event_packet.py +++ b/minecraft/networking/packets/clientbound/play/combat_event_packet.py @@ -8,7 +8,8 @@ from minecraft.networking.types import ( class CombatEventPacket(Packet): @staticmethod def get_id(context): - return 0x2D if context.protocol_version >= 336 else \ + return 0x2E if context.protocol_version >= 345 else \ + 0x2D if context.protocol_version >= 336 else \ 0x2C if context.protocol_version >= 332 else \ 0x2D if context.protocol_version >= 318 else \ 0x2C if context.protocol_version >= 86 else \ diff --git a/minecraft/networking/packets/clientbound/play/map_packet.py b/minecraft/networking/packets/clientbound/play/map_packet.py index 4855ccf..d37b62d 100644 --- a/minecraft/networking/packets/clientbound/play/map_packet.py +++ b/minecraft/networking/packets/clientbound/play/map_packet.py @@ -10,7 +10,8 @@ from minecraft.networking.types import ( class MapPacket(Packet): @staticmethod def get_id(context): - return 0x24 if context.protocol_version >= 334 else \ + return 0x25 if context.protocol_version >= 345 else \ + 0x24 if context.protocol_version >= 334 else \ 0x25 if context.protocol_version >= 318 else \ 0x24 if context.protocol_version >= 107 else \ 0x34 diff --git a/minecraft/networking/packets/clientbound/play/player_list_item_packet.py b/minecraft/networking/packets/clientbound/play/player_list_item_packet.py index 5930afe..4d2965a 100644 --- a/minecraft/networking/packets/clientbound/play/player_list_item_packet.py +++ b/minecraft/networking/packets/clientbound/play/player_list_item_packet.py @@ -8,7 +8,8 @@ from minecraft.networking.types import ( class PlayerListItemPacket(Packet): @staticmethod def get_id(context): - return 0x2E if context.protocol_version >= 336 else \ + return 0x2F if context.protocol_version >= 345 else \ + 0x2E if context.protocol_version >= 336 else \ 0x2D if context.protocol_version >= 332 else \ 0x2E if context.protocol_version >= 318 else \ 0x2D if context.protocol_version >= 107 else \ diff --git a/minecraft/networking/packets/clientbound/play/player_position_and_look_packet.py b/minecraft/networking/packets/clientbound/play/player_position_and_look_packet.py index 8536cd1..de52075 100644 --- a/minecraft/networking/packets/clientbound/play/player_position_and_look_packet.py +++ b/minecraft/networking/packets/clientbound/play/player_position_and_look_packet.py @@ -8,7 +8,9 @@ from minecraft.networking.types import ( class PlayerPositionAndLookPacket(Packet, BitFieldEnum): @staticmethod def get_id(context): - return 0x2F if context.protocol_version >= 336 else \ + return 0x31 if context.protocol_version >= 352 else \ + 0x30 if context.protocol_version >= 345 else \ + 0x2F if context.protocol_version >= 336 else \ 0x2E if context.protocol_version >= 332 else \ 0x2F if context.protocol_version >= 318 else \ 0x2E if context.protocol_version >= 70 else \ diff --git a/minecraft/networking/packets/serverbound/play/__init__.py b/minecraft/networking/packets/serverbound/play/__init__.py index 099e895..a2945d1 100644 --- a/minecraft/networking/packets/serverbound/play/__init__.py +++ b/minecraft/networking/packets/serverbound/play/__init__.py @@ -30,7 +30,9 @@ def get_packets(context): class KeepAlivePacket(AbstractKeepAlivePacket): @staticmethod def get_id(context): - return 0x0B if context.protocol_version >= 336 else \ + return 0x0B if context.protocol_version >= 345 else \ + 0x0A if context.protocol_version >= 343 else \ + 0x0B if context.protocol_version >= 336 else \ 0x0C if context.protocol_version >= 318 else \ 0x0B if context.protocol_version >= 107 else \ 0x00 @@ -39,7 +41,8 @@ class KeepAlivePacket(AbstractKeepAlivePacket): class ChatPacket(Packet): @staticmethod def get_id(context): - return 0x02 if context.protocol_version >= 336 else \ + return 0x01 if context.protocol_version >= 343 else \ + 0x02 if context.protocol_version >= 336 else \ 0x03 if context.protocol_version >= 318 else \ 0x02 if context.protocol_version >= 107 else \ 0x01 @@ -62,7 +65,9 @@ class ChatPacket(Packet): class PositionAndLookPacket(Packet): @staticmethod def get_id(context): - return 0x0E if context.protocol_version >= 336 else \ + return 0x0E if context.protocol_version >= 345 else \ + 0x0D if context.protocol_version >= 343 else \ + 0x0E if context.protocol_version >= 336 else \ 0x0F if context.protocol_version >= 332 else \ 0x0E if context.protocol_version >= 318 else \ 0x0D if context.protocol_version >= 107 else \ @@ -89,7 +94,9 @@ class TeleportConfirmPacket(Packet): class AnimationPacket(Packet, Enum): @staticmethod def get_id(context): - return 0x1D if context.protocol_version >= 332 else \ + return 0x1D if context.protocol_version >= 345 else \ + 0x1C if context.protocol_version >= 343 else \ + 0x1D if context.protocol_version >= 332 else \ 0x1C if context.protocol_version >= 318 else \ 0x1A if context.protocol_version >= 107 else \ 0x0A @@ -107,7 +114,8 @@ class AnimationPacket(Packet, Enum): class ClientStatusPacket(Packet, Enum): @staticmethod def get_id(context): - return 0x03 if context.protocol_version >= 336 else \ + return 0x02 if context.protocol_version >= 343 else \ + 0x03 if context.protocol_version >= 336 else \ 0x04 if context.protocol_version >= 318 else \ 0x03 if context.protocol_version >= 80 else \ 0x02 if context.protocol_version >= 67 else \ @@ -129,7 +137,9 @@ class ClientStatusPacket(Packet, Enum): class PluginMessagePacket(AbstractPluginMessagePacket): @staticmethod def get_id(context): - return 0x09 if context.protocol_version >= 336 else \ + return 0x09 if context.protocol_version >= 345 else \ + 0x08 if context.protocol_version >= 343 else \ + 0x09 if context.protocol_version >= 336 else \ 0x0A if context.protocol_version >= 317 else \ 0x09 if context.protocol_version >= 94 else \ 0x17 diff --git a/minecraft/networking/packets/serverbound/play/client_settings_packet.py b/minecraft/networking/packets/serverbound/play/client_settings_packet.py index 4d0637d..b1edeb9 100644 --- a/minecraft/networking/packets/serverbound/play/client_settings_packet.py +++ b/minecraft/networking/packets/serverbound/play/client_settings_packet.py @@ -7,7 +7,8 @@ from minecraft.networking.types import ( class ClientSettingsPacket(Packet): @staticmethod def get_id(context): - return 0x04 if context.protocol_version >= 336 else \ + return 0x03 if context.protocol_version >= 343 else \ + 0x04 if context.protocol_version >= 336 else \ 0x05 if context.protocol_version >= 318 else \ 0x04 if context.protocol_version >= 94 else \ 0x15