WIP packet builder

This commit is contained in:
Casey 2023-09-15 08:43:15 +03:00
parent 191b17fcc1
commit 134ca1eb89
Signed by: hkc
GPG Key ID: F0F6CFE11CDB0960
1 changed files with 173 additions and 0 deletions

View File

@ -0,0 +1,173 @@
from json import load
from dataclasses import dataclass, field
from typing import Literal, Optional, Union
from pprint import pprint
@dataclass(slots=True)
class Condition:
a: Union["Condition", str, int, float]
operator: Literal["gt", "lt", "ge", "le", "eq", "and", "or", "xor"]
b: Union["Condition", str, int, float]
@dataclass(slots=True)
class Field:
type: Literal[
"bool",
"byte",
"ubyte",
"short",
"ushort",
"int",
"uint",
"long",
"ulong",
"float",
"double",
"itemstack",
"optional_itemstack",
"itemstack_nbt",
"optional_itemstack_nbt",
"compoundtag",
"synchedentitydata",
"list", # AAABBBCCC
"column_major_list", # ABCABCABC
"string",
"utfstring",
"bytes",
"bytes_compressed",
"struct",
]
maxsize: Optional[int] = None
size: Optional[int] = None
sizetype: Optional[
Literal["byte", "ubyte", "short", "ushort", "int", "uint"]
] = None
condition: Optional[Condition] = None
method: Optional[Literal["zlib", "gzip"]] = None
fields: Optional[list["NamedField"]] = None
item: Optional[Union["Field", "NamedField"]] = None
@staticmethod
def _add_size(kwargs: dict, data: dict, sizetype: str = "short", maxsize: int = 256) -> dict:
if (size := data.get("size")) is not None:
kwargs['size'] = size
else:
kwargs['sizetype'] = data.get("sizetype", sizetype)
kwargs['maxsize'] = int(data.get("maxsize", maxsize))
return kwargs
@classmethod
def _get_init_args(cls, data: dict) -> tuple[tuple, dict]:
args = (data['type'],)
kwargs = {}
kwargs['condition'] = data.get("condition")
match data["type"]:
case "bool":
pass
case "byte" | "ubyte":
pass
case "short" | "ushort":
pass
case "int" | "uint":
pass
case "long" | "ulong":
pass
case "float":
pass
case "double":
pass
case "string" | "utfstring" | "bytes":
kwargs = cls._add_size(kwargs, data)
case "bytes_compressed":
kwargs['method'] = data.get("method")
assert kwargs['method'] in ("gzip", "zlib")
kwargs = cls._add_size(kwargs, data, maxsize=16777216)
case "list":
kwargs = cls._add_size(kwargs, data, maxsize=1024)
kwargs['item'] = data.get("item")
raise NotImplementedError(f"can't do list yet")
case "column_major_list":
kwargs = cls._add_size(kwargs, data)
kwargs['fields'] = list(map(NamedField.fromdict, data["fields"]))
case "optional_itemstack":
print("TODO: optional_itemstack")
case "optional_itemstack_nbt":
print("TODO: optional_itemstack_nbt")
case "itemstack":
print("TODO: itemstack")
case "itemstack_nbt":
print("TODO: itemstack_nbt")
case "synchedentitydata":
print("TODO: synchedentitydata")
case "compoundtag":
print("TODO: compoundtag")
case name:
raise NotImplementedError(f"unknown field type {name}")
return args, kwargs
@classmethod
def fromdict(cls, data: dict) -> "Field":
args, kwargs = cls._get_init_args(data)
return cls(*args, **kwargs)
@dataclass(slots=True)
class NamedField(Field):
name: str = ""
@classmethod
def _get_init_args(cls, data: dict) -> tuple[tuple, dict]:
args, kwargs = Field._get_init_args(data)
kwargs['name'] = data['name']
return args, kwargs
@classmethod
def fromdict(cls, data: dict) -> "NamedField":
args, kwargs = cls._get_init_args(data)
return cls(*args, **kwargs)
@dataclass(slots=True)
class PacketSchema:
id: int
name: str
server: bool = False
client: bool = False
fields: list[NamedField] = field(default_factory=list)
@classmethod
def fromdict(cls, data: dict) -> "PacketSchema":
assert data.get("server", False) or data.get("client", False)
return cls(
data["id"],
data["name"],
data.get("server", False),
data.get("client", True),
list(map(NamedField.fromdict, data["fields"])),
)
@dataclass(slots=True)
class ProtocolSchema:
protocol_version: int
game_version: str
packets: list[PacketSchema]
@classmethod
def fromdict(cls, data: dict) -> "ProtocolSchema":
return cls(
protocol_version=data["protocol_version"],
game_version=data["game_version"],
packets=list(map(PacketSchema.fromdict, data["packets"])),
)
with open("../packets.json", "r") as f:
data = load(f)
schema = ProtocolSchema.fromdict(data)