MORE PACKETS
This commit is contained in:
parent
79d9da259e
commit
f2155a631d
|
@ -4,17 +4,29 @@ import struct
|
||||||
class AsyncDataInputStream:
|
class AsyncDataInputStream:
|
||||||
def __init__(self, queue: Queue):
|
def __init__(self, queue: Queue):
|
||||||
self._queue = queue
|
self._queue = queue
|
||||||
|
self._buffer = b''
|
||||||
self._last = b''
|
self._last = b''
|
||||||
|
|
||||||
|
def read_rest(self):
|
||||||
|
out = self._buffer
|
||||||
|
self._buffer = b''
|
||||||
|
return out
|
||||||
|
|
||||||
async def read_bytes(self, n: int) -> bytes:
|
async def read_bytes(self, n: int) -> bytes:
|
||||||
if len(self._last) < n:
|
if len(self._buffer) < n:
|
||||||
self._last += await self._queue.get()
|
self._last = (await self._queue.get())
|
||||||
out, self._last = self._last[:n], self._last[n:]
|
self._buffer += self._last
|
||||||
|
out, self._buffer = self._buffer[:n], self._buffer[n:]
|
||||||
return out
|
return out
|
||||||
|
|
||||||
async def read(self) -> int:
|
async def read(self) -> int:
|
||||||
return (await self.read_bytes(1))[0]
|
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:
|
async def read_boolean(self) -> bool:
|
||||||
return (await self.read()) != 0
|
return (await self.read()) != 0
|
||||||
|
|
||||||
|
@ -59,8 +71,12 @@ class AsyncDataInputStream:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
async def read_string(self) -> str:
|
async def read_string(self) -> str:
|
||||||
|
last = self._last
|
||||||
size = await self.read_short()
|
size = await self.read_short()
|
||||||
|
try:
|
||||||
return (await self.read_bytes(size)).decode('utf-8')
|
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:
|
class SyncDataInputStream:
|
||||||
def __init__(self, buffer: bytes):
|
def __init__(self, buffer: bytes):
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
|
||||||
from asyncio.queues import Queue
|
from asyncio.queues import Queue
|
||||||
|
import time
|
||||||
|
|
||||||
from bta_proxy.datainputstream import AsyncDataInputStream
|
from bta_proxy.datainputstream import AsyncDataInputStream
|
||||||
from bta_proxy.packets import *
|
from bta_proxy.packets import *
|
||||||
|
@ -7,8 +8,13 @@ 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()
|
||||||
while True:
|
while True:
|
||||||
pkt = await Packet.read_packet(dis)
|
pkt = await Packet.read_packet(dis)
|
||||||
|
now = time.time()
|
||||||
|
delta = now - last_time
|
||||||
|
last_time = now
|
||||||
|
|
||||||
match pkt.packet_id:
|
match pkt.packet_id:
|
||||||
case Packet10Flying.packet_id:
|
case Packet10Flying.packet_id:
|
||||||
continue
|
continue
|
||||||
|
@ -21,10 +27,27 @@ async def inspect_client(queue: Queue, addr: tuple[str, int]):
|
||||||
case Packet255KickDisconnect.packet_id:
|
case Packet255KickDisconnect.packet_id:
|
||||||
break
|
break
|
||||||
case _:
|
case _:
|
||||||
print("C", pkt)
|
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()
|
||||||
while True:
|
while True:
|
||||||
pkt = await Packet.read_packet(dis)
|
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}")
|
||||||
|
|
|
@ -26,6 +26,7 @@ class EntityData:
|
||||||
async def read_from(cls, dis: AsyncDataInputStream) -> list[DataItem]:
|
async def read_from(cls, dis: AsyncDataInputStream) -> list[DataItem]:
|
||||||
items = []
|
items = []
|
||||||
while (data := await dis.read()) != 0x7F:
|
while (data := await dis.read()) != 0x7F:
|
||||||
|
print(f"========= EntityData.read_from {data=} ({(data & 0xE0) >> 5})")
|
||||||
item_type = DataItemType((data & 0xE0) >> 5)
|
item_type = DataItemType((data & 0xE0) >> 5)
|
||||||
item_id: int = data & 0x1F
|
item_id: int = data & 0x1F
|
||||||
match item_type:
|
match item_type:
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
from bta_proxy.datainputstream import AsyncDataInputStream, SyncDataInputStream
|
from bta_proxy.datainputstream import AsyncDataInputStream, SyncDataInputStream
|
||||||
|
|
||||||
|
|
||||||
class ItemStack:
|
class ItemStack:
|
||||||
__slots__ = ("item_id", "count", "data")
|
__slots__ = ("item_id", "count", "data", "tag")
|
||||||
def __init__(self, item_id: int, count: int, data: int):
|
def __init__(self, item_id: int, count: int, data: int, tag: Any = None):
|
||||||
self.item_id = item_id
|
self.item_id = item_id
|
||||||
self.count = count
|
self.count = count
|
||||||
self.data = data
|
self.data = data
|
||||||
|
self.tag = tag
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def read_from(cls, stream: AsyncDataInputStream) -> 'ItemStack':
|
async def read_from(cls, stream: AsyncDataInputStream) -> 'ItemStack':
|
||||||
|
@ -22,3 +24,8 @@ class ItemStack:
|
||||||
count = stream.read()
|
count = stream.read()
|
||||||
data = stream.read_ushort()
|
data = stream.read_ushort()
|
||||||
return cls(item_id, count, data)
|
return cls(item_id, count, data)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
if self.tag:
|
||||||
|
return f'<ItemStack! {self.item_id}:{self.data} x{self.count}>'
|
||||||
|
return f'<ItemStack {self.item_id}:{self.data} x{self.count}>'
|
||||||
|
|
|
@ -29,3 +29,32 @@ from .packet15place import Packet15Place
|
||||||
from .packet255kickdisconnect import Packet255KickDisconnect
|
from .packet255kickdisconnect import Packet255KickDisconnect
|
||||||
from .packet255kickdisconnect import Packet255KickDisconnect
|
from .packet255kickdisconnect import Packet255KickDisconnect
|
||||||
from .packet102windowclick import Packet102WindowClick
|
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
|
||||||
|
|
|
@ -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.entitydata import EntityData
|
||||||
from bta_proxy.itemstack import ItemStack
|
from bta_proxy.itemstack import ItemStack
|
||||||
from ..datainputstream import AsyncDataInputStream
|
from ..datainputstream import AsyncDataInputStream
|
||||||
|
|
||||||
|
|
||||||
|
def try_int(v: str) -> Union[str, int]:
|
||||||
|
try:
|
||||||
|
return int(v)
|
||||||
|
except ValueError:
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
class Packet:
|
class Packet:
|
||||||
REGISTRY: ClassVar[dict[int, Type['Packet']]] = {}
|
REGISTRY: ClassVar[dict[int, Type["Packet"]]] = {}
|
||||||
FIELDS: ClassVar[list[tuple[str, Any]]] = []
|
FIELDS: ClassVar[list[tuple[str, Any]]] = []
|
||||||
packet_id: int
|
packet_id: int
|
||||||
|
|
||||||
|
@ -14,81 +22,157 @@ class Packet:
|
||||||
setattr(self, k, v)
|
setattr(self, k, v)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def read_data_from(cls, stream: AsyncDataInputStream) -> 'Packet':
|
async def read_data_from(cls, stream: AsyncDataInputStream) -> "Packet":
|
||||||
fields: dict = {}
|
fields: dict = {}
|
||||||
for key, datatype in cls.FIELDS:
|
for key, datatype in cls.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)
|
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)
|
return cls(**fields)
|
||||||
|
|
||||||
@staticmethod
|
@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:
|
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()
|
return await stream.read_uint()
|
||||||
case 'int':
|
case "int":
|
||||||
return await stream.read_int()
|
return await stream.read_int()
|
||||||
case 'str':
|
case "str":
|
||||||
return await stream.read_string()
|
return await stream.read_string()
|
||||||
case 'str', length:
|
case "str", length:
|
||||||
return (await stream.read_string())[:length]
|
return (await stream.read_string())[:length]
|
||||||
case 'string':
|
case "string":
|
||||||
return await stream.read_string()
|
return await stream.read_string()
|
||||||
case 'string', length:
|
case "string", length:
|
||||||
return (await stream.read_string())[:length]
|
return (await stream.read_string())[:length]
|
||||||
case 'ulong':
|
case "ulong":
|
||||||
return await stream.read_ulong()
|
return await stream.read_ulong()
|
||||||
case 'long':
|
case "long":
|
||||||
return await stream.read_long()
|
return await stream.read_long()
|
||||||
case 'ushort':
|
case "ushort":
|
||||||
return await stream.read_ushort()
|
return await stream.read_ushort()
|
||||||
case 'short':
|
case "short":
|
||||||
return await stream.read_short()
|
return await stream.read_short()
|
||||||
case 'byte':
|
case "byte":
|
||||||
return await stream.read()
|
return await stream.read_byte()
|
||||||
case 'float':
|
case "ubyte":
|
||||||
|
return await stream.read_ubyte()
|
||||||
|
case "float":
|
||||||
return await stream.read_float()
|
return await stream.read_float()
|
||||||
case 'double':
|
case "double":
|
||||||
return await stream.read_double()
|
return await stream.read_double()
|
||||||
case 'bool':
|
case "bool":
|
||||||
return await stream.read_boolean()
|
return await stream.read_boolean()
|
||||||
case 'bytes', length_or_key:
|
case "bytes", length_or_key:
|
||||||
if isinstance(length_or_key, int):
|
if isinstance(length_or_key, int):
|
||||||
return await stream.read_bytes(length_or_key)
|
return await stream.read_bytes(length_or_key)
|
||||||
elif isinstance(length_or_key, str):
|
elif isinstance(length_or_key, str):
|
||||||
|
if length_or_key == ".rest":
|
||||||
|
return stream.read_rest()
|
||||||
if length_or_key not in fields:
|
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])
|
return await stream.read_bytes(fields[length_or_key])
|
||||||
raise ValueError(f'invalid type for bytes length_or_key: {length_or_key!r}')
|
raise ValueError(
|
||||||
case 'itemstack':
|
f"invalid type for bytes length_or_key: {length_or_key!r}"
|
||||||
|
)
|
||||||
|
case "itemstack":
|
||||||
return await ItemStack.read_from(stream)
|
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:
|
if (item_id := await stream.read_short()) >= 0:
|
||||||
count = await stream.read()
|
count = await stream.read()
|
||||||
data = await stream.read_short()
|
data = await stream.read_short()
|
||||||
return ItemStack(item_id, count, data)
|
return ItemStack(item_id, count, data)
|
||||||
return None
|
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)
|
return await EntityData.read_from(stream)
|
||||||
case _:
|
case _:
|
||||||
raise ValueError(f'unknown type {datatype}')
|
raise ValueError(f"unknown type {datatype}")
|
||||||
|
|
||||||
def __init_subclass__(cls, packet_id: int, **kwargs) -> None:
|
def __init_subclass__(cls, packet_id: int, **kwargs) -> None:
|
||||||
Packet.REGISTRY[packet_id] = cls
|
Packet.REGISTRY[packet_id] = cls
|
||||||
cls.packet_id = packet_id
|
cls.packet_id = packet_id
|
||||||
super().__init_subclass__(**kwargs)
|
super().__init_subclass__(**kwargs)
|
||||||
|
|
||||||
|
def post_creation(self):
|
||||||
|
pass
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def read_packet(cls, stream: AsyncDataInputStream) -> 'Packet':
|
async def read_packet(cls, stream: AsyncDataInputStream) -> "Packet":
|
||||||
packet_id: int = await stream.read()
|
packet_id: int = await stream.read()
|
||||||
if packet_id not in cls.REGISTRY:
|
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 = await cls.REGISTRY[packet_id].read_data_from(stream)
|
||||||
pkt.packet_id = packet_id
|
pkt.packet_id = packet_id
|
||||||
|
pkt.post_creation()
|
||||||
return pkt
|
return pkt
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
pkt_name = self.REGISTRY[self.packet_id].__name__
|
pkt_name = self.REGISTRY[self.packet_id].__name__
|
||||||
fields = []
|
fields = []
|
||||||
for name, _ in self.FIELDS:
|
for key, _ in self.FIELDS:
|
||||||
fields.append(f'{name}={getattr(self, name)!r}')
|
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)}>'
|
return f'<{pkt_name} {str.join(", ", fields)}>'
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
from .base import Packet
|
||||||
|
|
||||||
|
class Packet0KeepAlive(Packet, packet_id=0):
|
||||||
|
__slots__ = ()
|
||||||
|
FIELDS = [
|
||||||
|
]
|
|
@ -0,0 +1,8 @@
|
||||||
|
from .base import Packet
|
||||||
|
|
||||||
|
class Packet103SetSlot(Packet, packet_id=103):
|
||||||
|
FIELDS = [
|
||||||
|
('window_id', 'byte'),
|
||||||
|
('slot', 'short'),
|
||||||
|
('item', 'extendeditemstack_optional'),
|
||||||
|
]
|
|
@ -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')),
|
||||||
|
]
|
|
@ -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'),
|
||||||
|
]
|
|
@ -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)
|
|
@ -2,9 +2,9 @@ from .base import Packet
|
||||||
|
|
||||||
class Packet14BlockDig(Packet, packet_id=14):
|
class Packet14BlockDig(Packet, packet_id=14):
|
||||||
FIELDS = [
|
FIELDS = [
|
||||||
('status', 'byte'),
|
('status', 'ubyte'),
|
||||||
('x', 'int'),
|
('x', 'int'),
|
||||||
('y', 'byte'),
|
('y', 'ubyte'),
|
||||||
('z', 'int'),
|
('z', 'int'),
|
||||||
('side', 'byte'),
|
('side', 'ubyte'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -3,9 +3,9 @@ from .base import Packet
|
||||||
class Packet15Place(Packet, packet_id=15):
|
class Packet15Place(Packet, packet_id=15):
|
||||||
FIELDS = [
|
FIELDS = [
|
||||||
('x', 'int'),
|
('x', 'int'),
|
||||||
('y', 'byte'),
|
('y', 'ubyte'),
|
||||||
('z', 'int'),
|
('z', 'int'),
|
||||||
('direction', 'byte'),
|
('direction', 'ubyte'),
|
||||||
('y_placed', 'double'),
|
('y_placed', 'double'),
|
||||||
('item', 'itemstack_optional')
|
('item', 'itemstack_optional')
|
||||||
]
|
]
|
||||||
|
|
|
@ -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'),
|
||||||
|
]
|
|
@ -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'),
|
||||||
|
]
|
|
@ -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'),
|
||||||
|
]
|
|
@ -0,0 +1,9 @@
|
||||||
|
from .base import Packet
|
||||||
|
|
||||||
|
class Packet28EntityVelocity(Packet, packet_id=28):
|
||||||
|
FIELDS = [
|
||||||
|
('entity_id', 'int'),
|
||||||
|
('dx', 'short'),
|
||||||
|
('dy', 'short'),
|
||||||
|
('dz', 'short'),
|
||||||
|
]
|
|
@ -0,0 +1,6 @@
|
||||||
|
from .base import Packet
|
||||||
|
|
||||||
|
class Packet29DestroyEntity(Packet, packet_id=29):
|
||||||
|
FIELDS = [
|
||||||
|
('entity_id', 'int'),
|
||||||
|
]
|
|
@ -0,0 +1,6 @@
|
||||||
|
from .base import Packet
|
||||||
|
|
||||||
|
class Packet30Entity(Packet, packet_id=30):
|
||||||
|
FIELDS = [
|
||||||
|
('entity_id', 'int'),
|
||||||
|
]
|
|
@ -0,0 +1,9 @@
|
||||||
|
from .base import Packet
|
||||||
|
|
||||||
|
class Packet31RelEntityMove(Packet, packet_id=31):
|
||||||
|
FIELDS = [
|
||||||
|
('entity_id', 'int'),
|
||||||
|
('x', 'byte'),
|
||||||
|
('y', 'byte'),
|
||||||
|
('z', 'byte'),
|
||||||
|
]
|
|
@ -0,0 +1,8 @@
|
||||||
|
from .base import Packet
|
||||||
|
|
||||||
|
class Packet32EntityLook(Packet, packet_id=32):
|
||||||
|
FIELDS = [
|
||||||
|
('entity_id', 'int'),
|
||||||
|
('yaw', 'byte'),
|
||||||
|
('pitch', 'byte'),
|
||||||
|
]
|
|
@ -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'),
|
||||||
|
]
|
|
@ -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'),
|
||||||
|
]
|
|
@ -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'),
|
||||||
|
]
|
|
@ -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'),
|
||||||
|
]
|
|
@ -0,0 +1,7 @@
|
||||||
|
from .base import Packet
|
||||||
|
|
||||||
|
class Packet40EntityMetadata(Packet, packet_id=40):
|
||||||
|
FIELDS = [
|
||||||
|
('entity_id', 'int'),
|
||||||
|
('data', 'entitydata'),
|
||||||
|
]
|
|
@ -0,0 +1,6 @@
|
||||||
|
from .base import Packet
|
||||||
|
|
||||||
|
class Packet41EntityPlayerGamemode(Packet, packet_id=41):
|
||||||
|
FIELDS = [
|
||||||
|
('gamemode', 'byte'),
|
||||||
|
]
|
|
@ -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
|
|
@ -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')),
|
||||||
|
]
|
|
@ -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'),
|
||||||
|
]
|
|
@ -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'),
|
||||||
|
]
|
|
@ -5,7 +5,7 @@ class Packet73WeatherStatus(Packet, packet_id=73):
|
||||||
FIELDS = [
|
FIELDS = [
|
||||||
('dim', 'int'),
|
('dim', 'int'),
|
||||||
('id', 'int'),
|
('id', 'int'),
|
||||||
('new_id', 'id'),
|
('new_id', 'int'),
|
||||||
('duration', 'long'),
|
('duration', 'long'),
|
||||||
('intensity', 'float'),
|
('intensity', 'float'),
|
||||||
('power', 'float')
|
('power', 'float')
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
from .base import Packet
|
||||||
|
|
||||||
|
class Packet7UseEntity(Packet, packet_id=7):
|
||||||
|
FIELDS = [
|
||||||
|
('player_id', 'int'),
|
||||||
|
('entity_id', 'int'),
|
||||||
|
('is_left', 'bool'),
|
||||||
|
]
|
|
@ -0,0 +1,6 @@
|
||||||
|
from .base import Packet
|
||||||
|
|
||||||
|
class Packet8UpdateHealth(Packet, packet_id=8):
|
||||||
|
FIELDS = [
|
||||||
|
('health', 'short'),
|
||||||
|
]
|
|
@ -12,6 +12,11 @@ def main(argv: list[str]):
|
||||||
f.write(f'from .base import Packet\n')
|
f.write(f'from .base import Packet\n')
|
||||||
f.write(f'\n')
|
f.write(f'\n')
|
||||||
f.write(f'class {packetname}(Packet, packet_id={packet_id}):\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')
|
f.write(f' FIELDS = [\n')
|
||||||
for field in fields:
|
for field in fields:
|
||||||
args: list[Any]
|
args: list[Any]
|
||||||
|
|
Loading…
Reference in New Issue