class SpawnPlayerPacket(Packet): @staticmethod def get_id(context): return 0x04 if context.protocol_version >= 721 else \ 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 (protocol < 550) ]) # 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 ExplosionPacket(Packet): @staticmethod def get_id(context): return 0x1C if context.protocol_version >= 722 else \ 0x1D if context.protocol_version >= 550 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 ExplosionPacket(Packet): @staticmethod def get_id(context): return 0x1B if context.protocol_version >= 741 else \ 0x1C if context.protocol_version >= 721 else \ 0x1D if context.protocol_version >= 550 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' class Record(Vector, Type): __slots__ = () @classmethod def read(cls, file_object): return cls(*(Byte.read(file_object) for i in range(3))) @classmethod def send(cls, record, socket): for coord in record: Byte.send(coord, socket) definition = [{ 'x': Float }, { 'y': Float }, { 'z': Float }, { 'radius': Float }, { 'records': PrefixedArray(Integer, Record) }, { 'player_motion_x': Float }, { 'player_motion_y': Float }, { 'player_motion_z': Float }] # 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 ExplosionPacket(Packet): @staticmethod def get_id(context): return 0x1C if context.protocol_later_eq(755) else \ 0x1B if context.protocol_later_eq(741) else \ 0x1C if context.protocol_later_eq(721) else \ 0x1D if context.protocol_later_eq(550) else \ 0x1C if context.protocol_later_eq(471) else \ 0x1E if context.protocol_later_eq(389) else \ 0x1D if context.protocol_later_eq(345) else \ 0x1C if context.protocol_later_eq(332) else \ 0x1D if context.protocol_later_eq(318) else \ 0x1C if context.protocol_later_eq(80) else \ 0x1B if context.protocol_later_eq(67) else \ 0x27 packet_name = 'explosion' class Record(Vector, Type): __slots__ = () @classmethod def read(cls, file_object): return cls(*(Byte.read(file_object) for i in range(3))) @classmethod def send(cls, record, socket): for coord in record: Byte.send(coord, socket) @staticmethod def get_definition(context): return [ {'x': Float}, {'y': Float}, {'z': Float}, {'radius': Float}, {'records': PrefixedArray(VarInt, ExplosionPacket.Record)} if context.protocol_later_eq(755) else {'records': PrefixedArray(Integer, ExplosionPacket.Record)}, {'player_motion_x': Float}, {'player_motion_y': Float}, {'player_motion_z': Float}, ] # 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 PositionAndLookPacket(Packet): @staticmethod def get_id(context): return ( 0x13 if context.protocol_later_eq(712) else 0x12 if context.protocol_later_eq(471) else 0x13 if context.protocol_later_eq(464) else 0x11 if context.protocol_later_eq(389) else 0x0F if context.protocol_later_eq(386) else 0x0E if context.protocol_later_eq(345) else 0x0D if context.protocol_later_eq(343) else 0x0E if context.protocol_later_eq(336) else 0x0F if context.protocol_later_eq(332) else 0x0E if context.protocol_later_eq(318) else 0x0D if context.protocol_later_eq(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 SpawnPlayerPacket(Packet): @staticmethod def get_id(context): return (0x04 if context.protocol_later_eq(721) else 0x05 if context.protocol_later_eq(67) else 0x0C) packet_name = "spawn player" get_definition = staticmethod(lambda context: [ { "entity_id": VarInt }, { "player_UUID": UUID }, { "x": Double } if context.protocol_later_eq(100) else { "x": FixedPoint(Integer) }, { "y": Double } if context.protocol_later_eq(100) else { "y": FixedPoint(Integer) }, { "z": Double } if context.protocol_later_eq(100) else { "z": FixedPoint(Integer) }, { "yaw": Angle }, { "pitch": Angle }, { "current_item": Short } if context.protocol_earlier_eq(49) else {}, # TODO: read entity metadata (protocol < 550) ]) # 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 PlayerPositionPacket(Packet): @staticmethod def get_id(context): return 0x11 if context.protocol_version >= 471 else \ 0x12 if context.protocol_version >= 464 else \ 0x10 if context.protocol_version >= 389 else \ 0x0E if context.protocol_version >= 386 else \ 0x0D if context.protocol_version >= 345 else \ 0x0C if context.protocol_version >= 343 else \ 0x0D if context.protocol_version >= 336 else \ 0x0E if context.protocol_version >= 332 else \ 0x0D if context.protocol_version >= 318 else \ 0x0C if context.protocol_version >= 94 else \ 0x0B if context.protocol_version >= 70 else \ 0x04 packet_name = "player position" definition = [{ 'x': Double }, { 'feet_y': Double }, { 'z': Double }, { 'on_ground': Boolean }] # The code under this line was copied from the packets/clientbound/play/player_position_and_look_packet.py # Access the 'x', 'y', 'z' fields as a Vector tuple. position = multi_attribute_alias(Vector, 'x', 'feet_y', 'z')
class Record(MutableRecord, Type): __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") @classmethod def read_with_context(cls, file_object, context): record = cls() if context.protocol_version >= 741: value = VarLong.read(file_object) record.block_state_id = value >> 12 record.x = (value >> 8) & 0xF record.z = (value >> 4) & 0xF record.y = value & 0xF else: h_position = UnsignedByte.read(file_object) record.x = h_position >> 4 record.z = h_position & 0xF record.y = UnsignedByte.read(file_object) record.block_state_id = VarInt.read(file_object) return record @classmethod def send_with_context(self, record, socket, context): if context.protocol_version >= 741: value = (record.block_state_id << 12 | (record.x & 0xF) << 8 | (record.z & 0xF) << 4 | record.y & 0xF) VarLong.send(value, socket) else: UnsignedByte.send(record.x << 4 | record.z & 0xF, socket) UnsignedByte.send(record.y, socket) VarInt.send(record.block_state_id, socket)
class PositionAndLookPacket(Packet): @staticmethod def get_id(context): return 0x13 if context.protocol_version >= 712 else \ 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 VehicleMovePacket(Packet): @staticmethod def get_id(context): return 0x15 if context.protocol_version >= 464 else \ 0x13 if context.protocol_version >= 389 else \ 0x11 if context.protocol_version >= 386 else \ 0x10 if context.protocol_version >= 345 else \ 0x0F if context.protocol_version >= 343 else \ 0x10 if context.protocol_version >= 336 else \ 0x11 if context.protocol_version >= 318 else \ 0x10 packet_name = "vehicle move" definition = [{ 'x': Double }, { 'y': Double }, { 'z': Double }, { 'yaw': Float }, { 'pitch': Float }] # The code under this line was copied from the packets/clientbound/play/player_position_and_look_packet.py # 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 EntityPositionDeltaPacket(Packet): @staticmethod def get_id(context): return 0x27 if context.protocol_later_eq(741) else \ 0x28 if context.protocol_later_eq(721) else \ 0x29 if context.protocol_later_eq(550) else \ 0x28 if context.protocol_later_eq(389) else \ 0x27 if context.protocol_later_eq(345) else \ 0x26 if context.protocol_later_eq(318) else \ 0x25 if context.protocol_later_eq(94) else \ 0x26 if context.protocol_later_eq(70) else \ 0x15 packet_name = "entity position delta" @staticmethod def get_definition(context): delta_type = FixedPoint(Short, 12) \ if context.protocol_later_eq(106) else \ FixedPoint(Byte) return [ { 'entity_id': VarInt }, { 'delta_x_float': delta_type }, { 'delta_y_float': delta_type }, { 'delta_z_float': delta_type }, { 'on_ground': Boolean }, ] delta_position = multi_attribute_alias(Vector, 'delta_x_float', 'delta_y_float', 'delta_z_float') # The following transforms are retained for backward compatibility; # they represent the delta values as fixed-point integers with 12 bits # of fractional part, regardless of the protocol version. delta_x = attribute_transform('delta_x_float', lambda x: int(x * 4096), lambda x: x / 4096) delta_y = attribute_transform('delta_y_float', lambda y: int(y * 4096), lambda y: y / 4096) delta_z = attribute_transform('delta_z_float', lambda z: int(z * 4096), lambda z: z / 4096)
class Record(MutableRecord): __slots__ = 'x', 'y', 'z', 'block_state_id', 'location' 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, parent): 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) # Absolute position in world to be compatible with BlockChangePacket self.location = Vector(self.position.x + parent.chunk_x * 16, self.position.y, self.position.z + parent.chunk_z * 16) 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 PlayerPositionAndLookPacket(Packet, BitFieldEnum): @staticmethod def get_id(context): return ( 0x34 if context.protocol_later_eq(741) else 0x35 if context.protocol_later_eq(721) else 0x36 if context.protocol_later_eq(550) else 0x35 if context.protocol_later_eq(471) else 0x33 if context.protocol_later_eq(451) else 0x32 if context.protocol_later_eq(389) else 0x31 if context.protocol_later_eq(352) else 0x30 if context.protocol_later_eq(345) else 0x2F if context.protocol_later_eq(336) else 0x2E if context.protocol_later_eq(332) else 0x2F if context.protocol_later_eq(318) else 0x2E if context.protocol_later_eq(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_later_eq(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 FacePlayerPacket(Packet): @staticmethod def get_id(context): return 0x33 if context.protocol_version >= 741 else \ 0x34 if context.protocol_version >= 721 else \ 0x35 if context.protocol_version >= 550 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 FacePlayerPacket(Packet): @staticmethod def get_id(context): return (0x33 if context.protocol_later_eq(741) else 0x34 if context.protocol_later_eq(721) else 0x35 if context.protocol_later_eq(550) else 0x34 if context. protocol_later_eq(471) else 0x32 if context.protocol_later_eq( 451) else 0x31 if context.protocol_later_eq(389) else 0x30) packet_name = "face player" @property def fields(self): return (("origin", "x", "y", "z", "entity_id", "entity_origin") if self.context.protocol_later_eq(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_later_eq(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_later_eq(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 MultiBlockChangePacket(Packet): @staticmethod def get_id(context): return 0x10 if context.protocol_version >= 550 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', 'location' 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, parent): 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) # Absolute position in world to be compatible with BlockChangePacket self.location = Vector(self.position.x + parent.chunk_x * 16, self.position.y, self.position.z + parent.chunk_z * 16) 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) 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)
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): # XXX This has not been updated for >= v1.15 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 PlayerPositionAndLookPacket(Packet, BitFieldEnum): @staticmethod def get_id(context): return 0x36 if context.protocol_version >= 550 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 (0x3B if context.protocol_version >= 741 else 0x0F if context.protocol_version >= 721 else 0x10 if context.protocol_version >= 550 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" # Only used in protocol 741 and later. class ChunkSectionPos(Vector, Type): @classmethod def read(cls, file_object): value = Long.read(file_object) x = value >> 42 z = (value >> 20) & 0x3FFFFF y = value & 0xFFFFF return cls(x, y, z) @classmethod def send(cls, pos, socket): x, y, z = pos value = (x & 0x3FFFFF) << 42 | (z & 0x3FFFFF) << 20 | y & 0xFFFFF Long.send(value, socket) class Record(MutableRecord, Type): __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") @classmethod def read_with_context(cls, file_object, context): record = cls() if context.protocol_version >= 741: value = VarLong.read(file_object) record.block_state_id = value >> 12 record.x = (value >> 8) & 0xF record.z = (value >> 4) & 0xF record.y = value & 0xF else: h_position = UnsignedByte.read(file_object) record.x = h_position >> 4 record.z = h_position & 0xF record.y = UnsignedByte.read(file_object) record.block_state_id = VarInt.read(file_object) return record @classmethod def send_with_context(self, record, socket, context): if context.protocol_version >= 741: value = (record.block_state_id << 12 | (record.x & 0xF) << 8 | (record.z & 0xF) << 4 | record.y & 0xF) VarLong.send(value, socket) else: UnsignedByte.send(record.x << 4 | record.z & 0xF, socket) UnsignedByte.send(record.y, socket) VarInt.send(record.block_state_id, socket) get_definition = staticmethod(lambda context: [ { "chunk_section_pos": MultiBlockChangePacket.ChunkSectionPos }, { "invert_trust_edges": Boolean } if context.protocol_version >= 748 else {}, # Provisional field name. { "records": PrefixedArray(VarInt, MultiBlockChangePacket.Record) }, ] if context.protocol_version >= 741 else [ { "chunk_x": Integer }, { "chunk_z": Integer }, { "records": PrefixedArray(VarInt, MultiBlockChangePacket.Record) }, ]) # Access the 'chunk_x' and 'chunk_z' fields as a tuple. # Only used prior to protocol 741. chunk_pos = multi_attribute_alias(tuple, "chunk_x", "chunk_z")
class Chunk: position = multi_attribute_alias(Vector, 'x', 'y', 'z') def __init__(self, x, y, z, empty=True): self.x = x self.y = y self.z = z self.empty = empty self.entities = [] def __repr__(self): return 'Chunk(%r, %r, %r)' % (self.x, self.y, self.z) def read(self, file_object): self.empty = False self.block_count = Short.read(file_object) self.bpb = UnsignedByte.read(file_object) if self.bpb <= 4: self.bpb = 4 if self.bpb <= 8: # Indirect palette self.palette = [] size = VarInt.read(file_object) for i in range(size): self.palette.append(VarInt.read(file_object)) else: # Direct palette self.palette = None size = VarInt.read(file_object) longs = [] for i in range(size): longs.append(UnsignedLong.read(file_object)) self.blocks = [] mask = (1 << self.bpb)-1 for i in range(4096): l1 = int((i*self.bpb)/64) offset = (i*self.bpb)%64 l2 = int(((i+1)*self.bpb-1)/64) n = longs[l1] >> offset if l2>l1: n |= longs[l2] << (64-offset) n &= mask if self.palette: n = self.palette[n] self.blocks.append(n) def write_fields(self, packet_buffer): pass # TODO def get_block_at(self, x, y, z): if self.empty: return 0 return self.blocks[x+y*256+z*16] def set_block_at(self, x, y, z, block): if self.empty: self.init_empty() self.blocks[x+y*256+z*16] = block def init_empty(self): self.blocks = [] for i in range(4096): self.blocks.append(0) self.empty = False @property def origin(self): return self.position*16
class ExplosionPacket(Packet): @staticmethod def get_id(context): return ( 0x1B if context.protocol_later_eq(741) else 0x1C if context.protocol_later_eq(721) else 0x1D if context.protocol_later_eq(550) else 0x1C if context. protocol_later_eq(471) else 0x1E if context.protocol_later_eq(389) else 0x1D if context.protocol_later_eq(345) else 0x1C if context. protocol_later_eq(332) else 0x1D if context. protocol_later_eq(318) else 0x1C if context. protocol_later_eq(80) else 0x1B if context. protocol_later_eq(67) else 0x27) packet_name = "explosion" class Record(Vector, Type): __slots__ = () @classmethod def read(cls, file_object): return cls(*(Byte.read(file_object) for i in range(3))) @classmethod def send(cls, record, socket): for coord in record: Byte.send(coord, socket) definition = [ { "x": Float }, { "y": Float }, { "z": Float }, { "radius": Float }, { "records": PrefixedArray(Integer, Record) }, { "player_motion_x": Float }, { "player_motion_y": Float }, { "player_motion_z": Float }, ] # 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 SpawnObjectPacket(Packet): @staticmethod def get_id(context): return 0x00 if context.protocol_later_eq(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 name = "EntityType_%d" % context.protocol_version if hasattr(cls, name): return getattr(cls, name) era = 0 if context.protocol_earlier(458) else 1 class EntityType(Enum): # XXX This has not been updated for >= v1.15 ACTIVATED_TNT = (50, 55)[era] # PrimedTnt AREA_EFFECT_CLOUD = (3, 0)[era] ARMORSTAND = (78, 1)[era] ARROW = (60, 2)[era] BOAT = (1, 5)[era] DRAGON_FIREBALL = (93, 13)[era] EGG = (62, 74)[era] # ThrownEgg ENDERCRYSTAL = (51, 16)[era] ENDERPEARL = (65, 75)[era] # ThrownEnderpearl EVOCATION_FANGS = (79, 20)[era] EXP_BOTTLE = (75, 76)[era] # ThrownExpBottle EYE_OF_ENDER = (72, 23)[era] # EyeOfEnderSignal FALLING_OBJECT = (70, 24)[era] # FallingSand FIREBALL = (63, 34)[era] # Fireball (ghast) FIRECHARGE = (64, 65)[era] # SmallFireball (blaze) FIREWORK_ROCKET = (76, 25)[era] # FireworksRocketEntity FISHING_HOOK = (90, 93)[era] # Fishing bobber ITEM_FRAMES = (71, 33)[era] # ItemFrame ITEM_STACK = (2, 32)[era] # Item LEASH_KNOT = (77, 35)[era] LLAMA_SPIT = (68, 37)[era] MINECART = (10, 39)[era] # MinecartRideable POTION = (73, 77)[era] # ThrownPotion SHULKER_BULLET = (67, 60)[era] SNOWBALL = (61, 67)[era] SPECTRAL_ARROW = (91, 68)[era] WITHER_SKULL = (66, 85)[era] if context.protocol_later_eq(393): TRIDENT = 94 if context.protocol_later_eq(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_later_eq(49): self.object_uuid = UUID.read(file_object) if self.context.protocol_later_eq(458): self.type_id = VarInt.read(file_object) else: self.type_id = Byte.read(file_object) xyz_type = Double if self.context.protocol_later_eq(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_later_eq(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_later_eq(49): UUID.send(self.object_uuid, packet_buffer) if self.context.protocol_later_eq(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_later_eq(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_later_eq(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 MultiBlockChangePacket(Packet): @staticmethod def get_id(context): return 0x3F if context.protocol_later_eq(755) else \ 0x3B if context.protocol_later_eq(741) else \ 0x0F if context.protocol_later_eq(721) else \ 0x10 if context.protocol_later_eq(550) else \ 0x0F if context.protocol_later_eq(343) else \ 0x10 if context.protocol_later_eq(332) else \ 0x11 if context.protocol_later_eq(318) else \ 0x10 if context.protocol_later_eq(67) else \ 0x22 packet_name = 'multi block change' # Only used in protocol 741 and later. class ChunkSectionPos(Vector, Type): @classmethod def read(cls, file_object): value = UnsignedLong.read(file_object) y = value | ~0xFFFFF if value & 0x80000 else value & 0xFFFFF value >>= 20 z = value | ~0x3FFFFF if value & 0x200000 else value & 0x3FFFFF value >>= 22 x = value | ~0x3FFFFF if value & 0x200000 else value return cls(x, y, z) @classmethod def send(cls, pos, socket): x, y, z = pos value = (x & 0x3FFFFF) << 42 | (z & 0x3FFFFF) << 20 | y & 0xFFFFF UnsignedLong.send(value, socket) class Record(MutableRecord, Type): __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 before 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 before 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') @classmethod def read_with_context(cls, file_object, context): record = cls() if context.protocol_later_eq(741): value = VarLong.read(file_object) record.block_state_id = value >> 12 record.x = (value >> 8) & 0xF record.z = (value >> 4) & 0xF record.y = value & 0xF else: h_position = UnsignedByte.read(file_object) record.x = h_position >> 4 record.z = h_position & 0xF record.y = UnsignedByte.read(file_object) record.block_state_id = VarInt.read(file_object) return record @classmethod def send_with_context(self, record, socket, context): if context.protocol_later_eq(741): value = record.block_state_id << 12 | \ (record.x & 0xF) << 8 | \ (record.z & 0xF) << 4 | \ record.y & 0xF VarLong.send(value, socket) else: UnsignedByte.send(record.x << 4 | record.z & 0xF, socket) UnsignedByte.send(record.y, socket) VarInt.send(record.block_state_id, socket) get_definition = staticmethod(lambda context: [ { 'chunk_section_pos': MultiBlockChangePacket.ChunkSectionPos }, { 'invert_trust_edges': Boolean } if context.protocol_later_eq(748) else {}, # Provisional field name. { 'records': PrefixedArray(VarInt, MultiBlockChangePacket.Record) }, ] if context.protocol_later_eq(741) else [ { 'chunk_x': Integer }, { 'chunk_z': Integer }, { 'records': PrefixedArray(VarInt, MultiBlockChangePacket.Record) }, ]) # Access the 'chunk_x' and 'chunk_z' fields as a tuple. # Only used prior to protocol 741. chunk_pos = multi_attribute_alias(tuple, 'chunk_x', 'chunk_z')