added very basic protocol compiler

This commit is contained in:
əlemi 2021-10-09 20:55:31 +02:00 committed by alemidev
parent 16c75882f1
commit c08f3b5153

78
aiocraft/minecraft/compiler.py Executable file
View file

@ -0,0 +1,78 @@
#!/usr/bin/env python
import os
import json
from typing import List, Dict
DIR_MAP = {"toClient": "clientbound", "toServer": "serverbound"}
PREFACE = """\"\"\"[!] This file is autogenerated\"\"\"\n\n"""
IMPORTS = """from .minecraft.packet import Packet\nfrom .minecraft.types import *\n"""
IMPORT_ALL = """from .* import * # TODO!\n"""
OBJECT = """
class {name}(Packet):
ID : int = 0x{id:X}
SLOTS : list = (
{slots}
)
"""
def snake_to_camel(name:str) -> str:
return "".join(x.capitalize() for x in name.split("_"))
def parse_slot(slot: dict) -> str:
if "name" in slot:
if "type" in slot and isinstance(slot["type"], str):
return f"(\"{slot['name']}\", {slot['type']})"
else:
return f"(\"{slot['name']}\", [Special])"
elif "anon" in slot:
if "type" in slot and isinstance(slot["type"], str):
return f"(\"anon\", {slot['type']})"
else:
return f"(\"anon\", [Special])"
class PacketClassWriter:
pid : int
title : str
slots : List[Dict[str, str]]
def __init__(self, pid:int, title:str, slots:List[Dict[str, str]]):
self.pid = pid
self.title = title
self.slots = slots
def compile(self) -> str:
return PREFACE + IMPORTS + OBJECT.format(id=pid, name=self.title, slots=parse_slot(self.slots))
def _make_module(path:str):
os.mkdir(path)
if not path.endswith("/"):
path += "/"
with open(path + "__init__.py", "w") as f:
f.write(PREFACE + IMPORT_ALL)
if __name__ == "__main__":
# TODO load relatively!
# with open("???/minecraft-data/data/pc/1.12.2/protocol.json") as f:
# data = json.load(f)
_make_module("protocol")
for state in ("handshaking", "status", "login", "play"):
_make_module(f"protocol/{state}")
for _direction in ("toClient", "toServer"):
direction = DIR_MAP[_direction]
_make_module(f"protocol/{state}/{direction}")
buf = data[state][_direction]["types"]["packet"][1][0]["type"][1]["mappings"]
registry = { f"packet_{value}" : int(key, 16) for (key, value) in buf.items() }
for p_name in data[state][_direction]["types"].keys():
if p_name == "packet":
continue # it's the registry entry
packet = data[state][_direction]["types"][p_name]
pid = registry[p_name]
class_name = snake_to_camel(p_name)
with open(f"protocol/{state}/{direction}/{p_name}.py", "w") as f:
f.write(PacketClassWriter(pid, class_name, packet[1]).compile())