mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-14 03:58:18 +00:00
5ae37e6c72
This system can easily be extended by independent authors without collisions, something the old system with plain increasing integers did not allow. Do this by utilizing the previously unused message code `NETMSG_NULL` which has a value of 0. This works for engine and game messages, snapshot items and events.
350 lines
9.5 KiB
Python
350 lines
9.5 KiB
Python
import sys
|
|
|
|
GlobalIdCounter = 0
|
|
def GetID():
|
|
global GlobalIdCounter
|
|
GlobalIdCounter += 1
|
|
return GlobalIdCounter
|
|
def GetUID():
|
|
return "x%d"%GetID()
|
|
|
|
def FixCasing(Str):
|
|
NewStr = ""
|
|
NextUpperCase = True
|
|
for c in Str:
|
|
if NextUpperCase:
|
|
NextUpperCase = False
|
|
NewStr += c.upper()
|
|
else:
|
|
if c == "_":
|
|
NextUpperCase = True
|
|
else:
|
|
NewStr += c.lower()
|
|
return NewStr
|
|
|
|
def FormatName(type, name):
|
|
if "*" in type:
|
|
return "m_p" + FixCasing(name)
|
|
if "[]" in type:
|
|
return "m_a" + FixCasing(name)
|
|
return "m_" + FixCasing(name)
|
|
|
|
class BaseType:
|
|
def __init__(self, type_name):
|
|
self._type_name = type_name
|
|
self._target_name = "INVALID"
|
|
self._id = GetID() # this is used to remember what order the members have in structures etc
|
|
|
|
def Identifyer(self): return "x"+str(self._id)
|
|
def TargetName(self): return self._target_name
|
|
def TypeName(self): return self._type_name
|
|
def ID(self): return self._id;
|
|
|
|
def EmitDeclaration(self, name):
|
|
return ["%s %s;"%(self.TypeName(), FormatName(self.TypeName(), name))]
|
|
def EmitPreDefinition(self, target_name):
|
|
self._target_name = target_name
|
|
return []
|
|
def EmitDefinition(self, name):
|
|
return []
|
|
|
|
class MemberType:
|
|
def __init__(self, name, var):
|
|
self.name = name
|
|
self.var = var
|
|
|
|
class Struct(BaseType):
|
|
def __init__(self, type_name):
|
|
BaseType.__init__(self, type_name)
|
|
def Members(self):
|
|
def sorter(a):
|
|
return a.var.ID()
|
|
m = []
|
|
for name in self.__dict__:
|
|
if name[0] == "_":
|
|
continue
|
|
m += [MemberType(name, self.__dict__[name])]
|
|
try:
|
|
m.sort(key = sorter)
|
|
except:
|
|
for v in m:
|
|
print(v.name, v.var)
|
|
sys.exit(-1)
|
|
return m
|
|
|
|
def EmitTypeDeclaration(self, name):
|
|
lines = []
|
|
lines += ["struct " + self.TypeName()]
|
|
lines += ["{"]
|
|
for member in self.Members():
|
|
lines += ["\t"+l for l in member.var.EmitDeclaration(member.name)]
|
|
lines += ["};"]
|
|
return lines
|
|
|
|
def EmitPreDefinition(self, target_name):
|
|
BaseType.EmitPreDefinition(self, target_name)
|
|
lines = []
|
|
for member in self.Members():
|
|
lines += member.var.EmitPreDefinition(target_name+"."+member.name)
|
|
return lines
|
|
def EmitDefinition(self, name):
|
|
lines = ["/* %s */ {" % self.TargetName()]
|
|
for member in self.Members():
|
|
lines += ["\t" + " ".join(member.var.EmitDefinition("")) + ","]
|
|
lines += ["}"]
|
|
return lines
|
|
|
|
class Array(BaseType):
|
|
def __init__(self, type):
|
|
BaseType.__init__(self, type.TypeName())
|
|
self.type = type
|
|
self.items = []
|
|
def Add(self, instance):
|
|
if instance.TypeName() != self.type.TypeName():
|
|
error("bah")
|
|
self.items += [instance]
|
|
def EmitDeclaration(self, name):
|
|
return ["int m_Num%s;"%(FixCasing(name)),
|
|
"%s *%s;"%(self.TypeName(), FormatName("[]", name))]
|
|
def EmitPreDefinition(self, target_name):
|
|
BaseType.EmitPreDefinition(self, target_name)
|
|
|
|
lines = []
|
|
i = 0
|
|
for item in self.items:
|
|
lines += item.EmitPreDefinition("%s[%d]"%(self.Identifyer(), i))
|
|
i += 1
|
|
|
|
if len(self.items):
|
|
lines += ["static %s %s[] = {"%(self.TypeName(), self.Identifyer())]
|
|
for item in self.items:
|
|
itemlines = item.EmitDefinition("")
|
|
lines += ["\t" + " ".join(itemlines).replace("\t", " ") + ","]
|
|
lines += ["};"]
|
|
else:
|
|
lines += ["static %s *%s = 0;"%(self.TypeName(), self.Identifyer())]
|
|
|
|
return lines
|
|
def EmitDefinition(self, name):
|
|
return [str(len(self.items))+","+self.Identifyer()]
|
|
|
|
# Basic Types
|
|
|
|
class Int(BaseType):
|
|
def __init__(self, value):
|
|
BaseType.__init__(self, "int")
|
|
self.value = value
|
|
def Set(self, value):
|
|
self.value = value
|
|
def EmitDefinition(self, name):
|
|
return ["%d"%self.value]
|
|
#return ["%d /* %s */"%(self.value, self._target_name)]
|
|
|
|
class Float(BaseType):
|
|
def __init__(self, value):
|
|
BaseType.__init__(self, "float")
|
|
self.value = value
|
|
def Set(self, value):
|
|
self.value = value
|
|
def EmitDefinition(self, name):
|
|
return ["%ff"%self.value]
|
|
#return ["%d /* %s */"%(self.value, self._target_name)]
|
|
|
|
class String(BaseType):
|
|
def __init__(self, value):
|
|
BaseType.__init__(self, "const char*")
|
|
self.value = value
|
|
def Set(self, value):
|
|
self.value = value
|
|
def EmitDefinition(self, name):
|
|
return ['"'+self.value+'"']
|
|
|
|
class Pointer(BaseType):
|
|
def __init__(self, type, target):
|
|
BaseType.__init__(self, "%s*"%type().TypeName())
|
|
self.target = target
|
|
def Set(self, target):
|
|
self.target = target
|
|
def EmitDefinition(self, name):
|
|
return ["&"+self.target.TargetName()]
|
|
|
|
# helper functions
|
|
|
|
def EmitTypeDeclaration(root):
|
|
for l in root().EmitTypeDeclaration(""):
|
|
print(l)
|
|
|
|
def EmitDefinition(root, name):
|
|
for l in root.EmitPreDefinition(name):
|
|
print(l)
|
|
print("%s %s = " % (root.TypeName(), name))
|
|
for l in root.EmitDefinition(name):
|
|
print(l)
|
|
print(";")
|
|
|
|
# Network stuff after this
|
|
|
|
class Object:
|
|
pass
|
|
|
|
class Enum:
|
|
def __init__(self, name, values):
|
|
self.name = name
|
|
self.values = values
|
|
|
|
class Flags:
|
|
def __init__(self, name, values):
|
|
self.name = name
|
|
self.values = values
|
|
|
|
class NetObject:
|
|
def __init__(self, name, variables, ex=None):
|
|
l = name.split(":")
|
|
self.name = l[0]
|
|
self.base = ""
|
|
if len(l) > 1:
|
|
self.base = l[1]
|
|
self.base_struct_name = "CNetObj_%s" % self.base
|
|
self.struct_name = "CNetObj_%s" % self.name
|
|
self.enum_name = "NETOBJTYPE_%s" % self.name.upper()
|
|
self.variables = variables
|
|
self.ex = ex
|
|
def emit_declaration(self):
|
|
if self.base:
|
|
lines = ["struct %s : public %s"%(self.struct_name,self.base_struct_name), "{"]
|
|
else:
|
|
lines = ["struct %s"%self.struct_name, "{"]
|
|
for v in self.variables:
|
|
lines += ["\t"+line for line in v.emit_declaration()]
|
|
lines += ["};"]
|
|
return lines
|
|
def emit_validate(self):
|
|
lines = ["case %s:" % self.enum_name]
|
|
lines += ["{"]
|
|
lines += ["\t%s *pObj = (%s *)pData;"%(self.struct_name, self.struct_name)]
|
|
lines += ["\tif((int)sizeof(*pObj) > Size) return -1;"]
|
|
for v in self.variables:
|
|
lines += ["\t"+line for line in v.emit_validate()]
|
|
lines += ["\treturn 0;"]
|
|
lines += ["}"]
|
|
return lines
|
|
|
|
class NetEvent(NetObject):
|
|
def __init__(self, name, variables, ex=None):
|
|
NetObject.__init__(self, name, variables, ex=ex)
|
|
self.base_struct_name = "CNetEvent_%s" % self.base
|
|
self.struct_name = "CNetEvent_%s" % self.name
|
|
self.enum_name = "NETEVENTTYPE_%s" % self.name.upper()
|
|
|
|
class NetMessage(NetObject):
|
|
def __init__(self, name, variables, ex=None):
|
|
NetObject.__init__(self, name, variables, ex=ex)
|
|
self.base_struct_name = "CNetMsg_%s" % self.base
|
|
self.struct_name = "CNetMsg_%s" % self.name
|
|
self.enum_name = "NETMSGTYPE_%s" % self.name.upper()
|
|
def emit_unpack(self):
|
|
lines = []
|
|
lines += ["case %s:" % self.enum_name]
|
|
lines += ["{"]
|
|
lines += ["\t%s *pMsg = (%s *)m_aMsgData;" % (self.struct_name, self.struct_name)]
|
|
lines += ["\t(void)pMsg;"]
|
|
for v in self.variables:
|
|
lines += ["\t"+line for line in v.emit_unpack()]
|
|
for v in self.variables:
|
|
lines += ["\t"+line for line in v.emit_unpack_check()]
|
|
lines += ["} break;"]
|
|
return lines
|
|
def emit_declaration(self):
|
|
extra = []
|
|
extra += ["\tint MsgID() const { return %s; }" % self.enum_name]
|
|
extra += ["\t"]
|
|
extra += ["\tbool Pack(CMsgPacker *pPacker)"]
|
|
extra += ["\t{"]
|
|
#extra += ["\t\tmsg_pack_start(%s, flags);"%self.enum_name]
|
|
for v in self.variables:
|
|
extra += ["\t\t"+line for line in v.emit_pack()]
|
|
extra += ["\t\treturn pPacker->Error() != 0;"]
|
|
extra += ["\t}"]
|
|
|
|
|
|
lines = NetObject.emit_declaration(self)
|
|
lines = lines[:-1] + extra + lines[-1:]
|
|
return lines
|
|
|
|
class NetObjectEx(NetObject):
|
|
def __init__(self, name, ex, variables):
|
|
NetObject.__init__(self, name, variables, ex=ex)
|
|
|
|
class NetEventEx(NetEvent):
|
|
def __init__(self, name, ex, variables):
|
|
NetEvent.__init__(self, name, variables, ex=ex)
|
|
|
|
class NetMessageEx(NetMessage):
|
|
def __init__(self, name, ex, variables):
|
|
NetMessage.__init__(self, name, variables, ex=ex)
|
|
|
|
|
|
class NetVariable:
|
|
def __init__(self, name):
|
|
self.name = name
|
|
def emit_declaration(self):
|
|
return []
|
|
def emit_validate(self):
|
|
return []
|
|
def emit_pack(self):
|
|
return []
|
|
def emit_unpack(self):
|
|
return []
|
|
def emit_unpack_check(self):
|
|
return []
|
|
|
|
class NetString(NetVariable):
|
|
def emit_declaration(self):
|
|
return ["const char *%s;"%self.name]
|
|
def emit_unpack(self):
|
|
return ["pMsg->%s = pUnpacker->GetString();" % self.name]
|
|
def emit_pack(self):
|
|
return ["pPacker->AddString(%s, -1);" % self.name]
|
|
|
|
class NetStringHalfStrict(NetVariable):
|
|
def emit_declaration(self):
|
|
return ["const char *%s;"%self.name]
|
|
def emit_unpack(self):
|
|
return ["pMsg->%s = pUnpacker->GetString(CUnpacker::SANITIZE_CC);" % self.name]
|
|
def emit_pack(self):
|
|
return ["pPacker->AddString(%s, -1);" % self.name]
|
|
|
|
class NetStringStrict(NetVariable):
|
|
def emit_declaration(self):
|
|
return ["const char *%s;"%self.name]
|
|
def emit_unpack(self):
|
|
return ["pMsg->%s = pUnpacker->GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES);" % self.name]
|
|
def emit_pack(self):
|
|
return ["pPacker->AddString(%s, -1);" % self.name]
|
|
|
|
class NetIntAny(NetVariable):
|
|
def emit_declaration(self):
|
|
return ["int %s;"%self.name]
|
|
def emit_unpack(self):
|
|
return ["pMsg->%s = pUnpacker->GetInt();" % self.name]
|
|
def emit_pack(self):
|
|
return ["pPacker->AddInt(%s);" % self.name]
|
|
|
|
class NetIntRange(NetIntAny):
|
|
def __init__(self, name, min, max):
|
|
NetIntAny.__init__(self,name)
|
|
self.min = str(min)
|
|
self.max = str(max)
|
|
def emit_validate(self):
|
|
return ["pObj->%s = ClampInt(\"%s\", pObj->%s, %s, %s);"%(self.name, self.name, self.name, self.min, self.max)]
|
|
def emit_unpack_check(self):
|
|
return ["if(pMsg->%s < %s || pMsg->%s > %s) { m_pMsgFailedOn = \"%s\"; break; }" % (self.name, self.min, self.name, self.max, self.name)]
|
|
|
|
class NetBool(NetIntRange):
|
|
def __init__(self, name):
|
|
NetIntRange.__init__(self,name,0,1)
|
|
|
|
class NetTick(NetIntAny):
|
|
def __init__(self, name):
|
|
NetIntAny.__init__(self,name)
|