Пример #1
0
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)
Пример #3
0
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')
Пример #4
0
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')
Пример #5
0
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"
    )
Пример #6
0
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")
Пример #7
0
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')
Пример #8
0
    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)
Пример #9
0
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')
Пример #10
0
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')
Пример #11
0
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)
Пример #12
0
    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
Пример #14
0
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
Пример #15
0
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
Пример #16
0
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)
Пример #17
0
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')
Пример #18
0
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
Пример #19
0
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")
Пример #20
0
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
Пример #21
0
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")
Пример #22
0
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")
Пример #23
0
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')