Esempio n. 1
0
class ExplosionPacket(Packet):
    @staticmethod
    def get_id(context):
        return 0x1D if context.protocol_version >= 573 else \
               0x1C if context.protocol_version >= 471 else \
               0x1E if context.protocol_version >= 389 else \
               0x1D if context.protocol_version >= 345 else \
               0x1C if context.protocol_version >= 332 else \
               0x1D if context.protocol_version >= 318 else \
               0x1C if context.protocol_version >= 80 else \
               0x1B if context.protocol_version >= 67 else \
               0x27

    packet_name = 'explosion'

    fields = 'x', 'y', 'z', 'radius', 'records', \
             'player_motion_x', 'player_motion_y', 'player_motion_z'

    # Access the 'x', 'y', 'z' fields as a Vector tuple.
    position = multi_attribute_alias(Vector, 'x', 'y', 'z')

    # Access the 'player_motion_{x,y,z}' fields as a Vector tuple.
    player_motion = multi_attribute_alias(Vector, 'player_motion_x',
                                          'player_motion_y', 'player_motion_z')

    class Record(Vector):
        __slots__ = ()

    def read(self, file_object):
        self.x = Float.read(file_object)
        self.y = Float.read(file_object)
        self.z = Float.read(file_object)
        self.radius = Float.read(file_object)
        records_count = Integer.read(file_object)
        self.records = []
        for i in range(records_count):
            rec_x = Byte.read(file_object)
            rec_y = Byte.read(file_object)
            rec_z = Byte.read(file_object)
            record = ExplosionPacket.Record(rec_x, rec_y, rec_z)
            self.records.append(record)
        self.player_motion_x = Float.read(file_object)
        self.player_motion_y = Float.read(file_object)
        self.player_motion_z = Float.read(file_object)

    def write_fields(self, packet_buffer):
        Float.send(self.x, packet_buffer)
        Float.send(self.y, packet_buffer)
        Float.send(self.z, packet_buffer)
        Float.send(self.radius, packet_buffer)
        Integer.send(len(self.records), packet_buffer)
        for record in self.records:
            Byte.send(record.x, packet_buffer)
            Byte.send(record.y, packet_buffer)
            Byte.send(record.z, packet_buffer)
        Float.send(self.player_motion_x, packet_buffer)
        Float.send(self.player_motion_y, packet_buffer)
        Float.send(self.player_motion_z, packet_buffer)
Esempio n. 2
0
class SpawnPlayerPacket(Packet):
    @staticmethod
    def get_id(context):
        return 0x05 if context.protocol_version >= 67 else \
               0x0C

    packet_name = 'spawn player'
    get_definition = staticmethod(lambda context: [
        {
            'entity_id': VarInt
        },
        {
            'player_UUID': UUID
        },
        {
            'x': Double
        } if context.protocol_version >= 100 else {
            'x': FixedPointInteger
        },
        {
            'y': Double
        } if context.protocol_version >= 100 else {
            'y': FixedPointInteger
        },
        {
            'z': Double
        } if context.protocol_version >= 100 else {
            'z': FixedPointInteger
        },
        {
            'yaw': Angle
        },
        {
            'pitch': Angle
        },
        {
            'current_item': Short
        } if context.protocol_version <= 49 else {},
        # TODO: read entity metadata
    ])

    # Access the 'x', 'y', 'z' fields as a Vector tuple.
    position = multi_attribute_alias(Vector, 'x', 'y', 'z')

    # Access the 'yaw', 'pitch' fields as a Direction tuple.
    look = multi_attribute_alias(Direction, 'yaw', 'pitch')

    # Access the 'x', 'y', 'z', 'yaw', 'pitch' fields as a PositionAndLook.
    # NOTE: modifying the object retrieved from this property will not change
    # the packet; it can only be changed by attribute or property assignment.
    position_and_look = multi_attribute_alias(PositionAndLook, 'x', 'y', 'z',
                                              'yaw', 'pitch')
Esempio n. 3
0
class PositionAndLookPacket(Packet):
    @staticmethod
    def get_id(context):
        return 0x12 if context.protocol_version >= 471 else \
               0x13 if context.protocol_version >= 464 else \
               0x11 if context.protocol_version >= 389 else \
               0x0F if context.protocol_version >= 386 else \
               0x0E if context.protocol_version >= 345 else \
               0x0D if context.protocol_version >= 343 else \
               0x0E if context.protocol_version >= 336 else \
               0x0F if context.protocol_version >= 332 else \
               0x0E if context.protocol_version >= 318 else \
               0x0D if context.protocol_version >= 107 else \
               0x06

    packet_name = "position and look"
    definition = [
        {'x': Double},
        {'feet_y': Double},
        {'z': Double},
        {'yaw': Float},
        {'pitch': Float},
        {'on_ground': Boolean}]

    # Access the 'x', 'feet_y', 'z' fields as a Vector tuple.
    position = multi_attribute_alias(Vector, 'x', 'feet_y', 'z')

    # Access the 'yaw', 'pitch' fields as a Direction tuple.
    look = multi_attribute_alias(Direction, 'yaw', 'pitch')

    # Access the 'x', 'feet_y', 'z', 'yaw', 'pitch' fields as a
    # PositionAndLook.
    # NOTE: modifying the object retrieved from this property will not change
    # the packet; it can only be changed by attribute or property assignment.
    position_and_look = multi_attribute_alias(
        PositionAndLook, 'x', 'feet_y', 'z', 'yaw', 'pitch')
