MORE PACKETS
This commit is contained in:
parent
79d9da259e
commit
f2155a631d
|
@ -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()
|
||||
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):
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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'<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 .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.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:
|
||||
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)}>'
|
||||
|
|
|
@ -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):
|
||||
FIELDS = [
|
||||
('status', 'byte'),
|
||||
('status', 'ubyte'),
|
||||
('x', 'int'),
|
||||
('y', 'byte'),
|
||||
('y', 'ubyte'),
|
||||
('z', 'int'),
|
||||
('side', 'byte'),
|
||||
('side', 'ubyte'),
|
||||
]
|
||||
|
|
|
@ -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')
|
||||
]
|
||||
|
|
|
@ -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 = [
|
||||
('dim', 'int'),
|
||||
('id', 'int'),
|
||||
('new_id', 'id'),
|
||||
('new_id', 'int'),
|
||||
('duration', 'long'),
|
||||
('intensity', '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'\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]
|
||||
|
|
Loading…
Reference in New Issue