More packets

This commit is contained in:
Casey 2023-08-26 12:33:31 +03:00
parent f2155a631d
commit 69a00c1a2b
Signed by: hkc
GPG Key ID: F0F6CFE11CDB0960
13 changed files with 138 additions and 45 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@ __pycache__/
venv/ venv/
state state
packets.txt packets.txt
packets*.txt

View File

@ -9,9 +9,15 @@ MAX_SIZE = 0x400000
async def main(args): async def main(args: list[str]):
loop = asyncio.get_running_loop() loop = asyncio.get_running_loop()
server = await asyncio.start_server(BTAProxy(args[0], 25565, loop).handle_client, "localhost", 25565) port: int = 25565
if len(args) >= 2:
port = int(args[1])
server = await asyncio.start_server(BTAProxy(args[0], port, loop).handle_client, "localhost", 25565)
print("listening on", str.join(", ", [str(s.getsockname()) for s in server.sockets]))
print("forwarding to", args[0], port)
async with server: async with server:
await server.serve_forever() await server.serve_forever()

View File

@ -15,6 +15,8 @@ class AsyncDataInputStream:
async def read_bytes(self, n: int) -> bytes: async def read_bytes(self, n: int) -> bytes:
if len(self._buffer) < n: if len(self._buffer) < n:
self._last = (await self._queue.get()) self._last = (await self._queue.get())
if not self._last:
raise EOFError('empty packet was received')
self._buffer += self._last self._buffer += self._last
out, self._buffer = self._buffer[:n], self._buffer[n:] out, self._buffer = self._buffer[:n], self._buffer[n:]
return out return out
@ -76,7 +78,7 @@ class AsyncDataInputStream:
try: try:
return (await self.read_bytes(size)).decode('utf-8') return (await self.read_bytes(size)).decode('utf-8')
except Exception as e: except Exception as e:
raise ValueError(f'failed reading string of size {size} in {last}') from e raise ValueError(f'failed reading string of size {size} in {last!r}') from e
class SyncDataInputStream: class SyncDataInputStream:
def __init__(self, buffer: bytes): def __init__(self, buffer: bytes):
@ -98,7 +100,7 @@ class SyncDataInputStream:
def read(self) -> int: def read(self) -> int:
if self._cursor >= len(self._buffer): if self._cursor >= len(self._buffer):
raise EOFError(f'stream overread in {self._buffer} at {self._cursor}') raise EOFError(f'stream overread in {self._buffer!r} at {self._cursor}')
self._cursor += 1 self._cursor += 1
return self._buffer[self._cursor - 1] return self._buffer[self._cursor - 1]

View File

@ -5,49 +5,62 @@ import time
from bta_proxy.datainputstream import AsyncDataInputStream from bta_proxy.datainputstream import AsyncDataInputStream
from bta_proxy.packets import * from bta_proxy.packets import *
async def inspect_client(queue: Queue, addr: tuple[str, int]): async def inspect_client(queue: Queue, addr: tuple[str, int]):
dis = AsyncDataInputStream(queue) dis = AsyncDataInputStream(queue)
last_time = time.time() 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: with open("packets-%s-%d-client.txt" % addr, "w") as f:
case Packet10Flying.packet_id: while True:
continue try:
case Packet11PlayerPosition.packet_id: pkt = await Packet.read_packet(dis)
continue except EOFError:
case Packet12PlayerLook.packet_id:
continue
case Packet13LookMove.packet_id:
continue
case Packet255KickDisconnect.packet_id:
break break
case _: now = time.time()
print(f"C {delta*1000:+8.1f}ms {pkt}") delta = now - last_time
last_time = now
print(f"{delta*1000:+8.1f}ms {pkt}", file=f)
match pkt.packet_id:
case Packet10Flying.packet_id:
continue
case Packet11PlayerPosition.packet_id:
continue
case Packet12PlayerLook.packet_id:
continue
case Packet13LookMove.packet_id:
continue
case Packet255KickDisconnect.packet_id:
break
case _:
print(f"C {delta*1000:+8.1f}ms {pkt}")
async def inspect_server(queue: Queue, addr: tuple[str, int]): async def inspect_server(queue: Queue, addr: tuple[str, int]):
dis = AsyncDataInputStream(queue) dis = AsyncDataInputStream(queue)
last_time = time.time() 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: with open("packets-%s-%d-server.txt" % addr, "w") as f:
case Packet50PreChunk.packet_id: while True:
continue try:
case Packet51MapChunk.packet_id: pkt = await Packet.read_packet(dis)
continue except EOFError:
case Packet31RelEntityMove.packet_id: break
continue now = time.time()
case Packet32EntityLook.packet_id: delta = now - last_time
continue last_time = now
case Packet33RelEntityMoveLook.packet_id:
continue print(f"{delta*1000:+8.1f}ms {pkt}", file=f)
case _:
print(f"S {delta*1000:+8.1f}ms {pkt}") 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}")

View File