Esempio n. 4
0
    class Record(MutableRecord):
        __slots__ = 'x', 'y', 'z', 'block_state_id'

        def __init__(self, **kwds):
            self.block_state_id = 0
            super(MultiBlockChangePacket.Record, self).__init__(**kwds)

        # Access the 'x', 'y', 'z' fields as a Vector of ints.
        position = multi_attribute_alias(Vector, 'x', 'y', 'z')

        # For protocols < 347: an accessor for (block_state_id >> 4).
        @property
        def blockId(self):
            return self.block_state_id >> 4

        @blockId.setter
        def blockId(self, block_id):
            self.block_state_id = self.block_state_id & 0xF | block_id << 4

        # For protocols < 347: an accessor for (block_state_id & 0xF).
        @property
        def blockMeta(self):
            return self.block_state_id & 0xF

        @blockMeta.setter
        def blockMeta(self, meta):
            self.block_state_id = self.block_state_id & ~0xF | meta & 0xF

        # This alias is retained for backward compatibility.
        blockStateId = attribute_alias('block_state_id')

        def read(self, file_object):
            h_position = UnsignedByte.read(file_object)
            self.x, self.z = h_position >> 4, h_position & 0xF
            self.y = UnsignedByte.read(file_object)
            self.block_state_id = VarInt.read(file_object)

        def write(self, packet_buffer):
            UnsignedByte.send(self.x << 4 | self.z & 0xF, packet_buffer)
            UnsignedByte.send(self.y, packet_buffer)
            VarInt.send(self.block_state_id, packet_buffer)
Esempio n. 5
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):
            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')
Esempio n. 6
0
class FacePlayerPacket(Packet):
    @staticmethod
    def get_id(context):
        return 0x35 if context.protocol_version >= 573 else \
               0x34 if context.protocol_version >= 471 else \
               0x32 if context.protocol_version >= 451 else \
               0x31 if context.protocol_version >= 389 else \
               0x30

    packet_name = 'face player'

    @property
    def fields(self):
        return ('origin', 'x', 'y', 'z', 'entity_id', 'entity_origin') \
               if self.context.protocol_version >= 353 else \
               ('entity_id', 'x', 'y', 'z')

    # Access the 'x', 'y', 'z' fields as a Vector tuple.
    target = multi_attribute_alias(Vector, 'x', 'y', 'z')

    def read(self, file_object):
        if self.context.protocol_version >= 353:
            self.origin = VarInt.read(file_object)
            self.x = Double.read(file_object)
            self.y = Double.read(file_object)
            self.z = Double.read(file_object)
            is_entity = Boolean.read(file_object)
            if is_entity:
                # If the entity given by entity ID cannot be found,
                # this packet should be treated as if is_entity was false.
                self.entity_id = VarInt.read(file_object)
                self.entity_origin = VarInt.read(file_object)
            else:
                self.entity_id = None

        else:  # Protocol version 352
            is_entity = Boolean.read(file_object)
            self.entity_id = VarInt.read(file_object) if is_entity else None
            if not is_entity:
                self.x = Double.read(file_object)
                self.y = Double.read(file_object)
                self.z = Double.read(file_object)

    def write_fields(self, packet_buffer):
        if self.context.protocol_version >= 353:
            VarInt.send(self.origin, packet_buffer)
            Double.send(self.x, packet_buffer)
            Double.send(self.y, packet_buffer)
            Double.send(self.z, packet_buffer)
            if self.entity_id is not None:
                Boolean.send(True, packet_buffer)
                VarInt.send(self.entity_id, packet_buffer)
                VarInt.send(self.entity_origin, packet_buffer)
            else:
                Boolean.send(False, packet_buffer)

        else:  # Protocol version 352
            if self.entity_id is not None:
                Boolean.send(True, packet_buffer)
                VarInt.send(self.entity_id, packet_buffer)
            else:
                Boolean.send(False, packet_buffer)
                Double.send(self.x, packet_buffer)
                Double.send(self.y, packet_buffer)
                Double.send(self.z, packet_buffer)

    # These aliases declare the Enum type corresponding to each field:
    Origin = OriginPoint
    EntityOrigin = OriginPoint
