Generate pack() code for messages

This commit is contained in:
ChillerDragon 2023-03-26 13:03:04 +02:00
parent 992a855a57
commit 5f76de93a9
3 changed files with 75 additions and 1 deletions

View file

@ -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} ...")

View file

@ -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

View file

@ -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:
...