class ExplosionPacket(Packet): @staticmethod def get_id(context): return 0x1D if context.protocol_version >= 573 else \ 0x1C if context.protocol_version >= 471 else \ 0x1E if context.protocol_version >= 389 else \ 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 \ 0x27 packet_name = 'explosion' fields = 'x', 'y', 'z', 'radius', 'records', \ 'player_motion_x', 'player_motion_y', 'player_motion_z' # Access the 'x', 'y', 'z' fields as a Vector tuple. position = multi_attribute_alias(Vector, 'x', 'y', 'z') # Access the 'player_motion_{x,y,z}' fields as a Vector tuple. player_motion = multi_attribute_alias(Vector, 'player_motion_x', 'player_motion_y', 'player_motion_z') class Record(Vector): __slots__ = () def read(self, file_object): self.x = Float.read(file_object) self.y = Float.read(file_object) self.z = Float.read(file_object) self.radius = Float.read(file_object) records_count = Integer.read(file_object) self.records = [] for i in range(records_count): rec_x = Byte.read(file_object) rec_y = Byte.read(file_object) rec_z = Byte.read(file_object) record = ExplosionPacket.Record(rec_x, rec_y, rec_z) self.records.append(record) self.player_motion_x = Float.read(file_object) self.player_motion_y = Float.read(file_object) self.player_motion_z = Float.read(file_object) def write_fields(self, packet_buffer): Float.send(self.x, packet_buffer) Float.send(self.y, packet_buffer) Float.send(self.z, packet_buffer) Float.send(self.radius, packet_buffer) Integer.send(len(self.records), packet_buffer) for record in self.records: Byte.send(record.x, packet_buffer) Byte.send(record.y, packet_buffer) Byte.send(record.z, packet_buffer) Float.send(self.player_motion_x, packet_buffer) Float.send(self.player_motion_y, packet_buffer) Float.send(self.player_motion_z, packet_buffer)
class SpawnPlayerPacket(Packet): @staticmethod def get_id(context): return 0x05 if context.protocol_version >= 67 else \ 0x0C packet_name = 'spawn player' get_definition = staticmethod(lambda context: [ { 'entity_id': VarInt }, { 'player_UUID': UUID }, { 'x': Double } if context.protocol_version >= 100 else { 'x': FixedPointInteger }, { 'y': Double } if context.protocol_version >= 100 else { 'y': FixedPointInteger }, { 'z': Double } if context.protocol_version >= 100 else { 'z': FixedPointInteger }, { 'yaw': Angle }, { 'pitch': Angle }, { 'current_item': Short } if context.protocol_version <= 49 else {}, # TODO: read entity metadata ]) # Access the 'x', 'y', 'z' fields as a Vector tuple. position = multi_attribute_alias(Vector, 'x', 'y', 'z') # Access the 'yaw', 'pitch' fields as a Direction tuple. look = multi_attribute_alias(Direction, 'yaw', 'pitch') # Access the 'x', 'y', 'z', 'yaw', 'pitch' fields as a PositionAndLook. # NOTE: modifying the object retrieved from this property will not change # the packet; it can only be changed by attribute or property assignment. position_and_look = multi_attribute_alias(PositionAndLook, 'x', 'y', 'z', 'yaw', 'pitch')
class PositionAndLookPacket(Packet): @staticmethod def get_id(context): return 0x12 if context.protocol_version >= 471 else \ 0x13 if context.protocol_version >= 464 else \ 0x11 if context.protocol_version >= 389 else \ 0x0F if context.protocol_version >= 386 else \ 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 \ 0x06 packet_name = "position and look" definition = [ {'x': Double}, {'feet_y': Double}, {'z': Double}, {'yaw': Float}, {'pitch': Float}, {'on_ground': Boolean}] # Access the 'x', 'feet_y', 'z' fields as a Vector tuple. position = multi_attribute_alias(Vector, 'x', 'feet_y', 'z') # Access the 'yaw', 'pitch' fields as a Direction tuple. look = multi_attribute_alias(Direction, 'yaw', 'pitch') # Access the 'x', 'feet_y', 'z', 'yaw', 'pitch' fields as a # PositionAndLook. # NOTE: modifying the object retrieved from this property will not change # the packet; it can only be changed by attribute or property assignment. position_and_look = multi_attribute_alias( PositionAndLook, 'x', 'feet_y', 'z', 'yaw', 'pitch')
class Record(MutableRecord): __slots__ = 'x', 'y', 'z', 'block_state_id' def __init__(self, **kwds): self.block_state_id = 0 super(MultiBlockChangePacket.Record, self).__init__(**kwds) # Access the 'x', 'y', 'z' fields as a Vector of ints. position = multi_attribute_alias(Vector, 'x', 'y', 'z') # For protocols < 347: an accessor for (block_state_id >> 4). @property def blockId(self): return self.block_state_id >> 4 @blockId.setter def blockId(self, block_id): self.block_state_id = self.block_state_id & 0xF | block_id << 4 # For protocols < 347: an accessor for (block_state_id & 0xF). @property def blockMeta(self): return self.block_state_id & 0xF @blockMeta.setter def blockMeta(self, meta): self.block_state_id = self.block_state_id & ~0xF | meta & 0xF # This alias is retained for backward compatibility. blockStateId = attribute_alias('block_state_id') def read(self, file_object): h_position = UnsignedByte.read(file_object) self.x, self.z = h_position >> 4, h_position & 0xF self.y = UnsignedByte.read(file_object) self.block_state_id = VarInt.read(file_object) def write(self, packet_buffer): UnsignedByte.send(self.x << 4 | self.z & 0xF, packet_buffer) UnsignedByte.send(self.y, packet_buffer) VarInt.send(self.block_state_id, packet_buffer)
class SpawnObjectPacket(Packet): @staticmethod def get_id(context): return 0x00 if context.protocol_version >= 67 else \ 0x0E packet_name = 'spawn object' fields = ('entity_id', 'object_uuid', 'type_id', 'x', 'y', 'z', 'pitch', 'yaw', 'data', 'velocity_x', 'velocity_y', 'velocity_z') @descriptor def EntityType(desc, self, cls): # pylint: disable=no-self-argument if self is None: # EntityType is being accessed as a class attribute. raise AttributeError( 'This interface is deprecated:\n\n' 'As of pyCraft\'s support for Minecraft 1.14, the nested ' 'class "SpawnObjectPacket.EntityType" cannot be accessed as a ' 'class attribute, because it depends on the protocol version. ' 'There are two ways to access the correct version of the ' 'class:\n\n' '1. Access the "EntityType" attribute of a ' '"SpawnObjectPacket" instance with its "context" property ' 'set.\n\n' '2. Call "SpawnObjectPacket.field_enum(\'type_id\', ' 'context)".') else: # EntityType is being accessed as an instance attribute. return self.field_enum('type_id', self.context) @classmethod def field_enum(cls, field, context): if field != 'type_id' or context is None: return pv = context.protocol_version name = 'EntityType_%d' % pv if hasattr(cls, name): return getattr(cls, name) class EntityType(Enum): ACTIVATED_TNT = 50 if pv < 458 else 55 # PrimedTnt AREA_EFFECT_CLOUD = 3 if pv < 458 else 0 ARMORSTAND = 78 if pv < 458 else 1 ARROW = 60 if pv < 458 else 2 BOAT = 1 if pv < 458 else 5 DRAGON_FIREBALL = 93 if pv < 458 else 13 EGG = 62 if pv < 458 else 74 # ThrownEgg ENDERCRYSTAL = 51 if pv < 458 else 16 ENDERPEARL = 65 if pv < 458 else 75 # ThrownEnderpearl EVOCATION_FANGS = 79 if pv < 458 else 20 EXP_BOTTLE = 75 if pv < 458 else 76 # ThrownExpBottle EYE_OF_ENDER = 72 if pv < 458 else 23 # EyeOfEnderSignal FALLING_OBJECT = 70 if pv < 458 else 24 # FallingSand FIREBALL = 63 if pv < 458 else 34 # Fireball (ghast) FIRECHARGE = 64 if pv < 458 else 65 # SmallFireball (blaze) FIREWORK_ROCKET = 76 if pv < 458 else 25 # FireworksRocketEntity FISHING_HOOK = 90 if pv < 458 else 93 # Fishing bobber ITEM_FRAMES = 71 if pv < 458 else 33 # ItemFrame ITEM_STACK = 2 if pv < 458 else 32 # Item LEASH_KNOT = 77 if pv < 458 else 35 LLAMA_SPIT = 68 if pv < 458 else 37 MINECART = 10 if pv < 458 else 39 # MinecartRideable POTION = 73 if pv < 458 else 77 # ThrownPotion SHULKER_BULLET = 67 if pv < 458 else 60 SNOWBALL = 61 if pv < 458 else 67 SPECTRAL_ARROW = 91 if pv < 458 else 68 WITHER_SKULL = 66 if pv < 458 else 85 if pv >= 393: TRIDENT = 94 if pv >= 458: MINECART_CHEST = 40 MINECART_COMMAND_BLOCK = 41 MINECART_FURNACE = 42 MINECART_HOPPER = 43 MINECART_SPAWNER = 44 MINECART_TNT = 45 setattr(cls, name, EntityType) return EntityType def read(self, file_object): self.entity_id = VarInt.read(file_object) if self.context.protocol_version >= 49: self.object_uuid = UUID.read(file_object) if self.context.protocol_version >= 458: self.type_id = VarInt.read(file_object) else: self.type_id = Byte.read(file_object) xyz_type = Double if self.context.protocol_version >= 100 else Integer for attr in 'x', 'y', 'z': setattr(self, attr, xyz_type.read(file_object)) for attr in 'pitch', 'yaw': setattr(self, attr, Angle.read(file_object)) self.data = Integer.read(file_object) if self.context.protocol_version >= 49 or self.data > 0: for attr in 'velocity_x', 'velocity_y', 'velocity_z': setattr(self, attr, Short.read(file_object)) def write_fields(self, packet_buffer): VarInt.send(self.entity_id, packet_buffer) if self.context.protocol_version >= 49: UUID.send(self.object_uuid, packet_buffer) if self.context.protocol_version >= 458: VarInt.send(self.type_id, packet_buffer) else: Byte.send(self.type_id, packet_buffer) # pylint: disable=no-member xyz_type = Double if self.context.protocol_version >= 100 else Integer for coord in self.x, self.y, self.z: xyz_type.send(coord, packet_buffer) for coord in self.pitch, self.yaw: Angle.send(coord, packet_buffer) Integer.send(self.data, packet_buffer) if self.context.protocol_version >= 49 or self.data > 0: for coord in self.velocity_x, self.velocity_y, self.velocity_z: Short.send(coord, packet_buffer) # Access the entity type as a string, according to the EntityType enum. @property def type(self): if self.context is None: raise ValueError('This packet must have a non-None "context" ' 'in order to read the "type" property.') # pylint: disable=no-member return self.EntityType.name_from_value(self.type_id) @type.setter def type(self, type_name): if self.context is None: raise ValueError('This packet must have a non-None "context" ' 'in order to set the "type" property.') self.type_id = getattr(self.EntityType, type_name) @type.deleter def type(self): del self.type_id # Access the 'x', 'y', 'z' fields as a Vector. position = multi_attribute_alias(Vector, 'x', 'y', 'z') # Access the 'yaw', 'pitch' fields as a Direction. look = multi_attribute_alias(Direction, 'yaw', 'pitch') # Access the 'x', 'y', 'z', 'pitch', 'yaw' fields as a PositionAndLook. # NOTE: modifying the object retrieved from this property will not change # the packet; it can only be changed by attribute or property assignment. position_and_look = multi_attribute_alias(PositionAndLook, x='x', y='y', z='z', yaw='yaw', pitch='pitch') # Access the 'velocity_{x,y,z}' fields as a Vector. velocity = multi_attribute_alias(Vector, 'velocity_x', 'velocity_y', 'velocity_z') # This alias is retained for backward compatibility. objectUUID = attribute_alias('object_uuid')
class FacePlayerPacket(Packet): @staticmethod def get_id(context): return 0x35 if context.protocol_version >= 573 else \ 0x34 if context.protocol_version >= 471 else \ 0x32 if context.protocol_version >= 451 else \ 0x31 if context.protocol_version >= 389 else \ 0x30 packet_name = 'face player' @property def fields(self): return ('origin', 'x', 'y', 'z', 'entity_id', 'entity_origin') \ if self.context.protocol_version >= 353 else \ ('entity_id', 'x', 'y', 'z') # Access the 'x', 'y', 'z' fields as a Vector tuple. target = multi_attribute_alias(Vector, 'x', 'y', 'z') def read(self, file_object): if self.context.protocol_version >= 353: self.origin = VarInt.read(file_object) self.x = Double.read(file_object) self.y = Double.read(file_object) self.z = Double.read(file_object) is_entity = Boolean.read(file_object) if is_entity: # If the entity given by entity ID cannot be found, # this packet should be treated as if is_entity was false. self.entity_id = VarInt.read(file_object) self.entity_origin = VarInt.read(file_object) else: self.entity_id = None else: # Protocol version 352 is_entity = Boolean.read(file_object) self.entity_id = VarInt.read(file_object) if is_entity else None if not is_entity: self.x = Double.read(file_object) self.y = Double.read(file_object) self.z = Double.read(file_object) def write_fields(self, packet_buffer): if self.context.protocol_version >= 353: VarInt.send(self.origin, packet_buffer) Double.send(self.x, packet_buffer) Double.send(self.y, packet_buffer) Double.send(self.z, packet_buffer) if self.entity_id is not None: Boolean.send(True, packet_buffer) VarInt.send(self.entity_id, packet_buffer) VarInt.send(self.entity_origin, packet_buffer) else: Boolean.send(False, packet_buffer) else: # Protocol version 352 if self.entity_id is not None: Boolean.send(True, packet_buffer) VarInt.send(self.entity_id, packet_buffer) else: Boolean.send(False, packet_buffer) Double.send(self.x, packet_buffer) Double.send(self.y, packet_buffer) Double.send(self.z, packet_buffer) # These aliases declare the Enum type corresponding to each field: Origin = OriginPoint EntityOrigin = OriginPoint
class PlayerPositionAndLookPacket(Packet, BitFieldEnum): @staticmethod def get_id(context): return 0x36 if context.protocol_version >= 573 else \ 0x35 if context.protocol_version >= 471 else \ 0x33 if context.protocol_version >= 451 else \ 0x32 if context.protocol_version >= 389 else \ 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 \ 0x08 packet_name = "player position and look" get_definition = staticmethod(lambda context: [ { 'x': Double }, { 'y': Double }, { 'z': Double }, { 'yaw': Float }, { 'pitch': Float }, { 'flags': Byte }, { 'teleport_id': VarInt } if context.protocol_version >= 107 else {}, ]) # Access the 'x', 'y', 'z' fields as a Vector tuple. position = multi_attribute_alias(Vector, 'x', 'y', 'z') # Access the 'yaw', 'pitch' fields as a Direction tuple. look = multi_attribute_alias(Direction, 'yaw', 'pitch') # Access the 'x', 'y', 'z', 'yaw', 'pitch' fields as a PositionAndLook. # NOTE: modifying the object retrieved from this property will not change # the packet; it can only be changed by attribute or property assignment. position_and_look = multi_attribute_alias(PositionAndLook, 'x', 'y', 'z', 'yaw', 'pitch') field_enum = classmethod(lambda cls, field, context: cls if field == 'flags' else None) FLAG_REL_X = 0x01 FLAG_REL_Y = 0x02 FLAG_REL_Z = 0x04 FLAG_REL_YAW = 0x08 FLAG_REL_PITCH = 0x10 # This alias is retained for backward compatibility. PositionAndLook = PositionAndLook # Update a PositionAndLook instance using this packet. def apply(self, target): # pylint: disable=no-member if self.flags & self.FLAG_REL_X: target.x += self.x else: target.x = self.x if self.flags & self.FLAG_REL_Y: target.y += self.y else: target.y = self.y if self.flags & self.FLAG_REL_Z: target.z += self.z else: target.z = self.z if self.flags & self.FLAG_REL_YAW: target.yaw += self.yaw else: target.yaw = self.yaw if self.flags & self.FLAG_REL_PITCH: target.pitch += self.pitch else: target.pitch = self.pitch target.yaw %= 360 target.pitch %= 360
class MultiBlockChangePacket(Packet): @staticmethod def get_id(context): return 0x10 if context.protocol_version >= 573 else \ 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' fields = 'chunk_x', 'chunk_z', 'records' # Access the 'chunk_x' and 'chunk_z' fields as a tuple. chunk_pos = multi_attribute_alias(tuple, 'chunk_x', 'chunk_z') class Record(MutableRecord): __slots__ = 'x', 'y', 'z', 'block_state_id' def __init__(self, **kwds): self.block_state_id = 0 super(MultiBlockChangePacket.Record, self).__init__(**kwds) # Access the 'x', 'y', 'z' fields as a Vector of ints. position = multi_attribute_alias(Vector, 'x', 'y', 'z') # For protocols < 347: an accessor for (block_state_id >> 4). @property def blockId(self): return self.block_state_id >> 4 @blockId.setter def blockId(self, block_id): self.block_state_id = self.block_state_id & 0xF | block_id << 4 # For protocols < 347: an accessor for (block_state_id & 0xF). @property def blockMeta(self): return self.block_state_id & 0xF @blockMeta.setter def blockMeta(self, meta): self.block_state_id = self.block_state_id & ~0xF | meta & 0xF # This alias is retained for backward compatibility. blockStateId = attribute_alias('block_state_id') def read(self, file_object): h_position = UnsignedByte.read(file_object) self.x, self.z = h_position >> 4, h_position & 0xF self.y = UnsignedByte.read(file_object) self.block_state_id = VarInt.read(file_object) def write(self, packet_buffer): UnsignedByte.send(self.x << 4 | self.z & 0xF, packet_buffer) UnsignedByte.send(self.y, packet_buffer) VarInt.send(self.block_state_id, packet_buffer) 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): record = self.Record() record.read(file_object) self.records.append(record) def write_fields(self, packet_buffer): Integer.send(self.chunk_x, packet_buffer) Integer.send(self.chunk_z, packet_buffer) VarInt.send(len(self.records), packet_buffer) for record in self.records: record.write(packet_buffer)