From 79d9da259e2ecafe92358e9895edcc407b37a160 Mon Sep 17 00:00:00 2001 From: hkc Date: Fri, 25 Aug 2023 23:16:51 +0300 Subject: [PATCH] Added back synchronous DataInputStream and related --- bta_proxy/datainputstream.py | 71 +++++++++++++++++++++++ bta_proxy/entitydata.py | 26 ++++++++- bta_proxy/itemstack.py | 9 ++- bta_proxy/packets/packet102windowclick.py | 2 - 4 files changed, 104 insertions(+), 4 deletions(-) diff --git a/bta_proxy/datainputstream.py b/bta_proxy/datainputstream.py index be357e3..a0ec305 100644 --- a/bta_proxy/datainputstream.py +++ b/bta_proxy/datainputstream.py @@ -62,3 +62,74 @@ class AsyncDataInputStream: size = await self.read_short() return (await self.read_bytes(size)).decode('utf-8') +class SyncDataInputStream: + def __init__(self, buffer: bytes): + self._buffer = buffer + self._cursor = 0 + + def read_bytes(self, n: int) -> bytes: + if self._cursor + n > len(self._buffer): + raise EOFError('stream overread') + blob = self._buffer[self._cursor : self._cursor + n] + self._cursor += n + return blob + + def empty(self): + return self._cursor >= len(self._buffer) - 1 + + def end(self) -> bytes: + return self.read_bytes(len(self._buffer) - self._cursor) + + def read(self) -> int: + if self._cursor >= len(self._buffer): + raise EOFError(f'stream overread in {self._buffer} at {self._cursor}') + self._cursor += 1 + return self._buffer[self._cursor - 1] + + def read_boolean(self) -> bool: + return self.read() != 0 + + def read_short(self) -> int: + return struct.unpack('>h', self.read_bytes(2))[0] + + def read_ushort(self) -> int: + return struct.unpack('>H', self.read_bytes(2))[0] + + def read_int(self) -> int: + return struct.unpack('>i', self.read_bytes(4))[0] + + def read_uint(self) -> int: + return struct.unpack('>I', self.read_bytes(4))[0] + + def read_long(self) -> int: + return struct.unpack('>q', self.read_bytes(8))[0] + + def read_ulong(self) -> int: + return struct.unpack('>Q', self.read_bytes(8))[0] + + def read_float(self) -> float: + return struct.unpack('>f', self.read_bytes(4))[0] + + def read_double(self) -> float: + return struct.unpack('>d', self.read_bytes(8))[0] + + def read_char(self) -> str: + return chr(self.read_ushort()) + + def read_varint(self, bits: int = 32) -> int: + value: int = 0 + position: int = 0 + while True: + byte = self.read() + value |= (byte & 0x7F) << position + if ((byte & 0x80) == 0): + break + position += 7 + if position >= bits: + raise ValueError('varint too big') + return value + + def read_string(self) -> str: + size = self.read_short() + return self.read_bytes(size).decode('utf-8') + diff --git a/bta_proxy/entitydata.py b/bta_proxy/entitydata.py index aa51c96..889b01b 100644 --- a/bta_proxy/entitydata.py +++ b/bta_proxy/entitydata.py @@ -1,6 +1,6 @@ from typing import Any -from bta_proxy.datainputstream import AsyncDataInputStream +from bta_proxy.datainputstream import AsyncDataInputStream, SyncDataInputStream from enum import Enum from dataclasses import dataclass @@ -46,3 +46,27 @@ class EntityData: items.append(DataItem(item_type, item_id, (x, y, z))) return items + @classmethod + def read_from_sync(cls, dis: SyncDataInputStream) -> list[DataItem]: + items = [] + while (data := dis.read()) != 0x7F: + item_type = DataItemType((data & 0xE0) >> 5) + item_id: int = data & 0x1F + match item_type: + case DataItemType.BYTE: + items.append(DataItem(item_type, item_id, dis.read())) + case DataItemType.SHORT: + items.append(DataItem(item_type, item_id, dis.read_short())) + case DataItemType.FLOAT: + items.append(DataItem(item_type, item_id, dis.read_float())) + case DataItemType.STRING: + items.append(DataItem(item_type, item_id, dis.read_string())) + case DataItemType.ITEMSTACK: + items.append(DataItem(item_type, item_id, ItemStack.read_from_sync(dis))) + case DataItemType.CHUNK_COORDINATES: + x = dis.read_float() + y = dis.read_float() + z = dis.read_float() + items.append(DataItem(item_type, item_id, (x, y, z))) + return items + diff --git a/bta_proxy/itemstack.py b/bta_proxy/itemstack.py index 97edb2a..6888d41 100644 --- a/bta_proxy/itemstack.py +++ b/bta_proxy/itemstack.py @@ -1,5 +1,5 @@ -from bta_proxy.datainputstream import AsyncDataInputStream +from bta_proxy.datainputstream import AsyncDataInputStream, SyncDataInputStream class ItemStack: @@ -15,3 +15,10 @@ class ItemStack: count = await stream.read() data = await stream.read_ushort() return cls(item_id, count, data) + + @classmethod + def read_from_sync(cls, stream: SyncDataInputStream) -> 'ItemStack': + item_id = stream.read_short() + count = stream.read() + data = stream.read_ushort() + return cls(item_id, count, data) diff --git a/bta_proxy/packets/packet102windowclick.py b/bta_proxy/packets/packet102windowclick.py index a935faf..082d7f5 100644 --- a/bta_proxy/packets/packet102windowclick.py +++ b/bta_proxy/packets/packet102windowclick.py @@ -1,5 +1,3 @@ -from bta_proxy.datainputstream import AsyncDataInputStream -from bta_proxy.itemstack import ItemStack from .base import Packet class Packet102WindowClick(Packet, packet_id=102):