init
This commit is contained in:
437
datasrc/compile.py
Executable file
437
datasrc/compile.py
Executable file
@ -0,0 +1,437 @@
|
||||
import argparse
|
||||
import content
|
||||
import network
|
||||
|
||||
from datatypes import EmitDefinition, EmitTypeDeclaration
|
||||
|
||||
def create_enum_table(names, num):
|
||||
lines = []
|
||||
lines += ["enum", "{"]
|
||||
for name in names:
|
||||
lines += [f"\t{name},"]
|
||||
lines += [f"\t{num}", "};"]
|
||||
return lines
|
||||
|
||||
|
||||
def create_flags_table(names):
|
||||
lines = []
|
||||
lines += ["enum", "{"]
|
||||
for i, name in enumerate(names):
|
||||
lines += [f"\t{name} = 1<<{int(i)},"]
|
||||
lines += ["};"]
|
||||
return lines
|
||||
|
||||
|
||||
def EmitEnum(names, num):
|
||||
print("enum")
|
||||
print("{")
|
||||
print(f"\t{names[0]}=0,")
|
||||
for name in names[1:]:
|
||||
print(f"\t{name},")
|
||||
print(f"\t{num}")
|
||||
print("};")
|
||||
|
||||
|
||||
def EmitFlags(names):
|
||||
print("enum")
|
||||
print("{")
|
||||
for i, name in enumerate(names):
|
||||
print(f"\t{name} = 1<<{int(i)},")
|
||||
print("};")
|
||||
|
||||
|
||||
def gen_network_header():
|
||||
print("#ifndef GAME_GENERATED_PROTOCOL_H")
|
||||
print("#define GAME_GENERATED_PROTOCOL_H")
|
||||
print("class CUnpacker;")
|
||||
print("#include <engine/message.h>")
|
||||
print(network.RawHeader)
|
||||
|
||||
for e in network.Enums:
|
||||
for line in create_enum_table([f"{e.name}_{v}" for v in e.values], f'NUM_{e.name}S'): # pylint: disable=no-member
|
||||
print(line)
|
||||
print("")
|
||||
|
||||
for e in network.Flags:
|
||||
for line in create_flags_table([f"{e.name}_{v}" for v in e.values]):
|
||||
print(line)
|
||||
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 line in create_enum_table(["NETOBJTYPE_EX"]+[o.enum_name for o in non_extended], "NUM_NETOBJTYPES"):
|
||||
print(line)
|
||||
for line in create_enum_table(["__NETOBJTYPE_UUID_HELPER=OFFSET_GAME_UUID-1"]+[o.enum_name for o in extended], "OFFSET_NETMSGTYPE_UUID"):
|
||||
print(line)
|
||||
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 line in create_enum_table(["NETMSGTYPE_EX"]+[o.enum_name for o in non_extended], "NUM_NETMSGTYPES"):
|
||||
print(line)
|
||||
print("")
|
||||
for line in create_enum_table(["__NETMSGTYPE_UUID_HELPER=OFFSET_NETMSGTYPE_UUID-1"]+[o.enum_name for o in extended], "OFFSET_MAPITEMTYPE_UUID"):
|
||||
print(line)
|
||||
print("")
|
||||
|
||||
for item in network.Objects + network.Messages:
|
||||
for line in item.emit_declaration():
|
||||
print(line)
|
||||
print("")
|
||||
|
||||
EmitEnum([f"SOUND_{i.name.value.upper()}" for i in content.container.sounds.items], "NUM_SOUNDS")
|
||||
EmitEnum([f"WEAPON_{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")
|
||||
|
||||
|
||||
def gen_network_source():
|
||||
|
||||
print("""\
|
||||
#include "protocol.h"
|
||||
|
||||
#include <engine/shared/packer.h>
|
||||
#include <engine/shared/protocol.h>
|
||||
#include <engine/shared/uuid_manager.h>
|
||||
|
||||
#include <game/mapitems_ex.h>
|
||||
|
||||
CNetObjHandler::CNetObjHandler()
|
||||
{
|
||||
m_pMsgFailedOn = "";
|
||||
m_pObjFailedOn = "";
|
||||
m_pObjCorrectedOn = "";
|
||||
m_NumObjCorrections = 0;
|
||||
}
|
||||
|
||||
int CNetObjHandler::NumObjCorrections() const { return m_NumObjCorrections; }
|
||||
const char *CNetObjHandler::CorrectedObjOn() const { return m_pObjCorrectedOn; }
|
||||
const char *CNetObjHandler::FailedObjOn() const { return m_pObjFailedOn; }
|
||||
const char *CNetObjHandler::FailedMsgOn() const { return m_pMsgFailedOn; }
|
||||
|
||||
static const int max_int = 0x7fffffff;
|
||||
static const int min_int = 0x80000000;
|
||||
|
||||
int CNetObjHandler::ClampInt(const char *pErrorMsg, int Value, int Min, int Max)
|
||||
{
|
||||
if(Value < Min) { m_pObjCorrectedOn = pErrorMsg; m_NumObjCorrections++; return Min; }
|
||||
if(Value > Max) { m_pObjCorrectedOn = pErrorMsg; m_NumObjCorrections++; return Max; }
|
||||
return Value;
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
lines = []
|
||||
lines += ["const char *CNetObjHandler::ms_apObjNames[] = {"]
|
||||
lines += ['\t"EX/UUID",']
|
||||
lines += [f'\t"{o.name}",' for o in network.Objects if o.ex is None]
|
||||
lines += ['\t""', "};", ""]
|
||||
|
||||
lines += ["const char *CNetObjHandler::ms_apExObjNames[] = {"]
|
||||
lines += ['\t"invalid",']
|
||||
lines += [f'\t"{o.name}",' for o in network.Objects if o.ex is not None]
|
||||
lines += ['\t""', "};", ""]
|
||||
|
||||
lines += ["int CNetObjHandler::ms_aObjSizes[] = {"]
|
||||
lines += ['\t0,']
|
||||
lines += [f'\tsizeof({o.struct_name}),' for o in network.Objects if o.ex is None]
|
||||
lines += ['\t0', "};", ""]
|
||||
|
||||
lines += ["int CNetObjHandler::ms_aUnpackedObjSizes[] = {"]
|
||||
lines += ['\t16,']
|
||||
lines += [f'\tsizeof({o.struct_name}),' for o in network.Objects if o.ex is None]
|
||||
lines += ["};", ""]
|
||||
|
||||
lines += ["int CNetObjHandler::ms_aUnpackedExObjSizes[] = {"]
|
||||
lines += ['\t0,']
|
||||
lines += [f'\tsizeof({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 += [f'\t"{msg.name}",' for msg in network.Messages if msg.ex is None]
|
||||
lines += ['\t""', "};", ""]
|
||||
|
||||
lines += ['const char *CNetObjHandler::ms_apExMsgNames[] = {']
|
||||
lines += ['\t"invalid",']
|
||||
lines += [f'\t"{msg.name}",' for msg in network.Messages if msg.ex is not None]
|
||||
lines += ['\t""', "};", ""]
|
||||
|
||||
for line in lines:
|
||||
print(line)
|
||||
|
||||
print("""\
|
||||
const char *CNetObjHandler::GetObjName(int Type) const
|
||||
{
|
||||
if(Type >= 0 && Type < NUM_NETOBJTYPES)
|
||||
{
|
||||
return ms_apObjNames[Type];
|
||||
}
|
||||
else if(Type > __NETOBJTYPE_UUID_HELPER && Type < OFFSET_NETMSGTYPE_UUID)
|
||||
{
|
||||
return ms_apExObjNames[Type - __NETOBJTYPE_UUID_HELPER];
|
||||
}
|
||||
return "(out of range)";
|
||||
}
|
||||
|
||||
int CNetObjHandler::GetObjSize(int Type) const
|
||||
{
|
||||
if(Type < 0 || Type >= NUM_NETOBJTYPES) return 0;
|
||||
return ms_aObjSizes[Type];
|
||||
}
|
||||
|
||||
int CNetObjHandler::GetUnpackedObjSize(int Type) const
|
||||
{
|
||||
if(Type >= 0 && Type < NUM_NETOBJTYPES)
|
||||
{
|
||||
return ms_aUnpackedObjSizes[Type];
|
||||
}
|
||||
else if(Type > __NETOBJTYPE_UUID_HELPER && Type < OFFSET_NETMSGTYPE_UUID)
|
||||
{
|
||||
return ms_aUnpackedExObjSizes[Type - __NETOBJTYPE_UUID_HELPER];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *CNetObjHandler::GetMsgName(int Type) const
|
||||
{
|
||||
if(Type >= 0 && Type < NUM_NETMSGTYPES)
|
||||
{
|
||||
return ms_apMsgNames[Type];
|
||||
}
|
||||
else if(Type > __NETMSGTYPE_UUID_HELPER && Type < OFFSET_MAPITEMTYPE_UUID)
|
||||
{
|
||||
return ms_apExMsgNames[Type - __NETMSGTYPE_UUID_HELPER];
|
||||
}
|
||||
return "(out of range)";
|
||||
}
|
||||
""")
|
||||
|
||||
lines = []
|
||||
lines += ["""\
|
||||
void *CNetObjHandler::SecureUnpackObj(int Type, CUnpacker *pUnpacker)
|
||||
{
|
||||
m_pObjFailedOn = 0;
|
||||
switch(Type)
|
||||
{
|
||||
case NETOBJTYPE_EX:
|
||||
{
|
||||
const unsigned char *pPtr = pUnpacker->GetRaw(sizeof(CUuid));
|
||||
if(pPtr != 0)
|
||||
{
|
||||
mem_copy(m_aUnpackedData, pPtr, sizeof(CUuid));
|
||||
}
|
||||
break;
|
||||
}
|
||||
"""]
|
||||
|
||||
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 += ["""\
|
||||
default:
|
||||
m_pObjFailedOn = "(type out of range)";
|
||||
break;
|
||||
}
|
||||
|
||||
if(pUnpacker->Error())
|
||||
m_pObjFailedOn = "(unpack error)";
|
||||
|
||||
if(m_pObjFailedOn)
|
||||
return 0;
|
||||
m_pObjFailedOn = "";
|
||||
return m_aUnpackedData;
|
||||
}
|
||||
"""]
|
||||
for line in lines:
|
||||
print(line)
|
||||
|
||||
|
||||
lines = []
|
||||
lines += ["""\
|
||||
void *CNetObjHandler::SecureUnpackMsg(int Type, CUnpacker *pUnpacker)
|
||||
{
|
||||
m_pMsgFailedOn = 0;
|
||||
switch(Type)
|
||||
{
|
||||
"""]
|
||||
|
||||
for item in network.Messages:
|
||||
for line in item.emit_unpack_msg():
|
||||
lines += ["\t" + line]
|
||||
lines += ['\t']
|
||||
|
||||
lines += ["""\
|
||||
default:
|
||||
m_pMsgFailedOn = "(type out of range)";
|
||||
break;
|
||||
}
|
||||
|
||||
if(pUnpacker->Error())
|
||||
m_pMsgFailedOn = "(unpack error)";
|
||||
|
||||
if(m_pMsgFailedOn)
|
||||
return 0;
|
||||
m_pMsgFailedOn = "";
|
||||
return m_aUnpackedData;
|
||||
}
|
||||
"""]
|
||||
for line in lines:
|
||||
print(line)
|
||||
|
||||
|
||||
lines = []
|
||||
lines += ["""\
|
||||
bool CNetObjHandler::TeeHistorianRecordMsg(int Type)
|
||||
{
|
||||
switch(Type)
|
||||
{
|
||||
"""]
|
||||
|
||||
empty = True
|
||||
for msg in network.Messages:
|
||||
if not msg.teehistorian:
|
||||
lines += [f'\tcase {msg.enum_name}:']
|
||||
empty = False
|
||||
if not empty:
|
||||
lines += ['\t\treturn false;']
|
||||
|
||||
lines += ["""\
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
"""]
|
||||
for line in lines:
|
||||
print(line)
|
||||
|
||||
|
||||
lines = []
|
||||
lines += ["""\
|
||||
void RegisterGameUuids(CUuidManager *pManager)
|
||||
{
|
||||
"""]
|
||||
|
||||
for item in network.Objects + network.Messages:
|
||||
if item.ex is not None:
|
||||
lines += [f'\tpManager->RegisterName({item.enum_name}, "{item.ex}");']
|
||||
|
||||
lines += ["""
|
||||
RegisterMapItemTypeUuids(pManager);
|
||||
}
|
||||
"""]
|
||||
for line in lines:
|
||||
print(line)
|
||||
|
||||
|
||||
def gen_common_content_header():
|
||||
# print some includes
|
||||
print('#include <engine/graphics.h>')
|
||||
|
||||
# emit the type declarations
|
||||
with open("datasrc/content.py", "rb") as content_file:
|
||||
contentlines = content_file.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([f"IMAGE_{i.name.value.upper()}" for i in content.container.images.items], "NUM_IMAGES")
|
||||
EmitEnum([f"ANIM_{i.name.value.upper()}" for i in content.container.animations.items], "NUM_ANIMS")
|
||||
EmitEnum([f"SPRITE_{i.name.value.upper()}" for i in content.container.sprites.items], "NUM_SPRITES")
|
||||
|
||||
def gen_common_content_source():
|
||||
EmitDefinition(content.container, "datacontainer")
|
||||
print('CDataContainer *g_pData = &datacontainer;')
|
||||
|
||||
def gen_client_content_header():
|
||||
print("#ifndef CLIENT_CONTENT_HEADER")
|
||||
print("#define CLIENT_CONTENT_HEADER")
|
||||
gen_common_content_header()
|
||||
print("#endif")
|
||||
|
||||
|
||||
def gen_client_content_source():
|
||||
print('#include "client_data.h"')
|
||||
gen_common_content_source()
|
||||
|
||||
|
||||
def gen_server_content_header():
|
||||
print("#ifndef SERVER_CONTENT_HEADER")
|
||||
print("#define SERVER_CONTENT_HEADER")
|
||||
gen_common_content_header()
|
||||
print("#endif")
|
||||
|
||||
|
||||
def gen_server_content_source():
|
||||
print('#include "server_data.h"')
|
||||
gen_common_content_source()
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description=('Generate C++ Source Files for the Teeworlds Network Protocol')
|
||||
)
|
||||
FUNCTION_MAP = {
|
||||
'network_header': gen_network_header,
|
||||
'network_source': gen_network_source,
|
||||
'client_content_header': gen_client_content_header,
|
||||
'client_content_source': gen_client_content_source,
|
||||
'server_content_header': gen_server_content_header,
|
||||
'server_content_source': gen_server_content_source,
|
||||
}
|
||||
|
||||
parser.add_argument('file_to_generate', choices=FUNCTION_MAP.keys())
|
||||
args = parser.parse_args()
|
||||
FUNCTION_MAP[args.file_to_generate]()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Reference in New Issue
Block a user