This commit is contained in:
Chiller Dragon 2024-04-28 18:55:19 +02:00 committed by GitHub
commit 49d9a7b748
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 216 additions and 24 deletions

View File

@ -112,6 +112,8 @@ public:
const char *FailedObjOn() const;
const char *GetMsgName(int Type) const;
void DebugDumpSnapshot(const class CSnapshot *pSnap) const;
int DumpObj(int Type, const void *pData, int Size) const;
void *SecureUnpackMsg(int Type, CUnpacker *pUnpacker);
bool TeeHistorianRecordMsg(int Type);
const char *FailedMsgOn() const;
@ -130,7 +132,9 @@ def gen_network_source():
#include <engine/shared/packer.h>
#include <engine/shared/protocol.h>
#include <engine/shared/uuid_manager.h>
#include <engine/shared/snapshot.h>
#include <game/gamecore.h>
#include <game/mapitems_ex.h>
CNetObjHandler::CNetObjHandler()
@ -242,8 +246,50 @@ const char *CNetObjHandler::GetMsgName(int Type) const
}
return "(out of range)";
}
void CNetObjHandler::DebugDumpSnapshot(const CSnapshot *pSnap) const
{
dbg_msg("snapshot", "data_size=%d num_items=%d", pSnap->DataSize(), pSnap->NumItems());
for(int i = 0; i < pSnap->NumItems(); i++)
{
const CSnapshotItem *pItem = pSnap->GetItem(i);
int Size = pSnap->GetItemSize(i);
int Type = pSnap->GetItemType(i);
const char *pName = GetObjName(pItem->Type());
if(Type > OFFSET_UUID && Type < g_UuidManager.NumUuids() + OFFSET_UUID)
pName = g_UuidManager.GetName(Type);
dbg_msg("snapshot", "\\t%s type=%d id=%d size=%d", pName, pItem->Type(), pItem->Id(), Size);
if(!DumpObj(Type, pItem->Data(), Size))
continue;
for(size_t b = 0; b < Size / sizeof(int32_t); b++)
dbg_msg("snapshot", "\\t\\t%3d %12d\\t%08x", (int)b, pItem->Data()[b], pItem->Data()[b]);
}
}
""")
lines = []
lines += ['int CNetObjHandler::DumpObj(int Type, const void *pData, int Size) const']
lines += ['{']
lines += ["\tchar aRawData[512];"]
lines += ["\tint aInts[2];"]
lines += ["\taInts[1] = 0x80808000;"]
lines += ["\tchar aStr[sizeof(aInts)];"]
lines += ['\tswitch(Type)']
lines += ['\t{']
for item in network.Objects:
for line in item.emit_dump(network.Objects):
lines += ["\t" + line]
lines += ['\t']
lines += ['\t}']
lines += ['\treturn -1;']
lines += ['};']
lines += ['']
for line in lines:
print(line)
lines = []
lines += ["""\
void *CNetObjHandler::SecureUnpackObj(int Type, CUnpacker *pUnpacker)
@ -272,10 +318,10 @@ void *CNetObjHandler::SecureUnpackObj(int Type, CUnpacker *pUnpacker)
m_pObjFailedOn = "(type out of range)";
break;
}
if(pUnpacker->Error())
m_pObjFailedOn = "(unpack error)";
if(m_pObjFailedOn)
return 0;
m_pObjFailedOn = "";
@ -305,10 +351,10 @@ void *CNetObjHandler::SecureUnpackMsg(int Type, CUnpacker *pUnpacker)
m_pMsgFailedOn = "(type out of range)";
break;
}
if(pUnpacker->Error())
m_pMsgFailedOn = "(unpack error)";
if(m_pMsgFailedOn)
return 0;
m_pMsgFailedOn = "";

View File