Esempio n. 7
0
class PlayerPositionAndLookPacket(Packet, BitFieldEnum):
    @staticmethod
    def get_id(context):
        return 0x36 if context.protocol_version >= 573 else \
               0x35 if context.protocol_version >= 471 else \
               0x33 if context.protocol_version >= 451 else \
               0x32 if context.protocol_version >= 389 else \
               0x31 if context.protocol_version >= 352 else \
               0x30 if context.protocol_version >= 345 else \
               0x2F if context.protocol_version >= 336 else \
               0x2E if context.protocol_version >= 332 else \
               0x2F if context.protocol_version >= 318 else \
               0x2E if context.protocol_version >= 70 else \
               0x08

    packet_name = "player position and look"
    get_definition = staticmethod(lambda context: [
        {
            'x': Double
        },
        {
            'y': Double
        },
        {
            'z': Double
        },
        {
            'yaw': Float
        },
        {
            'pitch': Float
        },
        {
            'flags': Byte
        },
        {
            'teleport_id': VarInt
        } if context.protocol_version >= 107 else {},
    ])

    # Access the 'x', 'y', 'z' fields as a Vector tuple.
    position = multi_attribute_alias(Vector, 'x', 'y', 'z')

    # Access the 'yaw', 'pitch' fields as a Direction tuple.
    look = multi_attribute_alias(Direction, 'yaw', 'pitch')

    # Access the 'x', 'y', 'z', 'yaw', 'pitch' fields as a PositionAndLook.
    # NOTE: modifying the object retrieved from this property will not change
    # the packet; it can only be changed by attribute or property assignment.
    position_and_look = multi_attribute_alias(PositionAndLook, 'x', 'y', 'z',
                                              'yaw', 'pitch')

    field_enum = classmethod(lambda cls, field, context: cls
                             if field == 'flags' else None)

    FLAG_REL_X = 0x01
    FLAG_REL_Y = 0x02
    FLAG_REL_Z = 0x04
    FLAG_REL_YAW = 0x08
    FLAG_REL_PITCH = 0x10

    # This alias is retained for backward compatibility.
    PositionAndLook = PositionAndLook

    # Update a PositionAndLook instance using this packet.
    def apply(self, target):
        # pylint: disable=no-member
        if self.flags & self.FLAG_REL_X:
            target.x += self.x
        else:
            target.x = self.x

        if self.flags & self.FLAG_REL_Y:
            target.y += self.y
        else:
            target.y = self.y

        if self.flags & self.FLAG_REL_Z:
            target.z += self.z
        else:
            target.z = self.z

        if self.flags & self.FLAG_REL_YAW:
            target.yaw += self.yaw
        else:
            target.yaw = self.yaw

        if self.flags & self.FLAG_REL_PITCH:
            target.pitch += self.pitch
        else:
            target.pitch = self.pitch

        target.yaw %= 360
        target.pitch %= 360
Esempio n. 8
0
class MultiBlockChangePacket(Packet):
    @staticmethod
    def get_id(context):
        return 0x10 if context.protocol_version >= 573 else \
               0x0F if context.protocol_version >= 343 else \
               0x10 if context.protocol_version >= 332 else \
               0x11 if context.protocol_version >= 318 else \
               0x10 if context.protocol_version >= 67 else \
               0x22

    packet_name = 'multi block change'

    fields = 'chunk_x', 'chunk_z', 'records'

    # Access the 'chunk_x' and 'chunk_z' fields as a tuple.
    chunk_pos = multi_attribute_alias(tuple, 'chunk_x', 'chunk_z')

    class Record(MutableRecord):
        __slots__ = 'x', 'y', 'z', 'block_state_id'

        def __init__(self, **kwds):
            self.block_state_id = 0
            super(MultiBlockChangePacket.Record, self).__init__(**kwds)

        # Access the 'x', 'y', 'z' fields as a Vector of ints.
        position = multi_attribute_alias(Vector, 'x', 'y', 'z')

        # For protocols < 347: an accessor for (block_state_id >> 4).
        @property
        def blockId(self):
            return self.block_state_id >> 4

        @blockId.setter
        def blockId(self, block_id):
            self.block_state_id = self.block_state_id & 0xF | block_id << 4

        # For protocols < 347: an accessor for (block_state_id & 0xF).
        @property
        def blockMeta(self):
            return self.block_state_id & 0xF

        @blockMeta.setter
        def blockMeta(self, meta):
            self.block_state_id = self.block_state_id & ~0xF | meta & 0xF

        # This alias is retained for backward compatibility.
        blockStateId = attribute_alias('block_state_id')

        def read(self, file_object):
            h_position = UnsignedByte.read(file_object)
            self.x, self.z = h_position >> 4, h_position & 0xF
            self.y = UnsignedByte.read(file_object)
            self.block_state_id = VarInt.read(file_object)

        def write(self, packet_buffer):
            UnsignedByte.send(self.x << 4 | self.z & 0xF, packet_buffer)
            UnsignedByte.send(self.y, packet_buffer)
            VarInt.send(self.block_state_id, packet_buffer)

    def read(self, file_object):
        self.chunk_x = Integer.read(file_object)
        self.chunk_z = Integer.read(file_object)
        records_count = VarInt.read(file_object)
        self.records = []
        for i in range(records_count):
            record = self.Record()
            record.read(file_object)
            self.records.append(record)

    def write_fields(self, packet_buffer):
        Integer.send(self.chunk_x, packet_buffer)
        Integer.send(self.chunk_z, packet_buffer)
        VarInt.send(len(self.records), packet_buffer)
        for record in self.records:
            record.write(packet_buffer)