@ -56,5 +56,12 @@ from .packet132setmobspawner import Packet132SetMobSpawner
from .packet39attachentity import Packet39AttachEntity from .packet39attachentity import Packet39AttachEntity
from .packet35entitynickname import Packet35EntityNickname from .packet35entitynickname import Packet35EntityNickname
from .packet52multiblockchange import Packet52MultiBlockChange from .packet52multiblockchange import Packet52MultiBlockChange
from .packet20statistic import Packet20Statistic from .packet200statistic import Packet200Statistic
from .packet0keepalive import Packet0KeepAlive from .packet0keepalive import Packet0KeepAlive
from .packet106transaction import Packet106Transaction
from .packet20namedentityspawn import Packet20NamedEntitySpawn
from .packet107updatecreativeinventory import Packet107UpdateCreativeInventory
from .packet22collect import Packet22Collect
from .packet9respawn import Packet9Respawn
from .packet60explosion import Packet60Explosion
from .packet60explosion import Packet60Explosion

View File

@ -47,9 +47,11 @@ class Packet:
): ):
match datatype: match datatype:
case "list", sizekey, *args: case "list", sizekey, *args:
args = args[0] if len(args) == 1 else tuple(args)
length = sizekey if isinstance(try_int(sizekey), int) else fields[sizekey]
return [ return [
await Packet.read_field(stream, args, fields) await Packet.read_field(stream, args, fields)
for _ in range(fields[sizekey]) for _ in range(length)
] ]
case "uint": case "uint":
return await stream.read_uint() return await stream.read_uint()
@ -98,8 +100,8 @@ class Packet:
case "itemstack": case "itemstack":
return await ItemStack.read_from(stream) return await ItemStack.read_from(stream)
case "itemstack", length_or_key: case "itemstack", length_or_key:
items: list[Optional[ItemStack]] = []
if isinstance(length_or_key, int): if isinstance(length_or_key, int):
items: list[Optional[ItemStack]] = []
for _ in range(length_or_key): for _ in range(length_or_key):
if (item_id := await stream.read_short()) >= 0: if (item_id := await stream.read_short()) >= 0:
count = await stream.read() count = await stream.read()
@ -115,7 +117,6 @@ class Packet:
raise KeyError( raise KeyError(
f"failed to find {length_or_key} in {fields} to read number of itemstacks" 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]): for _ in range(fields[length_or_key]):
if (item_id := await stream.read_short()) >= 0: if (item_id := await stream.read_short()) >= 0:
count = await stream.read() count = await stream.read()

View File

@ -0,0 +1,9 @@
from .base import Packet
class Packet106Transaction(Packet, packet_id=106):
__slots__ = ('window_id', 'action_id', 'flag')
FIELDS = [
('window_id', 'ubyte'),
('action_id', 'short'),
('flag', 'bool'),
]

View File

@ -0,0 +1,9 @@
from .base import Packet
class Packet107UpdateCreativeInventory(Packet, packet_id=107):
__slots__ = ('window_id', 'page', 'text')
FIELDS = [
('window_id', 'ubyte'),
('page', 'int'),
('text', 'str'),
]

View File

@ -1,6 +1,6 @@
from .base import Packet from .base import Packet
class Packet20Statistic(Packet, packet_id=20): class Packet200Statistic(Packet, packet_id=200):
__slots__ = ('field_27052_a', 'field_27051') __slots__ = ('field_27052_a', 'field_27051')
FIELDS = [ FIELDS = [
('field_27052_a', 'int'), ('field_27052_a', 'int'),

View File

@ -0,0 +1,16 @@
from .base import Packet
class Packet20NamedEntitySpawn(Packet, packet_id=20):
__slots__ = ('entity_id', 'name', 'x', 'y', 'z', 'yaw', 'pitch', 'item', 'name', 'color')
FIELDS = [
('entity_id', 'int'),
('name', 'str'),
('x', 'int'),
('y', 'int'),
('z', 'int'),
('yaw', 'byte'),
('pitch', 'byte'),
('item', 'short'),
('name', 'str'),
('color', 'ubyte'),
]

View File

@ -0,0 +1,8 @@
from .base import Packet
class Packet22Collect(Packet, packet_id=22):
__slots__ = ('collected', 'collector')
FIELDS = [
('collected', 'int'),
('collector', 'int'),
]

View File

@ -0,0 +1,13 @@
from .base import Packet
class Packet60Explosion(Packet, packet_id=60):
__slots__ = ('x', 'y', 'z', 'size', 'destroyed_len', 'rel_destroyed', 'is_cannonball')
FIELDS = [
('x', 'double'),
('y', 'double'),
('z', 'double'),
('size', 'float'),
('destroyed_len', 'int'),
('rel_destroyed', ('list', 'destroyed_len', 'list', 3, 'byte')),
('is_cannonball', 'bool'),
]

View File

@ -0,0 +1,8 @@
from .base import Packet
class Packet9Respawn(Packet, packet_id=9):
__slots__ = ('dimension', 'world_type')
FIELDS = [
('dimension', 'byte'),
('world_type', 'byte'),
]