import sys from datatypes import EmitDefinition, EmitTypeDeclaration import content import network def create_enum_table(names, num): lines = [] lines += ["enum", "{"] for name in names: lines += ["\t%s,"%name] lines += ["\t%s" % num, "};"] return lines def create_flags_table(names): lines = [] lines += ["enum", "{"] i = 0 for name in names: lines += ["\t%s = 1<<%d," % (name,i)] i += 1 lines += ["};"] return lines def EmitEnum(names, num): print("enum") print("{") print("\t%s=0," % names[0]) for name in names[1:]: print("\t%s," % name) print("\t%s" % num) print("};") def EmitFlags(names): print("enum") print("{") i = 0 for name in names: print("\t%s = 1<<%d," % (name,i)) i += 1 print("};") def main(): gen_network_header = "network_header" in sys.argv gen_network_source = "network_source" in sys.argv gen_client_content_header = "client_content_header" in sys.argv gen_client_content_source = "client_content_source" in sys.argv gen_server_content_header = "server_content_header" in sys.argv gen_server_content_source = "server_content_source" in sys.argv if gen_client_content_header: print("#ifndef CLIENT_CONTENT_HEADER") print("#define CLIENT_CONTENT_HEADER") if gen_server_content_header: print("#ifndef SERVER_CONTENT_HEADER") print("#define SERVER_CONTENT_HEADER") if gen_client_content_header or gen_server_content_header: # print some includes print('#include ') # emit the type declarations contentlines = open("datasrc/content.py", "rb").readlines() order = [] for line in contentlines: line = line.strip() if line[:6] == "class ".encode() and "(Struct)".encode() in line: order += [line.split()[1].split("(".encode())[0].decode("ascii")] for name in order: EmitTypeDeclaration(content.__dict__[name]) # the container pointer print('extern CDataContainer *g_pData;') # enums EmitEnum(["IMAGE_%s"%i.name.value.upper() for i in content.container.images.items], "NUM_IMAGES") EmitEnum(["ANIM_%s"%i.name.value.upper() for i in content.container.animations.items], "NUM_ANIMS") EmitEnum(["SPRITE_%s"%i.name.value.upper() for i in content.container.sprites.items], "NUM_SPRITES") if gen_client_content_source or gen_server_content_source: if gen_client_content_source: print('#include "client_data.h"') if gen_server_content_source: print('#include "server_data.h"') EmitDefinition(content.container, "datacontainer") print('CDataContainer *g_pData = &datacontainer;') # NETWORK if gen_network_header: print("#ifndef GAME_GENERATED_PROTOCOL_H") print("#define GAME_GENERATED_PROTOCOL_H") print("class CUnpacker;") print("#include ") print(network.RawHeader) for e in network.Enums: for l in create_enum_table(["%s_%s"%(e.name, v) for v in e.values], 'NUM_%sS'%e.name): # pylint: disable=E1101 print(l) print("") for e in network.Flags: for l in create_flags_table(["%s_%s" % (e.name, v) for v in e.values]): print(l) print("") non_extended = [o for o in network.Objects if o.ex is None] extended = [o for o in network.Objects if o.ex is not None] for l in create_enum_table(["NETOBJTYPE_EX"]+[o.enum_name for o in non_extended], "NUM_NETOBJTYPES"): print(l) for l in create_enum_table(["__NETOBJTYPE_UUID_HELPER=OFFSET_GAME_UUID-1"]+[o.enum_name for o in extended], "OFFSET_NETMSGTYPE_UUID"): print(l) print("") non_extended = [o for o in network.Messages if o.ex is None] extended = [o for o in network.Messages if o.ex is not None] for l in create_enum_table(["NETMSGTYPE_EX"]+[o.enum_name for o in non_extended], "NUM_NETMSGTYPES"): print(l) print("") for l in create_enum_table(["__NETMSGTYPE_UUID_HELPER=OFFSET_NETMSGTYPE_UUID-1"]+[o.enum_name for o in extended], "OFFSET_MAPITEMTYPE_UUID"): print(l) print("") for item in network.Objects + network.Messages: for line in item.emit_declaration(): print(line) print("") EmitEnum(["SOUND_%s"%i.name.value.upper() for i in content.container.sounds.items], "NUM_SOUNDS") EmitEnum(["WEAPON_%s"%i.name.value.upper() for i in content.container.weapons.id.items], "NUM_WEAPONS") print(""" class CNetObjHandler { const char *m_pMsgFailedOn; const char *m_pObjFailedOn; const char *m_pObjCorrectedOn; char m_aUnpackedData[1024 * 2]; int m_NumObjCorrections; int ClampInt(const char *pErrorMsg, int Value, int Min, int Max); static const char *ms_apObjNames[]; static const char *ms_apExObjNames[]; static int ms_aObjSizes[]; static int ms_aUnpackedObjSizes[]; static int ms_aUnpackedExObjSizes[]; static const char *ms_apMsgNames[]; static const char *ms_apExMsgNames[]; public: CNetObjHandler(); void *SecureUnpackObj(int Type, CUnpacker *pUnpacker); const char *GetObjName(int Type) const; int GetObjSize(int Type) const; int GetUnpackedObjSize(int Type) const; int NumObjCorrections() const; const char *CorrectedObjOn() const; const char *FailedObjOn() const; const char *GetMsgName(int Type) const; void *SecureUnpackMsg(int Type, CUnpacker *pUnpacker); bool TeeHistorianRecordMsg(int Type); const char *FailedMsgOn() const; }; """) print("#endif // GAME_GENERATED_PROTOCOL_H") if gen_network_source: # create names lines = [] lines += ['#include "protocol.h"'] lines += ['#include '] lines += ['#include '] lines += ['#include '] lines += ['#include '] lines += ['CNetObjHandler::CNetObjHandler()'] lines += ['{'] lines += ['\tm_pMsgFailedOn = "";'] lines += ['\tm_pObjFailedOn = "";'] lines += ['\tm_pObjCorrectedOn = "";'] lines += ['\tm_NumObjCorrections = 0;'] lines += ['}'] lines += [''] lines += ['int CNetObjHandler::NumObjCorrections() const { return m_NumObjCorrections; }'] lines += ['const char *CNetObjHandler::CorrectedObjOn() const { return m_pObjCorrectedOn; }'] lines += ['const char *CNetObjHandler::FailedObjOn() const { return m_pObjFailedOn; }'] lines += ['const char *CNetObjHandler::FailedMsgOn() const { return m_pMsgFailedOn; }'] lines += [''] lines += [''] lines += [''] lines += [''] lines += [''] lines += ['static const int max_int = 0x7fffffff;'] lines += ['static const int min_int = 0x80000000;'] lines += ['int CNetObjHandler::ClampInt(const char *pErrorMsg, int Value, int Min, int Max)'] lines += ['{'] lines += ['\tif(Value < Min) { m_pObjCorrectedOn = pErrorMsg; m_NumObjCorrections++; return Min; }'] lines += ['\tif(Value > Max) { m_pObjCorrectedOn = pErrorMsg; m_NumObjCorrections++; return Max; }'] lines += ['\treturn Value;'] lines += ['}'] lines += ["const char *CNetObjHandler::ms_apObjNames[] = {"] lines += ['\t"EX/UUID",'] lines += ['\t"%s",' % o.name for o in network.Objects if o.ex is None] lines += ['\t""', "};", ""] lines += ["const char *CNetObjHandler::ms_apExObjNames[] = {"] lines += ['\t"invalid",'] lines += ['\t"%s",' % o.name for o in network.Objects if o.ex is not None] lines += ['\t""', "};", ""] lines += ["int CNetObjHandler::ms_aObjSizes[] = {"] lines += ['\t0,'] lines += ['\tsizeof(%s),' % o.struct_name for o in network.Objects if o.ex is None] lines += ['\t0', "};", ""] lines += ["int CNetObjHandler::ms_aUnpackedObjSizes[] = {"] lines += ['\t16,'] lines += ['\tsizeof(%s),' % o.struct_name for o in network.Objects if o.ex is None] lines += ["};", ""] lines += ["int CNetObjHandler::ms_aUnpackedExObjSizes[] = {"] lines += ['\t0,'] lines += ['\tsizeof(%s),' % o.struct_name for o in network.Objects if o.ex is not None] lines += ["};", ""] lines += ['const char *CNetObjHandler::ms_apMsgNames[] = {'] lines += ['\t"invalid",'] lines += ['\t"%s",' % msg.name for msg in network.Messages if msg.ex is None] lines += ['\t""', "};", ""] lines += ['const char *CNetObjHandler::ms_apExMsgNames[] = {'] lines += ['\t"invalid",'] lines += ['\t"%s",' % msg.name for msg in network.Messages if msg.ex is not None] lines += ['\t""', "};", ""] lines += ['const char *CNetObjHandler::GetObjName(int Type) const'] lines += ['{'] lines += ['\tif(Type >= 0 && Type < NUM_NETOBJTYPES)'] lines += ['\t{'] lines += ['\t\treturn ms_apObjNames[Type];'] lines += ['\t}'] lines += ['\telse if(Type > __NETOBJTYPE_UUID_HELPER && Type < OFFSET_NETMSGTYPE_UUID)'] lines += ['\t{'] lines += ['\t\treturn ms_apExObjNames[Type - __NETOBJTYPE_UUID_HELPER];'] lines += ['\t}'] lines += ['\treturn "(out of range)";'] lines += ['}'] lines += [''] lines += ['int CNetObjHandler::GetObjSize(int Type) const'] lines += ['{'] lines += ['\tif(Type < 0 || Type >= NUM_NETOBJTYPES) return 0;'] lines += ['\treturn ms_aObjSizes[Type];'] lines += ['}'] lines += [''] lines += ['int CNetObjHandler::GetUnpackedObjSize(int Type) const'] lines += ['{'] lines += ['\tif(Type >= 0 && Type < NUM_NETOBJTYPES)'] lines += ['\t{'] lines += ['\t\treturn ms_aUnpackedObjSizes[Type];'] lines += ['\t}'] lines += ['\telse if(Type > __NETOBJTYPE_UUID_HELPER && Type < OFFSET_NETMSGTYPE_UUID)'] lines += ['\t{'] lines += ['\t\treturn ms_aUnpackedExObjSizes[Type - __NETOBJTYPE_UUID_HELPER];'] lines += ['\t}'] lines += ['\treturn 0;'] lines += ['}'] lines += [''] lines += ['const char *CNetObjHandler::GetMsgName(int Type) const'] lines += ['{'] lines += ['\tif(Type >= 0 && Type < NUM_NETMSGTYPES)'] lines += ['\t{'] lines += ['\t\treturn ms_apMsgNames[Type];'] lines += ['\t}'] lines += ['\telse if(Type > __NETMSGTYPE_UUID_HELPER && Type < OFFSET_MAPITEMTYPE_UUID)'] lines += ['\t{'] lines += ['\t\treturn ms_apExMsgNames[Type - __NETMSGTYPE_UUID_HELPER];'] lines += ['\t}'] lines += ['\treturn "(out of range)";'] lines += ['}'] lines += [''] for l in lines: print(l) # create validate tables lines = [] lines += ['static int validate_invalid(void *data, int size) { return -1; }'] lines += ["typedef int(*VALIDATEFUNC)(void *data, int size);"] lines += ["static VALIDATEFUNC validate_funcs[] = {"] lines += ['\tvalidate_invalid,'] lines += ['\tvalidate_%s,' % o.name for o in network.Objects] lines += ["\t0x0", "};", ""] lines += ["int netobj_validate(int type, void *data, int size)"] lines += ["{"] lines += ["\tif(type < 0 || type >= NUM_NETOBJTYPES) return -1;"] lines += ["\treturn validate_funcs[type](data, size);"] lines += ["};", ""] lines = [] lines += ['void *CNetObjHandler::SecureUnpackObj(int Type, CUnpacker *pUnpacker)'] lines += ['{'] lines += ['\tm_pObjFailedOn = 0;'] lines += ['\tswitch(Type)'] lines += ['\t{'] lines += ['\tcase NETOBJTYPE_EX:'] lines += ['\t{'] lines += ['\t\tconst unsigned char *pPtr = pUnpacker->GetRaw(sizeof(CUuid));'] lines += ['\t\tif(pPtr != 0)'] lines += ['\t\t{'] lines += ['\t\t\tmem_copy(m_aUnpackedData, pPtr, sizeof(CUuid));'] lines += ['\t\t}'] lines += ['\t\tbreak;'] lines += ['\t}'] for item in network.Objects: base_item = None if item.base: base_item = next(i for i in network.Objects if i.name == item.base) for line in item.emit_uncompressed_unpack_and_validate(base_item): lines += ["\t" + line] lines += ['\t'] lines += ['\tdefault:'] lines += ['\t\tm_pObjFailedOn = "(type out of range)";'] lines += ['\t\tbreak;'] lines += ['\t}'] lines += ['\t'] lines += ['\tif(pUnpacker->Error())'] lines += ['\t\tm_pObjFailedOn = "(unpack error)";'] lines += ['\t'] lines += ['\tif(m_pObjFailedOn)'] lines += ['\t\treturn 0;'] lines += ['\tm_pObjFailedOn = "";'] lines += ['\treturn m_aUnpackedData;'] lines += ['}'] lines += [''] lines += ['void *CNetObjHandler::SecureUnpackMsg(int Type, CUnpacker *pUnpacker)'] lines += ['{'] lines += ['\tm_pMsgFailedOn = 0;'] lines += ['\tswitch(Type)'] lines += ['\t{'] for item in network.Messages: for line in item.emit_unpack_msg(): lines += ["\t" + line] lines += ['\t'] lines += ['\tdefault:'] lines += ['\t\tm_pMsgFailedOn = "(type out of range)";'] lines += ['\t\tbreak;'] lines += ['\t}'] lines += ['\t'] lines += ['\tif(pUnpacker->Error())'] lines += ['\t\tm_pMsgFailedOn = "(unpack error)";'] lines += ['\t'] lines += ['\tif(m_pMsgFailedOn)'] lines += ['\t\treturn 0;'] lines += ['\tm_pMsgFailedOn = "";'] lines += ['\treturn m_aUnpackedData;'] lines += ['}'] lines += [''] lines += ['bool CNetObjHandler::TeeHistorianRecordMsg(int Type)'] lines += ['{'] lines += ['\tswitch(Type)'] lines += ['\t{'] empty = True for msg in network.Messages: if not msg.teehistorian: lines += ['\tcase %s:' % msg.enum_name] empty = False if not empty: lines += ['\t\treturn false;'] lines += ['\tdefault:'] lines += ['\t\treturn true;'] lines += ['\t}'] lines += ['}'] lines += [''] lines += ['void RegisterGameUuids(CUuidManager *pManager)'] lines += ['{'] for item in network.Objects + network.Messages: if item.ex is not None: lines += ['\tpManager->RegisterName(%s, "%s");' % (item.enum_name, item.ex)] lines += ['\tRegisterMapItemTypeUuids(pManager);'] lines += ['}'] for l in lines: print(l) if gen_client_content_header or gen_server_content_header: print("#endif") if __name__ == '__main__': main()