Example #1
0
    def encode(self) -> bytes:
        out = b""

        for tags, REG in (
            (
                self.block,
                BLOCK_REGISTRY,
            ),
            (
                self.item,
                ITEM_REGISTRY,
            ),
            (
                self.fluid,
                FLUID_REGISTRY,
            ),
            (
                self.entity,
                ENTITY_REGISTRY,
            ),
        ):
            out += Buffer.pack_varint(len(tags))  # pack length

            for identifier in tags:
                # pack identifier name and  length of upcoming array
                out += Buffer.pack_string(identifier) + Buffer.pack_varint(
                    len(tags[identifier]))

                for value in tags[identifier]:
                    # values should be encoded as varints, so we need their id
                    out += Buffer.pack_varint(REG.encode(value))

        return out
Example #2
0
    def encode(self) -> bytes:
        out = Buffer.pack_varint(len(self.stats))

        for entry in self.stats:
            out += b"".join([Buffer.pack_varint(e) for e in entry])

        return out
Example #3
0
 def encode(self) -> bytes:
     return (
         Buffer.pack_varint(self.entity_id)
         + Buffer.pack("f", self.yaw)
         + Buffer.pack("f", self.pitch)
         + Buffer.pack("?", self.on_ground)
     )
Example #4
0
    def encode(self) -> bytes:
        out = Buffer.pack_varint(len(self.nodes))

        for node in self.nodes:
            pass  # idek yet

        return out + Buffer.pack_varint(0)
Example #5
0
 def encode(self) -> bytes:
     return (
         Buffer.pack_varint(self.eid)
         + Buffer.pack("h", self.vel_x)
         + Buffer.pack("h", self.vel_y)
         + Buffer.pack("h", self.vel_z)
     )
Example #6
0
 def encode(self) -> bytes:
     return (
         Buffer.pack_position(self.x, self.y, self.z)
         + Buffer.pack_varint(self.block)
         + Buffer.pack_varint(self.status)
         + Buffer.pack("?", self.successful)
     )
Example #7
0
async def login_start(stream: Stream, packet: Packet) -> tuple:
    if share["conf"][
            "online_mode"]:  # Online mode is enabled, so we request encryption
        lc = login_cache[stream.remote] = {
            "username": packet.username,
            "verify": None
        }

        packet = login_packets.LoginEncryptionRequest(
            share["rsa"]["public"].public_bytes(
                encoding=serialization.Encoding.DER,
                format=serialization.PublicFormat.SubjectPublicKeyInfo))

        lc["verify"] = packet.verify_token

        stream.write(Buffer.pack_packet(packet))
        await stream.drain()
    else:  # No need for encryption since online mode is off, just send login success
        uuid_ = (
            uuid.uuid4()
        )  # This should be only generated if the player name isn't found in the world data, but no way to do that rn

        stream.write(
            Buffer.pack_packet(
                login_packets.LoginSuccess(uuid_, packet.username),
                share["comp_thresh"]))
        await stream.drain()

        states[stream.remote] = 3  # Update state to play

    return True, stream
Example #8
0
async def encrypted_login(stream: Stream, packet: Packet) -> tuple:
    shared_key, auth = await server_auth(packet, stream.remote,
                                         login_cache[stream.remote])

    del login_cache[stream.remote]  # No longer needed

    if not auth:  # If authentication failed, disconnect client
        stream.write(
            Buffer.pack_packet(
                login_packets.LoginDisconnect(
                    "Failed to authenticate your connection.")))
        await stream.drain()
        return False, stream

    # Generate a cipher for that client using the shared key from the client
    cipher = encryption.gen_aes_cipher(shared_key)

    # Replace stream with one which auto decrypts + encrypts data when reading/writing
    stream = EncryptedStream(stream, cipher)

    if share["comp_thresh"] > 0:  # Send set compression packet if needed
        stream.write(
            Buffer.pack_packet(LoginSetCompression(share["comp_thresh"])))
        await stream.drain()

    # Send LoginSuccess packet, tells client they've logged in succesfully
    stream.write(
        Buffer.pack_packet(login_packets.LoginSuccess(*auth),
                           share["comp_thresh"]))
    await stream.drain()

    return True, stream
Example #9
0
 def encode(self) -> bytes:
     return (
         Buffer.pack_varint(self.sound_id)
         + Buffer.pack_varint(self.category)
         + Buffer.pack_varint(self.eid)
         + Buffer.pack("f", self.volume)
         + Buffer.pack("f", self.pitch)
     )
Example #10
0
 def encode(self) -> bytes:
     return (
         Buffer.pack_varint(self.entity_id)
         + Buffer.pack("h", self.dx)
         + Buffer.pack("h", self.dy)
         + Buffer.pack("h", self.dz)
         + Buffer.pack("?", self.on_ground)
     )
