diff --git a/aiocraft/dispatcher.py b/aiocraft/dispatcher.py index 37e6d23..4f497a3 100644 --- a/aiocraft/dispatcher.py +++ b/aiocraft/dispatcher.py @@ -17,6 +17,7 @@ from .util import encryption LOGGER = logging.getLogger(__name__) +DIFFICULT_PACKETS = (28, 36) # Explosion, Map class InvalidState(Exception): pass @@ -194,6 +195,7 @@ class Dispatcher: length = await self._read_varint() return await self._down.readexactly(length) + async def _down_worker(self, timeout:float=30): while self._dispatching: try: # these 2 will timeout or raise EOFError if client gets disconnected @@ -215,6 +217,8 @@ class Dispatcher: buffer = io.BytesIO(decompressed_data) packet_id = VarInt.read(buffer) + if packet_id in DIFFICULT_PACKETS: + continue # don't try to parse, can't handle types this complex (yet! TODO) cls = self._packet_type_from_registry(packet_id) self._logger.debug("Deserializing packet %s | %s", str(cls), cls._state) packet = cls.deserialize(self.proto, buffer) @@ -222,8 +226,6 @@ class Dispatcher: await self._incoming.put(packet) if self.state != ConnectionState.PLAY: await self._incoming.join() # During play we can pre-process packets - except AttributeError: - self._logger.debug("Received unimplemented packet [%d] %s", packet_id, cls.__name__) # TODO this is cheating! implement them! except (asyncio.TimeoutError, TimeoutError): self._logger.error("Connection timed out") await self.disconnect(block=False) diff --git a/aiocraft/mc/types.py b/aiocraft/mc/types.py index d33207b..5640d21 100644 --- a/aiocraft/mc/types.py +++ b/aiocraft/mc/types.py @@ -1,8 +1,9 @@ import io import struct import asyncio +import uuid -from typing import Any +from typing import Any, Optional, Type as VarType class Type(object): _pytype : type @@ -138,6 +139,29 @@ class VarLong(VarInt): _pytype : type = int _size = 10 +# class Maybe(Type): # TODO better fucking name! +# _t : Type +# +# @classmethod +# def of(cls, t:Type) -> VarType[Maybe]: +# return type(f"Optional{t.__name__}", (Maybe,), {"_t":t}) +# +# @classmethod +# def write(cls, data:Optional[Any], buffer:io.BytesIO): +# if not hasattr(cls, "_t"): +# raise NotImplementedError +# Boolean.write(bool(data), buffer) +# if data: +# cls._t.write(data, buffer) +# +# @classmethod +# def read(cls, buffer:io.BytesIO) -> Optional[cls.T]: +# if not hasattr(cls, "_t"): +# raise NotImplementedError +# if Boolean.read(buffer): +# return cls._t.read(buffer) +# return None + class String(Type): _pytype : type = str @@ -189,36 +213,46 @@ class Angle(Type): _size : int = 1 _fmt : str = ">b" -class EntityMetadata(Type): - _pytype : type = bytes - # TODO - pass - class EntityMetadataItem(Type): _pytype : type = bytes # TODO pass -class Slot(Type): - _pytype : type = bytes - # TODO - pass - class NBTTag(Type): _pytype : type = bytes # TODO pass class Position(Type): - _pytype : type = bytes - # TODO - pass + _pytype : type = tuple + _size = 8 + # TODO THIS IS FOR 1.12.2!!! + + @classmethod + def write(cls, data:tuple, buffer:io.BytesIO): + packed = ((0x3FFFFFF & data[0]) << 38) | ((0xFFF & data[1]) << 26) | (0x3FFFFFF & data[2]) + UnsignedLong.write(packed, buffer) + + @classmethod + def read(cls, buffer:io.BytesIO) -> tuple: + packed = UnsignedLong.read(buffer) + x = packed >> 38 + y = (packed >> 24) & 0xFFF + z = packed & 0x3FFFFFF + return (x, y, z) class UUID(Type): - _pytype : type = bytes - # TODO - pass + _pytype : type = str + _size = 16 + + @classmethod + def write(cls, data:uuid.UUID, buffer:io.BytesIO): + buffer.write(int(data).to_bytes(cls._size, 'big')) + + @classmethod + def read(cls, buffer:io.BytesIO) -> uuid.UUID: + return uuid.UUID(int=int.from_bytes(buffer.read(cls._size), 'big')) class TrailingByteArray(Type): _pytype : type = bytes @@ -232,3 +266,12 @@ class TrailingByteArray(Type): def read(cls, buffer:io.BytesIO) -> bytes: return buffer.read() +class EntityMetadata(TrailingByteArray): + # TODO + pass + +class Slot(TrailingByteArray): + _pytype : type = bytes + # TODO + pass +