Generate system messages
This commit is contained in:
parent
14fd5f2b40
commit
b39f067222
|
@ -20,22 +20,23 @@ class GameMessageMemberTypeJson(TypedDict):
|
||||||
kind: str
|
kind: str
|
||||||
disallow_cc: bool
|
disallow_cc: bool
|
||||||
|
|
||||||
class GameMessageMemberJson(TypedDict):
|
class NetMessageMemberJson(TypedDict):
|
||||||
name: list[str]
|
name: list[str]
|
||||||
type: GameMessageMemberTypeJson
|
type: GameMessageMemberTypeJson
|
||||||
|
|
||||||
class GameMessageJson(TypedDict):
|
class NetMessageJson(TypedDict):
|
||||||
id: int
|
id: int
|
||||||
name: list[str]
|
name: list[str]
|
||||||
members: list[GameMessageMemberJson]
|
members: list[NetMessageMemberJson]
|
||||||
attributes: list[Literal['msg_encoding']]
|
attributes: list[Literal['msg_encoding']]
|
||||||
|
|
||||||
class SpecJson(TypedDict):
|
class SpecJson(TypedDict):
|
||||||
constants: list[ConstantJson]
|
constants: list[ConstantJson]
|
||||||
game_enumerations: list[GameEnumJson]
|
game_enumerations: list[GameEnumJson]
|
||||||
game_messages: list[GameMessageJson]
|
game_messages: list[NetMessageJson]
|
||||||
|
system_messages: list[NetMessageJson]
|
||||||
|
|
||||||
def gen_match_game7(game_messages: list[GameMessageJson]):
|
def gen_match_game7(game_messages: list[NetMessageJson]):
|
||||||
match_game7: str = """# generated by scripts/generate_messages.py
|
match_game7: str = """# generated by scripts/generate_messages.py
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ from twnet_parser.net_message import NetMessage
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
msg: GameMessageJson
|
msg: NetMessageJson
|
||||||
for msg in game_messages:
|
for msg in game_messages:
|
||||||
name_snake = name_to_snake(msg['name'])
|
name_snake = name_to_snake(msg['name'])
|
||||||
match_game7 += "import twnet_parser.messages7.game" \
|
match_game7 += "import twnet_parser.messages7.game" \
|
||||||
|
@ -100,13 +101,13 @@ def name_to_snake(name_list: list[str]) -> str:
|
||||||
name = '_'.join(name_list)
|
name = '_'.join(name_list)
|
||||||
return fix_name_conflict(name)
|
return fix_name_conflict(name)
|
||||||
|
|
||||||
def generate_msg(msg: GameMessageJson) -> None:
|
def generate_msg(msg: NetMessageJson, game: str) -> None:
|
||||||
name_snake = name_to_snake(msg['name'])
|
name_snake = name_to_snake(msg['name'])
|
||||||
name_camel = name_to_camel(msg['name'])
|
name_camel = name_to_camel(msg['name'])
|
||||||
dirname = os.path.dirname(__file__)
|
dirname = os.path.dirname(__file__)
|
||||||
file_path= os.path.join(
|
file_path= os.path.join(
|
||||||
dirname,
|
dirname,
|
||||||
'../twnet_parser/messages7/game/',
|
f'../twnet_parser/messages7/{game}/',
|
||||||
f'{name_snake}.py')
|
f'{name_snake}.py')
|
||||||
# if os.path.exists(file_path):
|
# if os.path.exists(file_path):
|
||||||
# print(f"Warning: file already exists! {file_path}")
|
# print(f"Warning: file already exists! {file_path}")
|
||||||
|
@ -131,7 +132,7 @@ def generate_msg(msg: GameMessageJson) -> None:
|
||||||
if member['type']['kind'] == 'string': # TODO: sanitize cc
|
if member['type']['kind'] == 'string': # TODO: sanitize cc
|
||||||
ftype = 'str'
|
ftype = 'str'
|
||||||
default = "'default'"
|
default = "'default'"
|
||||||
elif member['type']['kind'] == 'raw':
|
elif member['type']['kind'] in ('raw', 'sha256', 'rest', 'data'): # TODO: data has a size field
|
||||||
ftype = 'bytes'
|
ftype = 'bytes'
|
||||||
default = "b'\\x00'"
|
default = "b'\\x00'"
|
||||||
# {"name": ["mode"], "type": {"kind": "enum", "enum": ["chat"]}},
|
# {"name": ["mode"], "type": {"kind": "enum", "enum": ["chat"]}},
|
||||||
|
@ -158,15 +159,18 @@ def generate_msg(msg: GameMessageJson) -> None:
|
||||||
elif member['type']['kind'] == 'flags': # TODO: think about flags
|
elif member['type']['kind'] == 'flags': # TODO: think about flags
|
||||||
ftype = 'int'
|
ftype = 'int'
|
||||||
default = '0'
|
default = '0'
|
||||||
|
elif member['type']['kind'] == 'optional': # TODO: think about optionals
|
||||||
|
ftype = 'int'
|
||||||
|
default = '0'
|
||||||
else:
|
else:
|
||||||
print(f"Error: unknown type {member['type']}")
|
raise ValueError(f"Error: unknown type {member['type']}")
|
||||||
exit(1)
|
|
||||||
name = name_to_snake(member["name"])
|
name = name_to_snake(member["name"])
|
||||||
args.append(f' {name}: {ftype} = {default}')
|
args.append(f' {name}: {ftype} = {default}')
|
||||||
out_file.write(',\n'.join(args) + '\n')
|
out_file.write(',\n'.join(args) + '\n')
|
||||||
out_file.write(' ) -> None:\n')
|
out_file.write(' ) -> None:\n')
|
||||||
out_file.write(f" self.message_name = '{name_snake}'\n")
|
out_file.write(f" self.message_name = '{name_snake}'\n")
|
||||||
out_file.write(" self.system_message = False\n")
|
sys: str = 'True' if game == 'system' else 'False'
|
||||||
|
out_file.write(f" self.system_message = {sys}\n")
|
||||||
out_file.write(" self.header: ChunkHeader\n")
|
out_file.write(" self.header: ChunkHeader\n")
|
||||||
out_file.write('\n')
|
out_file.write('\n')
|
||||||
for member in msg['members']:
|
for member in msg['members']:
|
||||||
|
@ -174,7 +178,7 @@ def generate_msg(msg: GameMessageJson) -> None:
|
||||||
ftype = 'int'
|
ftype = 'int'
|
||||||
if member['type']['kind'] == 'string':
|
if member['type']['kind'] == 'string':
|
||||||
ftype = 'str'
|
ftype = 'str'
|
||||||
elif member['type']['kind'] == 'raw':
|
elif member['type']['kind'] in ('raw', 'sha256', 'rest', 'data'): # TODO: data has a size field
|
||||||
ftype = 'bytes'
|
ftype = 'bytes'
|
||||||
# {"name": ["mode"], "type": {"kind": "enum", "enum": ["chat"]}},
|
# {"name": ["mode"], "type": {"kind": "enum", "enum": ["chat"]}},
|
||||||
elif member['type']['kind'] == 'enum':
|
elif member['type']['kind'] == 'enum':
|
||||||
|
@ -192,9 +196,10 @@ def generate_msg(msg: GameMessageJson) -> None:
|
||||||
ftype = 'int'
|
ftype = 'int'
|
||||||
elif member['type']['kind'] == 'flags': # TODO: think about flags
|
elif member['type']['kind'] == 'flags': # TODO: think about flags
|
||||||
ftype = 'int'
|
ftype = 'int'
|
||||||
|
elif member['type']['kind'] == 'optional': # TODO: think about optionals
|
||||||
|
ftype = 'int'
|
||||||
else:
|
else:
|
||||||
print(f"Error: unknown type {member['type']}")
|
raise ValueError(f"Error: unknown type {member['type']}")
|
||||||
exit(1)
|
|
||||||
name = name_to_snake(member["name"])
|
name = name_to_snake(member["name"])
|
||||||
out_file.write(f" self.{name}: {ftype} = {name}\n")
|
out_file.write(f" self.{name}: {ftype} = {name}\n")
|
||||||
out_file.write('\n')
|
out_file.write('\n')
|
||||||
|
@ -208,7 +213,7 @@ def generate_msg(msg: GameMessageJson) -> None:
|
||||||
unpacker = 'int()'
|
unpacker = 'int()'
|
||||||
if member['type']['kind'] == 'string': # TODO: sanitize cc
|
if member['type']['kind'] == 'string': # TODO: sanitize cc
|
||||||
unpacker = 'str()'
|
unpacker = 'str()'
|
||||||
elif member['type']['kind'] == 'raw':
|
elif member['type']['kind'] in ('raw', 'sha256', 'rest', 'data'): # TODO: data has a size field
|
||||||
unpacker = 'raw()'
|
unpacker = 'raw()'
|
||||||
# {"name": ["mode"], "type": {"kind": "enum", "enum": ["chat"]}},
|
# {"name": ["mode"], "type": {"kind": "enum", "enum": ["chat"]}},
|
||||||
elif member['type']['kind'] == 'enum':
|
elif member['type']['kind'] == 'enum':
|
||||||
|
@ -226,9 +231,10 @@ def generate_msg(msg: GameMessageJson) -> None:
|
||||||
unpacker = 'int() # TODO: this is an array'
|
unpacker = 'int() # TODO: this is an array'
|
||||||
elif member['type']['kind'] == 'flags': # TODO: think about flags
|
elif member['type']['kind'] == 'flags': # TODO: think about flags
|
||||||
unpacker = 'int() # TODO: this is a flag'
|
unpacker = 'int() # TODO: this is a flag'
|
||||||
|
elif member['type']['kind'] == 'optional': # TODO: think about optional
|
||||||
|
unpacker = 'int() # TODO: this is a optional of type any'
|
||||||
else:
|
else:
|
||||||
print(f"Error: unknown type {member['type']}")
|
raise ValueError(f"Error: unknown type {member['type']}")
|
||||||
exit(1)
|
|
||||||
name = name_to_snake(member["name"])
|
name = name_to_snake(member["name"])
|
||||||
out_file.write(f' self.{name} = unpacker.get_{unpacker}\n')
|
out_file.write(f' self.{name} = unpacker.get_{unpacker}\n')
|
||||||
out_file.write(' return True\n')
|
out_file.write(' return True\n')
|
||||||
|
@ -236,12 +242,12 @@ def generate_msg(msg: GameMessageJson) -> None:
|
||||||
out_file.write(' def pack(self) -> bytes:\n')
|
out_file.write(' def pack(self) -> bytes:\n')
|
||||||
out_file.write(gen_pack_return(msg))
|
out_file.write(gen_pack_return(msg))
|
||||||
|
|
||||||
def get_dependencies(msg: GameMessageJson) -> str:
|
def get_dependencies(msg: NetMessageJson) -> str:
|
||||||
packer_deps: list[str] = []
|
packer_deps: list[str] = []
|
||||||
for member in msg['members']:
|
for member in msg['members']:
|
||||||
if member['type']['kind'] == 'string': # TODO: sanitize cc
|
if member['type']['kind'] == 'string': # TODO: sanitize cc
|
||||||
packer_deps.append('pack_str')
|
packer_deps.append('pack_str')
|
||||||
elif member['type']['kind'] == 'raw':
|
elif member['type']['kind'] in ('raw', 'sha256', 'rest', 'data'): # TODO: data has a size field
|
||||||
pass
|
pass
|
||||||
# {"name": ["mode"], "type": {"kind": "enum", "enum": ["chat"]}},
|
# {"name": ["mode"], "type": {"kind": "enum", "enum": ["chat"]}},
|
||||||
elif member['type']['kind'] == 'enum':
|
elif member['type']['kind'] == 'enum':
|
||||||
|
@ -259,20 +265,21 @@ def get_dependencies(msg: GameMessageJson) -> str:
|
||||||
packer_deps.append('pack_int')
|
packer_deps.append('pack_int')
|
||||||
elif member['type']['kind'] == 'flags': # TODO: think about flags
|
elif member['type']['kind'] == 'flags': # TODO: think about flags
|
||||||
packer_deps.append('pack_int')
|
packer_deps.append('pack_int')
|
||||||
|
elif member['type']['kind'] == 'optional': # TODO: think about optional
|
||||||
|
packer_deps.append('pack_int')
|
||||||
else:
|
else:
|
||||||
print(f"Error: unknown type {member['type']}")
|
raise ValueError(f"Error: unknown type {member['type']}")
|
||||||
exit(1)
|
|
||||||
if len(packer_deps) == 0:
|
if len(packer_deps) == 0:
|
||||||
return ''
|
return ''
|
||||||
return 'from twnet_parser.packer import ' + \
|
return 'from twnet_parser.packer import ' + \
|
||||||
', '.join(set(packer_deps)) + '\n'
|
', '.join(set(packer_deps)) + '\n'
|
||||||
|
|
||||||
def pack_field(member: GameMessageMemberJson) -> str:
|
def pack_field(member: NetMessageMemberJson) -> str:
|
||||||
name: str = name_to_snake(member["name"])
|
name: str = name_to_snake(member["name"])
|
||||||
packer = 'int'
|
packer = 'int'
|
||||||
if member['type']['kind'] == 'string': # TODO: sanitize cc
|
if member['type']['kind'] == 'string': # TODO: sanitize cc
|
||||||
packer = 'str'
|
packer = 'str'
|
||||||
elif member['type']['kind'] == 'raw':
|
elif member['type']['kind'] in ('raw', 'sha256', 'rest', 'data'): # TODO: data has a size field
|
||||||
return f'self.{name}'
|
return f'self.{name}'
|
||||||
# {"name": ["mode"], "type": {"kind": "enum", "enum": ["chat"]}},
|
# {"name": ["mode"], "type": {"kind": "enum", "enum": ["chat"]}},
|
||||||
elif member['type']['kind'] == 'enum':
|
elif member['type']['kind'] == 'enum':
|
||||||
|
@ -290,13 +297,14 @@ def pack_field(member: GameMessageMemberJson) -> str:
|
||||||
packer = 'int'
|
packer = 'int'
|
||||||
elif member['type']['kind'] == 'flags': # TODO: think about flags
|
elif member['type']['kind'] == 'flags': # TODO: think about flags
|
||||||
packer = 'int'
|
packer = 'int'
|
||||||
|
elif member['type']['kind'] == 'optional': # TODO: think about optional
|
||||||
|
packer = 'int'
|
||||||
else:
|
else:
|
||||||
print(f"Error: unknown type {member['type']}")
|
raise ValueError(f"Error: unknown type {member['type']}")
|
||||||
exit(1)
|
|
||||||
return f'pack_{packer}(self.{name})'
|
return f'pack_{packer}(self.{name})'
|
||||||
|
|
||||||
def gen_pack_return(msg: GameMessageJson) -> str:
|
def gen_pack_return(msg: NetMessageJson) -> str:
|
||||||
members: list[GameMessageMemberJson] = msg['members']
|
members: list[NetMessageMemberJson] = msg['members']
|
||||||
if len(members) == 0:
|
if len(members) == 0:
|
||||||
return " return b''"
|
return " return b''"
|
||||||
if len(members) == 1:
|
if len(members) == 1:
|
||||||
|
@ -311,12 +319,13 @@ def generate(spec: str) -> None:
|
||||||
with open(spec) as spec_io:
|
with open(spec) as spec_io:
|
||||||
spec_data: SpecJson = json.load(spec_io)
|
spec_data: SpecJson = json.load(spec_io)
|
||||||
# for msg in [spec_data['game_messages'][1]]:
|
# for msg in [spec_data['game_messages'][1]]:
|
||||||
game_messages: list[GameMessageJson] = spec_data['game_messages']
|
game_messages: list[NetMessageJson] = spec_data['game_messages']
|
||||||
|
system_messages: list[NetMessageJson] = spec_data['system_messages']
|
||||||
gen_match_game7(game_messages)
|
gen_match_game7(game_messages)
|
||||||
exit(0)
|
|
||||||
for msg in game_messages:
|
for msg in game_messages:
|
||||||
generate_msg(msg)
|
generate_msg(msg, 'game')
|
||||||
|
for msg in system_messages:
|
||||||
|
generate_msg(msg, 'system')
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
dirname = os.path.dirname(__file__)
|
dirname = os.path.dirname(__file__)
|
||||||
|
|
Loading…
Reference in a new issue