@ -232,6 +232,15 @@ class NetObject:
lines += ["};"]
return lines
def members_from_this_and_parents(self, objects):
variables = self.variables
next_base_name = self.base
while next_base_name is not None:
base_item = only([i for i in objects if i.name == next_base_name])
variables = base_item.variables + variables
next_base_name = base_item.base
return variables
def emit_uncompressed_unpack_and_validate(self, objects):
lines = []
lines += [f"case {self.enum_name}:"]
@ -239,12 +248,7 @@ class NetObject:
lines += [f"\t{self.struct_name} *pData = ({self.struct_name} *)m_aUnpackedData;"]
unpack_lines = []
variables = self.variables
next_base_name = self.base
while next_base_name is not None:
base_item = only([i for i in objects if i.name == next_base_name])
variables = base_item.variables + variables
next_base_name = base_item.base
variables = self.members_from_this_and_parents(objects)
for v in variables:
if not self.validate_size and v.default is None:
raise ValueError(f"{v.name} in {self.name} has no default value. Member variables that do not have a default value cannot be used in a structure whose size is not validated.")
@ -259,6 +263,26 @@ class NetObject:
lines += ["} break;"]
return lines
def emit_dump(self, objects):
lines = []
lines += [f"case {self.enum_name}:"]
lines += ["{"]
lines += [f"\t{self.struct_name} *pObj = ({self.struct_name} *)pData;"]
unpack_lines = []
variables = self.members_from_this_and_parents(objects)
offset = 0
for v in variables:
unpack_lines += ["\t"+line for line in v.emit_dump(offset)]
offset += 1
if len(unpack_lines) > 0:
lines += unpack_lines
else:
lines += ["\t(void)pData;"]
lines += ["return 0;"]
lines += ["};"]
return lines
class NetEvent(NetObject):
def __init__(self, name, variables, ex=None):
NetObject.__init__(self, name, variables, ex=ex)
@ -339,6 +363,8 @@ class NetVariable:
return []
def emit_unpack_msg_check(self):
return []
def emit_dump(self, offset):
return [f"str_format(aRawData, sizeof(aRawData), \"\\t\\t%3d %12d\\t%08x\", {offset}, ((const int *)pData)[{offset}], ((const int *)pData)[{offset}]);"]
class NetString(NetVariable):
def emit_declaration(self):
@ -383,6 +409,16 @@ class NetIntAny(NetVariable):
return [f"pData->{self.name} = pUnpacker->GetIntOrDefault({self.default});"]
def emit_pack(self):
return [f"pPacker->AddInt({self.name});"]
def emit_dump(self, offset):
return NetVariable(self.name).emit_dump(offset) + \
[f"dbg_msg(\"snapshot\", \"%s\\t{self.name}=%d\", aRawData, pObj->{self.name});"]
class NetTwIntString(NetIntAny):
def emit_dump(self, offset):
return NetVariable(self.name).emit_dump(offset) + \
[f"aInts[0] = pObj->{self.name};"] + \
["IntsToStr(aInts, std::size(aInts), aStr, std::size(aStr));"] + \
[f"dbg_msg(\"snapshot\", \"%s\\t{self.name}=%d\\tIntToStr: %s\", aRawData, pObj->{self.name}, aStr);"]
class NetIntRange(NetIntAny):
def __init__(self, name, min_val, max_val, default=None):
@ -393,6 +429,23 @@ class NetIntRange(NetIntAny):
return [f"pData->{self.name} = ClampInt(\"{self.name}\", pData->{self.name}, {self.min}, {self.max});"]
def emit_unpack_msg_check(self):
return [f"if(pData->{self.name} < {self.min} || pData->{self.name} > {self.max}) {{ m_pMsgFailedOn = \"{self.name}\"; break; }}"]
def emit_dump(self, offset):
min_fmt=f"min={self.min}"
min_arg = ''
try:
int(self.min)
except ValueError:
min_fmt = f"min={self.min}(%d)"
min_arg = f", (int){self.min}"
max_fmt=f"max={self.max}"
max_arg = ''
try:
int(self.max)
except ValueError:
max_fmt = f"max={self.max}(%d)"
max_arg = f", (int){self.max}"
return NetVariable(self.name).emit_dump(offset) + \
[f"dbg_msg(\"snapshot\", \"%s\\t{self.name}=%d ({min_fmt} {max_fmt})\", aRawData, pObj->{self.name}{min_arg}{max_arg});"]
class NetBool(NetIntRange):
def __init__(self, name, default=None):
@ -402,6 +455,9 @@ class NetBool(NetIntRange):
class NetTick(NetIntAny):
def __init__(self, name, default=None):
NetIntAny.__init__(self,name,default=default)
def emit_dump(self, offset):
return NetVariable(self.name).emit_dump(offset) + \
[f"dbg_msg(\"snapshot\", \"%s\\t{self.name}=%d (NetTick)\", aRawData, pObj->{self.name});"]
class NetArray(NetVariable):
def __init__(self, var, size):