Example #11
0
 def encode(self) -> bytes:
     return (
         Buffer.pack_string(" " * 20)
         + Buffer.pack_varint(len(self.public_key))
         + self.public_key
         + Buffer.pack_varint(len(self.verify_token))
         + self.verify_token
     )
Example #12
0
 def decode(cls, buf: Buffer) -> PlayUpdateSign:
     return cls(
         *buf.unpack_position(),
         buf.unpack_string(),
         buf.unpack_string(),
         buf.unpack_string(),
         buf.unpack_string(),
     )
Example #13
0
 def encode(self) -> bytes:
     return (
         Buffer.pack("d", self.x)
         + Buffer.pack("d", self.y)
         + Buffer.pack("d", self.z)
         + Buffer.pack("f", self.yaw)
         + Buffer.pack("f", self.pitch)
     )
Example #14
0
async def handle_packet(stream: Stream):
    packet_length = 0

    # Basically an implementation of Buffer.unpack_varint()
    # except designed to read directly from a a StreamReader
    # and also to handle legacy server list ping packets
    for i in range(5):
        try:
            read = await asyncio.wait_for(stream.read(1), 5)
        except asyncio.TimeoutError:
            logger.debug("Closing due to timeout on read...")
            return False, stream

        if read == b"":
            logger.debug("Closing due to invalid read....")
            return False, stream

        if i == 0 and read == b"\xFE":
            logger.warn("Legacy ping attempted, legacy ping is not supported.")
            return False, stream

        b = struct.unpack("B", read)[0]
        packet_length |= (b & 0x7F) << 7 * i

        if not b & 0x80:
            break

    if packet_length & (1 << 31):
        packet_length -= 1 << 32

    buf = Buffer(await stream.read(packet_length))

    state = STATES.encode(states.get(stream.remote, 0))
    packet = buf.unpack_packet(state, PACKET_MAP)

    logger.debug(
        f"IN : state:{state:<11} | id:0x{packet.id:02X} | packet:{type(packet).__name__}"
    )

    for handler in pymine_api.packet.PACKET_HANDLERS[state][packet.id]:
        resp_value = await handler(stream, packet)

        try:
            continue_, stream = resp_value
        except (
                ValueError,
                TypeError,
        ):
            logger.warn(
                f"Invalid return from packet handler: {handler.__module__}.{handler.__qualname__}"
            )
            continue

        if not continue_:
            return False, stream

    return continue_, stream
Example #15
0
 def decode(cls, buf: Buffer) -> PlayPlayerPositionAndRotationServerBound:
     return cls(
         buf.unpack("d"),
         buf.unpack("d"),
         buf.unpack("d"),
         buf.unpack("d"),
         buf.unpack("d"),
         buf.unpack("?"),
     )
Example #16
0
    def encode(self) -> bytes:
        out = Buffer.pack_varint(self.action)

        if 2 >= self.action >= 0:
            out += Buffer.pack_chat(Chat(self.data))
        elif self.action == 3:
            out += b"".join([Buffer.pack("i", i) for i in self.data])

        return out
Example #17
0
 def decode(cls, buf: Buffer) -> PlayUpdateJigsawBlock:
     return cls(
         *buf.unpack_pos(),
         buf.unpack_string(),
         buf.unpack_string(),
         buf.unpack_string(),
         buf.unpack_string(),
         buf.unpack_string(),
     )
Example #18
0
 def decode(cls, buf: Buffer) -> PlayClientSettings:
     return cls(
         buf.unpack_string(),
         buf.unpack("b"),
         buf.unpack_varint(),
         buf.unpack("?"),
         buf.unpack("B"),
         buf.unpack_varint(),
     )
Example #19
0
 def decode(cls, buf: Buffer) -> PlayClickWindow:
     return cls(
         buf.unpack("B"),
         buf.unpack("h"),
         buf.unpack("b"),
         buf.unpack("h"),
         buf.unpack_varint(),
         buf.unpack_slot(),
     )
Example #20
0
    def encode(self) -> bytes:
        out = Buffer.pack_varint(self.entity_id)

        for prop in self.properties:
            out += (
                Buffer.pack_string(prop["key"])
                + Buffer.pack("d", prop["value"])
                + Buffer.pack_varint(len(prop["modifiers"]))
                + b"".join([Buffer.pack_modifier(m) for m in prop["modifiers"]])
            )
Example #21
0
 def decode(cls, buf: Buffer) -> PlayBlockPlacement:
     return cls(
         buf.unpack_varint(),
         *buf.unpack_pos(),
         buf.unpack_varint(),
         buf.unpack("f"),
         buf.unpack("f"),
         buf.unpack("f"),
         buf.unpack("?"),
     )
