diff --git a/aiocraft/minecraft/compiler.py b/aiocraft/minecraft/compiler.py new file mode 100755 index 0000000..247ad2e --- /dev/null +++ b/aiocraft/minecraft/compiler.py @@ -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()) + + +