diff --git a/scripts/generate_messages.py b/scripts/generate_messages.py index ff94dd0..479ab67 100644 --- a/scripts/generate_messages.py +++ b/scripts/generate_messages.py @@ -66,6 +66,7 @@ def generate_msg(msg: GameMessageJson) -> None: out_file.write('\n') out_file.write('from twnet_parser.pretty_print import PrettyPrint\n') out_file.write('from twnet_parser.packer import Unpacker\n') + out_file.write(get_dependencies(msg)) out_file.write('\n') out_file.write(f'class {name_camel}(PrettyPrint):\n') out_file.write(' def __init__(\n') @@ -113,6 +114,8 @@ def generate_msg(msg: GameMessageJson) -> None: out_file.write(',\n'.join(args) + '\n') out_file.write(' ) -> None:\n') out_file.write(f" self.message_name = '{name_snake}'\n") + out_file.write(" self.system_message = False\n") + out_file.write('\n') for member in msg['members']: # {'name': ['message'], 'type': {'kind': 'string', 'disallow_cc': False}} ftype = 'int' @@ -178,8 +181,77 @@ def generate_msg(msg: GameMessageJson) -> None: out_file.write(' return True\n') out_file.write('\n') out_file.write(' def pack(self) -> bytes:\n') - out_file.write(" return b'todo'\n") + out_file.write(gen_pack_return(msg)) +def get_dependencies(msg: GameMessageJson) -> str: + packer_deps: list[str] = [] + for member in msg['members']: + if member['type']['kind'] == 'string': # TODO: sanitize cc + packer_deps.append('pack_str') + elif member['type']['kind'] == 'raw': + pass + # {"name": ["mode"], "type": {"kind": "enum", "enum": ["chat"]}}, + elif member['type']['kind'] == 'enum': + packer_deps.append('pack_int') + elif member['type']['kind'] in ('int32', 'tick'): + packer_deps.append('pack_int') + elif member['type']['kind'] == 'boolean': + packer_deps.append('pack_int') + elif member['type']['kind'] == 'tune_param': # TODO: think about tune params + packer_deps.append('pack_int') + elif member['type']['kind'] == 'snapshot_object': + # TODO: think about snapshot_object + packer_deps.append('pack_int') + elif member['type']['kind'] == 'array': # TODO: think about array + packer_deps.append('pack_int') + elif member['type']['kind'] == 'flags': # TODO: think about flags + packer_deps.append('pack_int') + else: + print(f"Error: unknown type {member['type']}") + exit(1) + if len(packer_deps) == 0: + return '' + return 'from twnet_parser.packer import ' + \ + ', '.join(set(packer_deps)) + '\n' + +def pack_field(member: GameMessageMemberJson) -> str: + name: str = name_to_snake(member["name"]) + packer = 'int' + if member['type']['kind'] == 'string': # TODO: sanitize cc + packer = 'str' + elif member['type']['kind'] == 'raw': + return f'self.{name}' + # {"name": ["mode"], "type": {"kind": "enum", "enum": ["chat"]}}, + elif member['type']['kind'] == 'enum': + packer = 'int' + elif member['type']['kind'] in ('int32', 'tick'): + packer = 'int' + elif member['type']['kind'] == 'boolean': + packer = 'int' + elif member['type']['kind'] == 'tune_param': # TODO: think about tune params + packer = 'int' + elif member['type']['kind'] == 'snapshot_object': + # TODO: think about snapshot_object + packer = 'int' + elif member['type']['kind'] == 'array': # TODO: think about array + packer = 'int' + elif member['type']['kind'] == 'flags': # TODO: think about flags + packer = 'int' + else: + print(f"Error: unknown type {member['type']}") + exit(1) + return f'pack_{packer}(self.{name})' + +def gen_pack_return(msg: GameMessageJson) -> str: + members: list[GameMessageMemberJson] = msg['members'] + if len(members) == 0: + return " return b''" + if len(members) == 1: + return f' return {pack_field(members[0])}' + mem_strs: list[str] = [ + f' {pack_field(member)}' for member in members[1:]] + return f" return {pack_field(members[0])} + \\\n" + \ + ' + \\\n'.join(mem_strs) def generate(spec: str) -> None: print(f"generating classes from {spec} ...") diff --git a/twnet_parser/message_parser.py b/twnet_parser/message_parser.py index 01adb07..3b3095a 100644 --- a/twnet_parser/message_parser.py +++ b/twnet_parser/message_parser.py @@ -10,6 +10,7 @@ from twnet_parser.chunk_header import ChunkHeader class TodoMessage(): def __init__(self, name: str) -> None: self.message_name = name + self.system_message = False self.header: ChunkHeader def unpack(self, data: bytes) -> bool: return len(data) > 0 diff --git a/twnet_parser/net_message.py b/twnet_parser/net_message.py index 26c20d3..d212c07 100644 --- a/twnet_parser/net_message.py +++ b/twnet_parser/net_message.py @@ -4,6 +4,7 @@ from twnet_parser.chunk_header import ChunkHeader class NetMessage(Protocol): message_name: str + system_message: bool header: ChunkHeader def unpack(self, data: bytes) -> bool: ...