Example #22
0
 def decode(cls, buf: Buffer) -> PlayInteractEntity:
     return cls(
         buf.unpack_varint(),
         buf.unpack_varint(),
         buf.unpack_optional(buf.unpack_varint),
         buf.unpack_optional(buf.unpack_varint),
         buf.unpack_optional(buf.unpack_varint),
         buf.unpack_optional(buf.unpack_varint),
         buf.unpack("?"),
     )
Example #23
0
 def encode(self) -> bytes:
     return (Buffer.pack("f", self.x) + Buffer.pack("f", self.y) +
             Buffer.pack("f", self.z) + Buffer.pack("f", self.strength) +
             Buffer.pack("i", self.record_count) +
             Buffer.pack_array("b", self.records) +
             Buffer.pack("f", self.pmx) + Buffer.pack("f", self.pmy) +
             Buffer.pack("f", self.pmz))
Example #24
0
 def encode(self) -> bytes:
     return (Buffer.pack("f", self.x) + Buffer.pack("f", self.y) +
             Buffer.pack("f", self.z) + Buffer.pack("f", self.strength) +
             Buffer.pack("i", self.record_count) +
             b"".join([Buffer.pack("b", r) for r in self.records]) +
             Buffer.pack("f", self.pmx) + Buffer.pack("f", self.pmy) +
             Buffer.pack("f", self.pmz))
Example #25
0
def test_basic():
    buf = Buffer()

    buf.write(
        Buffer.pack("i", 123) + Buffer.pack("b", 1) + Buffer.pack("?", True) +
        Buffer.pack("q", 1234567890456))
    assert buf.buf == b"\x00\x00\x00{\x01\x01\x00\x00\x01\x1fq\xfb\x06\x18"

    assert buf.unpack("i") == 123
    assert buf.unpack("b") == 1
    assert buf.unpack("?") is True
    assert buf.unpack("q") == 1234567890456
Example #26
0
    def encode(self) -> bytes:
        # if self.event == 0:  # start combat
        #     return Buffer.pack_varint(self.event)
        #
        # if self.event == 1:  # end combat
        #     return Buffer.pack_varint(self.event) + Buffer.pack_varint(self.data['duration']) + \
        #         Buffer.pack('i', self.data['opponent'])

        if self.event == 2:  # entity dead, only one actually used
            return (Buffer.pack_varint(self.event) +
                    Buffer.pack_varint(self.data["player_id"]) +
                    Buffer.pack("i", self.data["entity_id"]) +
                    Buffer.pack_chat(self.data["message"]))
Example #27
0
    def encode(self) -> bytes:
        out = (Buffer.pack_varint(((self.chunk_sect_x & 0x3FFFFF) << 42)
                                  | (self.chunk_sect_y & 0xFFFFF) | (
                                      (self.chunk_sect_z & 0x3FFFFF) << 20)) +
               Buffer.pack("?", self.trust_edges) +
               Buffer.pack_varint(len(self.blocks)))

        for block_id, local_x, local_y, local_z in self.blocks:
            out += Buffer.pack_varint(block_id << 12
                                      | (local_x << 8 | local_z << 4
                                         | local_y))

        return out
Example #28
0
def test_varint(var_int, error_msg):
    buf = Buffer()
    if error_msg:
        with pytest.raises(ValueError) as err:

            buf.write(Buffer.pack_varint(var_int))
            assert error_msg in str(err)
    else:
        buf.write(Buffer.pack_varint(var_int))
        assert buf.unpack_varint() == var_int
Example #29
0
 def encode(self) -> bytes:
     return (Buffer.pack_string(self.name) +
             Buffer.pack_varint(self.category) +
             Buffer.pack("i", self.category) +
             Buffer.pack("i", self.effect_pos_x) +
             Buffer.pack("i", self.effect_pos_y) +
             Buffer.pack("i", self.effect_pos_z) +
             Buffer.pack("f", self.volume) + Buffer.pack("f", self.pitch))
Example #30
0
    async def fetch_player(self, uuid_: uuid.UUID) -> Player:
        try:
            return self.cache[int(uuid_)]
        except KeyError:
            file = os.path.join(self.data_dir, f"{uuid_}.dat")  # filename of the player

            if not os.path.isfile(file):  # create new player if needed
                level_data = self.server.worlds["minecraft:overworld"].data

                player = Player.new(
                    self.server.api.eid(),
                    uuid_,
                    (level_data["SpawnX"], level_data["SpawnY"], level_data["SpawnX"]),
                    "minecraft:overworld",
                )
                self.cache[int(player.uuid)] = player

                return player

            async with aiofile.async_open(file, "rb") as player_file:  # load preexisting
                player = Player(
                    self.server.eid(), nbt.TAG_Compound.unpack(Buffer(await player_file.read()))
                )
                self.cache[player.uuid] = player

                return player