diff --git a/bta_proxy/datainputstream.py b/bta_proxy/datainputstream.py index a0ec305..dc9fbc4 100644 --- a/bta_proxy/datainputstream.py +++ b/bta_proxy/datainputstream.py @@ -4,17 +4,29 @@ import struct class AsyncDataInputStream: def __init__(self, queue: Queue): self._queue = queue + self._buffer = b'' self._last = b'' + def read_rest(self): + out = self._buffer + self._buffer = b'' + return out + async def read_bytes(self, n: int) -> bytes: - if len(self._last) < n: - self._last += await self._queue.get() - out, self._last = self._last[:n], self._last[n:] + if len(self._buffer) < n: + self._last = (await self._queue.get()) + self._buffer += self._last + out, self._buffer = self._buffer[:n], self._buffer[n:] return out async def read(self) -> int: return (await self.read_bytes(1))[0] + read_ubyte = read + + async def read_byte(self) -> int: + return struct.unpack('b', await self.read_bytes(1))[0] + async def read_boolean(self) -> bool: return (await self.read()) != 0 @@ -59,8 +71,12 @@ class AsyncDataInputStream: return value async def read_string(self) -> str: + last = self._last size = await self.read_short() - return (await self.read_bytes(size)).decode('utf-8') + try: + return (await self.read_bytes(size)).decode('utf-8') + except Exception as e: + raise ValueError(f'failed reading string of size {size} in {last}') from e class SyncDataInputStream: def __init__(self, buffer: bytes): diff --git a/bta_proxy/dpi.py b/bta_proxy/dpi.py index f9b2294..60a19ba 100644 --- a/bta_proxy/dpi.py +++ b/bta_proxy/dpi.py @@ -1,5 +1,6 @@ from asyncio.queues import Queue +import time from bta_proxy.datainputstream import AsyncDataInputStream from bta_proxy.packets import * @@ -7,8 +8,13 @@ from bta_proxy.packets import * async def inspect_client(queue: Queue, addr: tuple[str, int]): dis = AsyncDataInputStream(queue) + last_time = time.time() while True: pkt = await Packet.read_packet(dis) + now = time.time() + delta = now - last_time + last_time = now + match pkt.packet_id: case Packet10Flying.packet_id: continue @@ -21,10 +27,27 @@ async def inspect_client(queue: Queue, addr: tuple[str, int]): case Packet255KickDisconnect.packet_id: break case _: - print("C", pkt) + print(f"C {delta*1000:+8.1f}ms {pkt}") async def inspect_server(queue: Queue, addr: tuple[str, int]): dis = AsyncDataInputStream(queue) + last_time = time.time() while True: pkt = await Packet.read_packet(dis) - print("S", pkt) + now = time.time() + delta = now - last_time + last_time = now + + match pkt.packet_id: + case Packet50PreChunk.packet_id: + continue + case Packet51MapChunk.packet_id: + continue + case Packet31RelEntityMove.packet_id: + continue + case Packet32EntityLook.packet_id: + continue + case Packet33RelEntityMoveLook.packet_id: + continue + case _: + print(f"S {delta*1000:+8.1f}ms {pkt}") diff --git a/bta_proxy/entitydata.py b/bta_proxy/entitydata.py index 889b01b..0c6474d 100644 --- a/bta_proxy/entitydata.py +++ b/bta_proxy/entitydata.py @@ -26,6 +26,7 @@ class EntityData: async def read_from(cls, dis: AsyncDataInputStream) -> list[DataItem]: items = [] while (data := await dis.read()) != 0x7F: + print(f"========= EntityData.read_from {data=} ({(data & 0xE0) >> 5})") item_type = DataItemType((data & 0xE0) >> 5) item_id: int = data & 0x1F match item_type: diff --git a/bta_proxy/itemstack.py b/bta_proxy/itemstack.py index 6888d41..209762b 100644 --- a/bta_proxy/itemstack.py +++ b/bta_proxy/itemstack.py @@ -1,13 +1,15 @@ +from typing import Any from bta_proxy.datainputstream import AsyncDataInputStream, SyncDataInputStream class ItemStack: - __slots__ = ("item_id", "count", "data") - def __init__(self, item_id: int, count: int, data: int): + __slots__ = ("item_id", "count", "data", "tag") + def __init__(self, item_id: int, count: int, data: int, tag: Any = None): self.item_id = item_id self.count = count self.data = data + self.tag = tag @classmethod async def read_from(cls, stream: AsyncDataInputStream) -> 'ItemStack': @@ -22,3 +24,8 @@ class ItemStack: count = stream.read() data = stream.read_ushort() return cls(item_id, count, data) + + def __repr__(self): + if self.tag: + return f'' + return f'' diff --git a/bta_proxy/packets/__init__.py b/bta_proxy/packets/__init__.py index 14d2a16..d3023c8 100644 --- a/bta_proxy/packets/__init__.py +++ b/bta_proxy/packets/__init__.py @@ -29,3 +29,32 @@ from .packet15place import Packet15Place from .packet255kickdisconnect import Packet255KickDisconnect from .packet255kickdisconnect import Packet255KickDisconnect from .packet102windowclick import Packet102WindowClick +from .packet7useentity import Packet7UseEntity +from .packet8updatehealth import Packet8UpdateHealth +from .packet21pickupspawn import Packet21PickupSpawn +from .packet23vehiclespawn import Packet23VehicleSpawn +from .packet28entityvelocity import Packet28EntityVelocity +from .packet41entityplayergamemode import Packet41EntityPlayerGamemode +from .packet104windowitems import Packet104WindowItems +from .packet104windowitems import Packet104WindowItems +from .packet104windowitems import Packet104WindowItems +from .packet61playsoundeffect import Packet61PlaySoundEffect +from .packet104windowitems import Packet104WindowItems +from .packet103setslot import Packet103SetSlot +from .packet31relentitymove import Packet31RelEntityMove +from .packet29destroyentity import Packet29DestroyEntity +from .packet33relentitymovelook import Packet33RelEntityMoveLook +from .packet32entitylook import Packet32EntityLook +from .packet34entityteleport import Packet34EntityTeleport +from .packet30entity import Packet30Entity +from .packet40entitymetadata import Packet40EntityMetadata +from .packet53blockchange import Packet53BlockChange +from .packet51mapchunk import Packet51MapChunk +from .packet51mapchunk import Packet51MapChunk +from .packet140tileentitydata import Packet140TileEntityData +from .packet132setmobspawner import Packet132SetMobSpawner +from .packet39attachentity import Packet39AttachEntity +from .packet35entitynickname import Packet35EntityNickname +from .packet52multiblockchange import Packet52MultiBlockChange +from .packet20statistic import Packet20Statistic +from .packet0keepalive import Packet0KeepAlive diff --git a/bta_proxy/packets/base.py b/bta_proxy/packets/base.py index 8e375ea..83c840f 100644 --- a/bta_proxy/packets/base.py +++ b/bta_proxy/packets/base.py @@ -1,11 +1,19 @@ -from typing import Any, ClassVar, Type +from typing import Any, ClassVar, Optional, Type, Union from bta_proxy.entitydata import EntityData from bta_proxy.itemstack import ItemStack from ..datainputstream import AsyncDataInputStream + +def try_int(v: str) -> Union[str, int]: + try: + return int(v) + except ValueError: + return v + + class Packet: - REGISTRY: ClassVar[dict[int, Type['Packet']]] = {} + REGISTRY: ClassVar[dict[int, Type["Packet"]]] = {} FIELDS: ClassVar[list[tuple[str, Any]]] = [] packet_id: int @@ -14,81 +22,157 @@ class Packet: setattr(self, k, v) @classmethod - async def read_data_from(cls, stream: AsyncDataInputStream) -> 'Packet': + async def read_data_from(cls, stream: AsyncDataInputStream) -> "Packet": fields: dict = {} for key, datatype in cls.FIELDS: - fields[key] = await cls.read_field(stream, datatype, fields) + if "?" in key: + key, cond = key.split("?", 1) + if "==" in cond: + k, v = cond.split("==") + if fields[k] != try_int(v): + continue + elif not fields[cond]: + continue + try: + fields[key] = await cls.read_field(stream, datatype, fields) + except Exception as e: + raise ValueError(f"Failed getting key {key} on {cls}") from e return cls(**fields) @staticmethod - async def read_field(stream: AsyncDataInputStream, datatype: Any, fields: dict[str, Any] = {}): + async def read_field( + stream: AsyncDataInputStream, + datatype: Any, + fields: dict[str, Any] = {}, + ): match datatype: - case 'uint': + case "list", sizekey, *args: + return [ + await Packet.read_field(stream, args, fields) + for _ in range(fields[sizekey]) + ] + case "uint": return await stream.read_uint() - case 'int': + case "int": return await stream.read_int() - case 'str': + case "str": return await stream.read_string() - case 'str', length: + case "str", length: return (await stream.read_string())[:length] - case 'string': + case "string": return await stream.read_string() - case 'string', length: + case "string", length: return (await stream.read_string())[:length] - case 'ulong': + case "ulong": return await stream.read_ulong() - case 'long': + case "long": return await stream.read_long() - case 'ushort': + case "ushort": return await stream.read_ushort() - case 'short': + case "short": return await stream.read_short() - case 'byte': - return await stream.read() - case 'float': + case "byte": + return await stream.read_byte() + case "ubyte": + return await stream.read_ubyte() + case "float": return await stream.read_float() - case 'double': + case "double": return await stream.read_double() - case 'bool': + case "bool": return await stream.read_boolean() - case 'bytes', length_or_key: + case "bytes", length_or_key: if isinstance(length_or_key, int): return await stream.read_bytes(length_or_key) elif isinstance(length_or_key, str): + if length_or_key == ".rest": + return stream.read_rest() if length_or_key not in fields: - raise KeyError(f'failed to find {length_or_key} in {fields} to read bytes length') + raise KeyError( + f"failed to find {length_or_key} in {fields} to read bytes length" + ) return await stream.read_bytes(fields[length_or_key]) - raise ValueError(f'invalid type for bytes length_or_key: {length_or_key!r}') - case 'itemstack': + raise ValueError( + f"invalid type for bytes length_or_key: {length_or_key!r}" + ) + case "itemstack": return await ItemStack.read_from(stream) - case 'itemstack_optional': + case "itemstack", length_or_key: + if isinstance(length_or_key, int): + items: list[Optional[ItemStack]] = [] + for _ in range(length_or_key): + if (item_id := await stream.read_short()) >= 0: + count = await stream.read() + data = await stream.read_short() + items.append(ItemStack(item_id, count, data)) + else: + items.append(None) + return items + elif isinstance(length_or_key, str): + if fields[length_or_key] <= 0: + return [] + if length_or_key not in fields: + raise KeyError( + f"failed to find {length_or_key} in {fields} to read number of itemstacks" + ) + items: list[Optional[ItemStack]] = [] + for _ in range(fields[length_or_key]): + if (item_id := await stream.read_short()) >= 0: + count = await stream.read() + data = await stream.read_short() + items.append(ItemStack(item_id, count, data)) + else: + items.append(None) + return items + raise ValueError( + f"invalid type for itemstack length_or_key: {length_or_key!r}" + ) + case "itemstack_optional": if (item_id := await stream.read_short()) >= 0: count = await stream.read() data = await stream.read_short() return ItemStack(item_id, count, data) return None - case 'entitydata': + case "extendeditemstack_optional": + if (item_id := await stream.read_short()) >= 0: + count = await stream.read() + data = await stream.read_short() + tag_size = await stream.read_short() + tag = await stream.read_bytes(tag_size) + return ItemStack(item_id, count, data, tag) + return None + case "entitydata": return await EntityData.read_from(stream) case _: - raise ValueError(f'unknown type {datatype}') + raise ValueError(f"unknown type {datatype}") def __init_subclass__(cls, packet_id: int, **kwargs) -> None: Packet.REGISTRY[packet_id] = cls cls.packet_id = packet_id super().__init_subclass__(**kwargs) + def post_creation(self): + pass + @classmethod - async def read_packet(cls, stream: AsyncDataInputStream) -> 'Packet': + async def read_packet(cls, stream: AsyncDataInputStream) -> "Packet": packet_id: int = await stream.read() if packet_id not in cls.REGISTRY: - raise ValueError(f'invalid packet 0x{packet_id:02x} ({packet_id})') + raise ValueError( + f"invalid packet 0x{packet_id:02x} ({packet_id}) (rest: {stream.read_rest()[:16]}...)" + ) pkt = await cls.REGISTRY[packet_id].read_data_from(stream) pkt.packet_id = packet_id + pkt.post_creation() return pkt def __repr__(self): pkt_name = self.REGISTRY[self.packet_id].__name__ fields = [] - for name, _ in self.FIELDS: - fields.append(f'{name}={getattr(self, name)!r}') + for key, _ in self.FIELDS: + if "?" in key: + key, cond = key.split("?", 1) + fields.append(f"{key}={getattr(self, key, None)!r} if {cond}") + else: + fields.append(f"{key}={getattr(self, key)!r}") return f'<{pkt_name} {str.join(", ", fields)}>' diff --git a/bta_proxy/packets/packet0keepalive.py b/bta_proxy/packets/packet0keepalive.py new file mode 100644 index 0000000..4af8c11 --- /dev/null +++ b/bta_proxy/packets/packet0keepalive.py @@ -0,0 +1,6 @@ +from .base import Packet + +class Packet0KeepAlive(Packet, packet_id=0): + __slots__ = () + FIELDS = [ + ] diff --git a/bta_proxy/packets/packet103setslot.py b/bta_proxy/packets/packet103setslot.py new file mode 100644 index 0000000..e2285d0 --- /dev/null +++ b/bta_proxy/packets/packet103setslot.py @@ -0,0 +1,8 @@ +from .base import Packet + +class Packet103SetSlot(Packet, packet_id=103): + FIELDS = [ + ('window_id', 'byte'), + ('slot', 'short'), + ('item', 'extendeditemstack_optional'), + ] diff --git a/bta_proxy/packets/packet104windowitems.py b/bta_proxy/packets/packet104windowitems.py new file mode 100644 index 0000000..baaa460 --- /dev/null +++ b/bta_proxy/packets/packet104windowitems.py @@ -0,0 +1,8 @@ +from .base import Packet + +class Packet104WindowItems(Packet, packet_id=104): + FIELDS = [ + ('window_id', 'byte'), + ('n_items', 'short'), + ('items', ('itemstack', 'n_items')), + ] diff --git a/bta_proxy/packets/packet132setmobspawner.py b/bta_proxy/packets/packet132setmobspawner.py new file mode 100644 index 0000000..acf52b4 --- /dev/null +++ b/bta_proxy/packets/packet132setmobspawner.py @@ -0,0 +1,10 @@ +from .base import Packet + +class Packet132SetMobSpawner(Packet, packet_id=132): + __slots__ = ('x', 'y', 'z', 'type') + FIELDS = [ + ('x', 'int'), + ('y', 'short'), + ('z', 'int'), + ('type', 'str'), + ] diff --git a/bta_proxy/packets/packet140tileentitydata.py b/bta_proxy/packets/packet140tileentitydata.py new file mode 100644 index 0000000..915cacd --- /dev/null +++ b/bta_proxy/packets/packet140tileentitydata.py @@ -0,0 +1,12 @@ +from .base import Packet +import gzip + +class Packet140TileEntityData(Packet, packet_id=140): + __slots__ = ('size', 'data') + FIELDS = [ + ('size', 'short'), + ('data', ('bytes', 'size')), + ] + + def post_creation(self): + self.data = gzip.decompress(self.data) diff --git a/bta_proxy/packets/packet14blockdig.py b/bta_proxy/packets/packet14blockdig.py index b494909..8ad015f 100644 --- a/bta_proxy/packets/packet14blockdig.py +++ b/bta_proxy/packets/packet14blockdig.py @@ -2,9 +2,9 @@ from .base import Packet class Packet14BlockDig(Packet, packet_id=14): FIELDS = [ - ('status', 'byte'), + ('status', 'ubyte'), ('x', 'int'), - ('y', 'byte'), + ('y', 'ubyte'), ('z', 'int'), - ('side', 'byte'), + ('side', 'ubyte'), ] diff --git a/bta_proxy/packets/packet15place.py b/bta_proxy/packets/packet15place.py index 245ac5b..8d3eaeb 100644 --- a/bta_proxy/packets/packet15place.py +++ b/bta_proxy/packets/packet15place.py @@ -3,9 +3,9 @@ from .base import Packet class Packet15Place(Packet, packet_id=15): FIELDS = [ ('x', 'int'), - ('y', 'byte'), + ('y', 'ubyte'), ('z', 'int'), - ('direction', 'byte'), + ('direction', 'ubyte'), ('y_placed', 'double'), ('item', 'itemstack_optional') ] diff --git a/bta_proxy/packets/packet20statistic.py b/bta_proxy/packets/packet20statistic.py new file mode 100644 index 0000000..3c8f025 --- /dev/null +++ b/bta_proxy/packets/packet20statistic.py @@ -0,0 +1,8 @@ +from .base import Packet + +class Packet20Statistic(Packet, packet_id=20): + __slots__ = ('field_27052_a', 'field_27051') + FIELDS = [ + ('field_27052_a', 'int'), + ('field_27051', 'byte'), + ] diff --git a/bta_proxy/packets/packet21pickupspawn.py b/bta_proxy/packets/packet21pickupspawn.py new file mode 100644 index 0000000..819002c --- /dev/null +++ b/bta_proxy/packets/packet21pickupspawn.py @@ -0,0 +1,17 @@ +from .base import Packet + +class Packet21PickupSpawn(Packet, packet_id=21): + FIELDS = [ + ('entity_id', 'int'), + ('item_id', 'short'), + ('count', 'byte'), + ('damage', 'short'), + ('tag_size', 'short'), + ('tag', ('bytes', 'tag_size')), + ('x', 'int'), + ('y', 'int'), + ('z', 'int'), + ('yaw', 'byte'), + ('pitch', 'byte'), + ('roll', 'byte'), + ] diff --git a/bta_proxy/packets/packet23vehiclespawn.py b/bta_proxy/packets/packet23vehiclespawn.py new file mode 100644 index 0000000..fdcb846 --- /dev/null +++ b/bta_proxy/packets/packet23vehiclespawn.py @@ -0,0 +1,17 @@ +from .base import Packet + +class Packet23VehicleSpawn(Packet, packet_id=23): + FIELDS = [ + ('entity_id', 'int'), + ('type', 'byte'), + ('x', 'int'), + ('y', 'int'), + ('z', 'int'), + ('pitch', 'float'), + ('yaw', 'float'), + ('vehicle_type', 'int'), + ('dx?vehicle_type', 'short'), + ('dy?vehicle_type', 'short'), + ('dz?vehicle_type', 'short'), + ('arrow_type?type==60', 'int'), + ] diff --git a/bta_proxy/packets/packet28entityvelocity.py b/bta_proxy/packets/packet28entityvelocity.py new file mode 100644 index 0000000..b4ff94a --- /dev/null +++ b/bta_proxy/packets/packet28entityvelocity.py @@ -0,0 +1,9 @@ +from .base import Packet + +class Packet28EntityVelocity(Packet, packet_id=28): + FIELDS = [ + ('entity_id', 'int'), + ('dx', 'short'), + ('dy', 'short'), + ('dz', 'short'), + ] diff --git a/bta_proxy/packets/packet29destroyentity.py b/bta_proxy/packets/packet29destroyentity.py new file mode 100644 index 0000000..fa8abfe --- /dev/null +++ b/bta_proxy/packets/packet29destroyentity.py @@ -0,0 +1,6 @@ +from .base import Packet + +class Packet29DestroyEntity(Packet, packet_id=29): + FIELDS = [ + ('entity_id', 'int'), + ] diff --git a/bta_proxy/packets/packet30entity.py b/bta_proxy/packets/packet30entity.py new file mode 100644 index 0000000..bde23a8 --- /dev/null +++ b/bta_proxy/packets/packet30entity.py @@ -0,0 +1,6 @@ +from .base import Packet + +class Packet30Entity(Packet, packet_id=30): + FIELDS = [ + ('entity_id', 'int'), + ] diff --git a/bta_proxy/packets/packet31relentitymove.py b/bta_proxy/packets/packet31relentitymove.py new file mode 100644 index 0000000..c80177a --- /dev/null +++ b/bta_proxy/packets/packet31relentitymove.py @@ -0,0 +1,9 @@ +from .base import Packet + +class Packet31RelEntityMove(Packet, packet_id=31): + FIELDS = [ + ('entity_id', 'int'), + ('x', 'byte'), + ('y', 'byte'), + ('z', 'byte'), + ] diff --git a/bta_proxy/packets/packet32entitylook.py b/bta_proxy/packets/packet32entitylook.py new file mode 100644 index 0000000..8c65fae --- /dev/null +++ b/bta_proxy/packets/packet32entitylook.py @@ -0,0 +1,8 @@ +from .base import Packet + +class Packet32EntityLook(Packet, packet_id=32): + FIELDS = [ + ('entity_id', 'int'), + ('yaw', 'byte'), + ('pitch', 'byte'), + ] diff --git a/bta_proxy/packets/packet33relentitymovelook.py b/bta_proxy/packets/packet33relentitymovelook.py new file mode 100644 index 0000000..e66c617 --- /dev/null +++ b/bta_proxy/packets/packet33relentitymovelook.py @@ -0,0 +1,11 @@ +from .base import Packet + +class Packet33RelEntityMoveLook(Packet, packet_id=33): + FIELDS = [ + ('entity_id', 'int'), + ('x', 'byte'), + ('y', 'byte'), + ('z', 'byte'), + ('yaw', 'byte'), + ('pitch', 'byte'), + ] diff --git a/bta_proxy/packets/packet34entityteleport.py b/bta_proxy/packets/packet34entityteleport.py new file mode 100644 index 0000000..f09ea41 --- /dev/null +++ b/bta_proxy/packets/packet34entityteleport.py @@ -0,0 +1,11 @@ +from .base import Packet + +class Packet34EntityTeleport(Packet, packet_id=34): + FIELDS = [ + ('entity_id', 'int'), + ('x', 'int'), + ('y', 'int'), + ('z', 'int'), + ('yaw', 'byte'), + ('pitch', 'byte'), + ] diff --git a/bta_proxy/packets/packet35entitynickname.py b/bta_proxy/packets/packet35entitynickname.py new file mode 100644 index 0000000..2e3c45d --- /dev/null +++ b/bta_proxy/packets/packet35entitynickname.py @@ -0,0 +1,9 @@ +from .base import Packet + +class Packet35EntityNickname(Packet, packet_id=35): + __slots__ = ('entity_id', 'name', 'color') + FIELDS = [ + ('entity_id', 'int'), + ('name', 'str'), + ('color', 'ubyte'), + ] diff --git a/bta_proxy/packets/packet39attachentity.py b/bta_proxy/packets/packet39attachentity.py new file mode 100644 index 0000000..e63bcee --- /dev/null +++ b/bta_proxy/packets/packet39attachentity.py @@ -0,0 +1,8 @@ +from .base import Packet + +class Packet39AttachEntity(Packet, packet_id=39): + __slots__ = ('entity_id', 'vehicle_entity_id') + FIELDS = [ + ('entity_id', 'int'), + ('vehicle_entity_id', 'int'), + ] diff --git a/bta_proxy/packets/packet40entitymetadata.py b/bta_proxy/packets/packet40entitymetadata.py new file mode 100644 index 0000000..78ea873 --- /dev/null +++ b/bta_proxy/packets/packet40entitymetadata.py @@ -0,0 +1,7 @@ +from .base import Packet + +class Packet40EntityMetadata(Packet, packet_id=40): + FIELDS = [ + ('entity_id', 'int'), + ('data', 'entitydata'), + ] diff --git a/bta_proxy/packets/packet41entityplayergamemode.py b/bta_proxy/packets/packet41entityplayergamemode.py new file mode 100644 index 0000000..6467d21 --- /dev/null +++ b/bta_proxy/packets/packet41entityplayergamemode.py @@ -0,0 +1,6 @@ +from .base import Packet + +class Packet41EntityPlayerGamemode(Packet, packet_id=41): + FIELDS = [ + ('gamemode', 'byte'), + ] diff --git a/bta_proxy/packets/packet51mapchunk.py b/bta_proxy/packets/packet51mapchunk.py new file mode 100644 index 0000000..7d269b0 --- /dev/null +++ b/bta_proxy/packets/packet51mapchunk.py @@ -0,0 +1,19 @@ +from .base import Packet + +class Packet51MapChunk(Packet, packet_id=51): + __slots__ = ('x', 'y', 'z', 'xs', 'ys', 'zs', 'size', 'data') + FIELDS = [ + ('x', 'int'), + ('y', 'short'), + ('z', 'int'), + ('xs', 'ubyte'), + ('ys', 'ubyte'), + ('zs', 'ubyte'), + ('size', 'int'), + ('data', ('bytes', 'size')), + ] + + def post_creation(self): + self.xs += 1 + self.ys += 1 + self.zs += 1 diff --git a/bta_proxy/packets/packet52multiblockchange.py b/bta_proxy/packets/packet52multiblockchange.py new file mode 100644 index 0000000..d84313c --- /dev/null +++ b/bta_proxy/packets/packet52multiblockchange.py @@ -0,0 +1,12 @@ +from .base import Packet + +class Packet52MultiBlockChange(Packet, packet_id=52): + __slots__ = ('x', 'z', 'size', 'coordinates', 'types', 'metadata') + FIELDS = [ + ('x', 'int'), + ('z', 'int'), + ('size', 'short'), + ('coordinates', ('list', 'size', 'short')), + ('types', ('list', 'size', 'short')), + ('metadata', ('list', 'size', 'ubyte')), + ] diff --git a/bta_proxy/packets/packet53blockchange.py b/bta_proxy/packets/packet53blockchange.py new file mode 100644 index 0000000..21a38e0 --- /dev/null +++ b/bta_proxy/packets/packet53blockchange.py @@ -0,0 +1,10 @@ +from .base import Packet + +class Packet53BlockChange(Packet, packet_id=53): + FIELDS = [ + ('x', 'int'), + ('y', 'ubyte'), + ('z', 'int'), + ('type', 'short'), + ('metadata', 'ubyte'), + ] diff --git a/bta_proxy/packets/packet61playsoundeffect.py b/bta_proxy/packets/packet61playsoundeffect.py new file mode 100644 index 0000000..84e7c9c --- /dev/null +++ b/bta_proxy/packets/packet61playsoundeffect.py @@ -0,0 +1,10 @@ +from .base import Packet + +class Packet61PlaySoundEffect(Packet, packet_id=61): + FIELDS = [ + ('sound_id', 'int'), + ('x', 'int'), + ('y', 'int'), + ('z', 'int'), + ('data', 'int'), + ] diff --git a/bta_proxy/packets/packet73weatherstatus.py b/bta_proxy/packets/packet73weatherstatus.py index bd14476..b5139f1 100644 --- a/bta_proxy/packets/packet73weatherstatus.py +++ b/bta_proxy/packets/packet73weatherstatus.py @@ -5,7 +5,7 @@ class Packet73WeatherStatus(Packet, packet_id=73): FIELDS = [ ('dim', 'int'), ('id', 'int'), - ('new_id', 'id'), + ('new_id', 'int'), ('duration', 'long'), ('intensity', 'float'), ('power', 'float') diff --git a/bta_proxy/packets/packet7useentity.py b/bta_proxy/packets/packet7useentity.py new file mode 100644 index 0000000..db37b8d --- /dev/null +++ b/bta_proxy/packets/packet7useentity.py @@ -0,0 +1,8 @@ +from .base import Packet + +class Packet7UseEntity(Packet, packet_id=7): + FIELDS = [ + ('player_id', 'int'), + ('entity_id', 'int'), + ('is_left', 'bool'), + ] diff --git a/bta_proxy/packets/packet8updatehealth.py b/bta_proxy/packets/packet8updatehealth.py new file mode 100644 index 0000000..17b9d37 --- /dev/null +++ b/bta_proxy/packets/packet8updatehealth.py @@ -0,0 +1,6 @@ +from .base import Packet + +class Packet8UpdateHealth(Packet, packet_id=8): + FIELDS = [ + ('health', 'short'), + ] diff --git a/tools/mkpacketfile.py b/tools/mkpacketfile.py index 0a1da64..5e679a0 100644 --- a/tools/mkpacketfile.py +++ b/tools/mkpacketfile.py @@ -12,6 +12,11 @@ def main(argv: list[str]): f.write(f'from .base import Packet\n') f.write(f'\n') f.write(f'class {packetname}(Packet, packet_id={packet_id}):\n') + slots = tuple([ + arg.split(':')[0].split('?')[0] + for arg in fields + ]) + f.write(f' __slots__ = {slots!r}\n') f.write(f' FIELDS = [\n') for field in fields: args: list[Any]