View File

@ -1,7 +1,8 @@
# pylint: skip-file
# See https://github.com/ddnet/ddnet/issues/3507
from datatypes import Enum, Flags, NetArray, NetBool, NetEvent, NetIntAny, NetIntRange, NetMessage, NetMessageEx, NetObject, NetObjectEx, NetString, NetStringHalfStrict, NetStringStrict, NetTick
from datatypes import Enum, Flags, NetArray, NetBool, NetEvent, NetIntAny, NetTwIntString, NetIntRange
from datatypes import NetMessage, NetMessageEx, NetObject, NetObjectEx, NetString, NetStringHalfStrict, NetStringStrict, NetTick
Emotes = ["NORMAL", "PAIN", "HAPPY", "SURPRISE", "ANGRY", "BLINK"]
PlayerFlags = ["PLAYING", "IN_MENU", "CHATTING", "SCOREBOARD", "AIM"]
@ -217,17 +218,17 @@ Objects = [
NetObject("ClientInfo", [
# 4*4 = 16 characters
NetIntAny("m_Name0"), NetIntAny("m_Name1"), NetIntAny("m_Name2"),
NetIntAny("m_Name3"),
NetTwIntString("m_Name0"), NetTwIntString("m_Name1"), NetTwIntString("m_Name2"),
NetTwIntString("m_Name3"),
# 4*3 = 12 characters
NetIntAny("m_Clan0"), NetIntAny("m_Clan1"), NetIntAny("m_Clan2"),
NetTwIntString("m_Clan0"), NetTwIntString("m_Clan1"), NetTwIntString("m_Clan2"),
NetIntAny("m_Country"),
# 4*6 = 24 characters
NetIntAny("m_Skin0"), NetIntAny("m_Skin1"), NetIntAny("m_Skin2"),
NetIntAny("m_Skin3"), NetIntAny("m_Skin4"), NetIntAny("m_Skin5"),
NetTwIntString("m_Skin0"), NetTwIntString("m_Skin1"), NetTwIntString("m_Skin2"),
NetTwIntString("m_Skin3"), NetTwIntString("m_Skin4"), NetTwIntString("m_Skin5"),
NetIntRange("m_UseCustomColor", 0, 1),
@ -545,7 +546,7 @@ Messages = [
NetIntAny("m_ServerTimeBest"),
NetIntAny("m_PlayerTimeBest"),
]),
NetMessageEx("Sv_KillMsgTeam", "killmsgteam@netmsg.ddnet.tw", [
NetIntRange("m_Team", 0, 'MAX_CLIENTS-1'),
NetIntRange("m_First", -1, 'MAX_CLIENTS-1'),

View File

@ -87,6 +87,7 @@ def main():
print("#ifndef GAME_GENERATED_PROTOCOL7_H")
print("#define GAME_GENERATED_PROTOCOL7_H")
print("class CUnpacker;")
print("class CSnapshot;")
print("#include <engine/message.h>")
print("namespace protocol7 {")
print(network.RawHeader)
@ -150,6 +151,8 @@ def main():
CNetObjHandler();
int ValidateObj(int Type, const void *pData, int Size);
void DebugDumpSnapshot(const CSnapshot *pSnap) const;
int DumpObj(int Type, const void *pData, int Size) const;
const char *GetObjName(int Type) const;
int GetObjSize(int Type) const;
const char *FailedObjOn() const;
@ -174,6 +177,7 @@ def main():
lines += ['#include <base/system.h>']
lines += ['#include <engine/shared/packer.h>']
lines += ['#include <engine/shared/protocol.h>']
lines += ['#include <engine/shared/snapshot.h>']
lines += ['namespace protocol7 {']
@ -269,6 +273,43 @@ def main():
lines += ['};']
lines += ['']
print("""\
void CNetObjHandler::DebugDumpSnapshot(const ::CSnapshot *pSnap) const
{
dbg_msg("snapshot", "data_size=%d num_items=%d", pSnap->DataSize(), pSnap->NumItems());
for(int i = 0; i < pSnap->NumItems(); i++)
{
const CSnapshotItem *pItem = pSnap->GetItem(i);
int Size = pSnap->GetItemSize(i);
int Type = pSnap->GetItemType(i);
const char *pName = GetObjName(pItem->Type());
if(Type > OFFSET_UUID && Type < g_UuidManager.NumUuids() + OFFSET_UUID)
pName = g_UuidManager.GetName(Type);
dbg_msg("snapshot", "\\t%s type=%d id=%d size=%d", pName, pItem->Type(), pItem->Id(), Size);
if(!DumpObj(Type, pItem->Data(), Size))
continue;
for(size_t b = 0; b < Size / sizeof(int32_t); b++)
dbg_msg("snapshot", "\\t\\t%3d %12d\\t%08x", (int)b, pItem->Data()[b], pItem->Data()[b]);
}
}\n""")
lines = []
lines += ['int CNetObjHandler::DumpObj(int Type, const void *pData, int Size) const']
lines += ['{']
lines += ["\tchar aRawData[512];"]
lines += ['\tswitch(Type)']
lines += ['\t{']
for item in network.Objects:
for line in item.emit_dump(network.Objects):
lines += ["\t" + line]
lines += ['\t']
lines += ['\t}']
lines += ['\treturn -1;']
lines += ['};']
lines += ['']
lines += ['void *CNetObjHandler::SecureUnpackMsg(int Type, CUnpacker *pUnpacker)']
lines += ['{']
lines += ['\tm_pMsgFailedOn = 0;']

View File

@ -234,24 +234,38 @@ class NetObject:
lines += ["\t"+line for line in v.emit_declaration()]
lines += ["};"]
return lines
def emit_validate(self, objects):
lines = [f"case {self.enum_name}:"]
lines += ["{"]
lines += [f"\t{self.struct_name} *pObj = ({self.struct_name} *)pData;"]
lines += ["\tif(sizeof(*pObj) != Size) return -1;"]
def members_from_this_and_parents(self, objects):
variables = self.variables
next_base_name = self.base
while next_base_name is not None:
base_item = only([i for i in objects if i.name == next_base_name])
variables = base_item.variables + variables
next_base_name = base_item.base
return variables
def emit_validate(self, objects):
lines = [f"case {self.enum_name}:"]
lines += ["{"]
lines += [f"\t{self.struct_name} *pObj = ({self.struct_name} *)pData;"]
lines += ["\tif(sizeof(*pObj) != Size) return -1;"]
variables = self.members_from_this_and_parents(objects)
for v in variables:
lines += ["\t"+line for line in v.emit_validate()]
lines += ["\treturn 0;"]
lines += ["}"]
return lines
def emit_dump(self, objects):
lines = [f"case {self.enum_name}:"]
lines += ["{"]
lines += [f"\t{self.struct_name} *pObj = ({self.struct_name} *)pData;"]
lines += ["\tif(sizeof(*pObj) != Size) return -1;"]
variables = self.members_from_this_and_parents(objects)
offset = 0
for v in variables:
lines += ["\t"+line for line in v.emit_dump(offset)]
offset += 1
lines += ["\treturn 0;"]
lines += ["}"]
return lines
class NetEvent(NetObject):
@ -312,6 +326,8 @@ class NetVariable:
return []
def emit_unpack_check(self):
return []
def emit_dump(self, offset):
return [f"str_format(aRawData, sizeof(aRawData), \"\\t\\t%3d %12d\\t%08x\", {offset}, ((const int *)pData)[{offset}], ((const int *)pData)[{offset}]);"]
class NetString(NetVariable):
def emit_declaration(self):
@ -338,6 +354,9 @@ class NetIntAny(NetVariable):
return [f"pMsg->{self.name} = pUnpacker->GetIntOrDefault({self.default});"]
def emit_pack(self):
return [f"pPacker->AddInt({self.name});"]
def emit_dump(self, offset):
return NetVariable(self.name).emit_dump(offset) + \
[f"dbg_msg(\"snapshot\", \"%s\\t{self.name}=%d\", aRawData, pObj->{self.name});"]
class NetIntRange(NetIntAny):
def __init__(self, name, min_val, max_val, default=None):
@ -348,6 +367,23 @@ class NetIntRange(NetIntAny):
return [f"if(!CheckInt(\"{self.name}\", pObj->{self.name}, {self.min}, {self.max})) return -1;"]
def emit_unpack_check(self):
return [f"if(!CheckInt(\"{self.name}\", pMsg->{self.name}, {self.min}, {self.max})) break;"]
def emit_dump(self, offset):
min_fmt=f"min={self.min}"
min_arg = ''
try:
int(self.min)
except ValueError:
min_fmt = f"min={self.min}(%d)"
min_arg = f", (int){self.min}"
max_fmt=f"max={self.max}"
max_arg = ''
try:
int(self.max)
except ValueError:
max_fmt = f"max={self.max}(%d)"
max_arg = f", (int){self.max}"
return NetVariable(self.name).emit_dump(offset) + \
[f"dbg_msg(\"snapshot\", \"%s\\t{self.name}=%d ({min_fmt} {max_fmt})\", aRawData, pObj->{self.name}{min_arg}{max_arg});"]
class NetEnum(NetIntRange):
def __init__(self, name, enum):
@ -366,6 +402,9 @@ class NetFlag(NetIntAny):
return [f"if(!CheckFlag(\"{self.name}\", pObj->{self.name}, {self.mask})) return -1;"]
def emit_unpack_check(self):
return [f"if(!CheckFlag(\"{self.name}\", pMsg->{self.name}, {self.mask})) break;"]
def emit_dump(self, offset):
return NetVariable(self.name).emit_dump(offset) + \
[f"dbg_msg(\"snapshot\", \"%s\\t{self.name}=%d (mask=%d)\", aRawData, pObj->{self.name}, {self.mask});"]
class NetBool(NetIntRange):
def __init__(self, name, default=None):

View File

@ -345,6 +345,9 @@ public:
virtual const char *Version() const = 0;
virtual const char *NetVersion() const = 0;
virtual CNetObjHandler *GetNetObjHandler() = 0;
virtual protocol7::CNetObjHandler *GetNetObjHandler7() = 0;
// DDRace
virtual void OnPreTickTeehistorian() = 0;

View File

@ -49,6 +49,7 @@ public:
};
int NumItems() const { return m_NumItems; }
int DataSize() const { return m_DataSize; }
const CSnapshotItem *GetItem(int Index) const;
int GetItemSize(int Index) const;
int GetItemIndex(int Key) const;
@ -57,6 +58,9 @@ public:
const void *FindItem(int Type, int Id) const;
unsigned Crc() const;
// Prints the raw snapshot data showing item and int boundaries.
// See also `CNetObjHandler::DebugDumpSnapshot(const CSnapshot *pSnap)`
// For more detailed annotations of the data.
void DebugDump() const;
bool IsValid(size_t ActualSize) const;

View File

@ -168,6 +168,8 @@ public:
IAntibot *Antibot() { return m_pAntibot; }
CTeeHistorian *TeeHistorian() { return &m_TeeHistorian; }
bool TeeHistorianActive() const { return m_TeeHistorianActive; }
CNetObjHandler *GetNetObjHandler() override { return &m_NetObjHandler; }
protocol7::CNetObjHandler *GetNetObjHandler7() override { return &m_NetObjHandler7; }
CGameContext();
CGameContext(int Reset);