diff --git a/.gitignore b/.gitignore index ba91678a4..bfa1e6904 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ teeworlds* teeworlds_srv* !other/bash-completion/teeworlds_srv testrunner +uuid* versionsrv* # IDE project files diff --git a/CMakeLists.txt b/CMakeLists.txt index e12070c8e..40200a184 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1295,6 +1295,7 @@ set_src(ENGINE_INTERFACE GLOB src/engine sound.h storage.h textrender.h + uuid.h ) set_src(ENGINE_SHARED GLOB src/engine/shared compression.cpp @@ -1313,6 +1314,7 @@ set_src(ENGINE_SHARED GLOB src/engine/shared engine.cpp filecollection.cpp filecollection.h + global_uuid_manager.cpp huffman.cpp huffman.h jobs.cpp @@ -1343,11 +1345,16 @@ set_src(ENGINE_SHARED GLOB src/engine/shared packer.cpp packer.h protocol.h + protocol_ex.cpp + protocol_ex.h + protocol_ex_msgs.h ringbuffer.cpp ringbuffer.h snapshot.cpp snapshot.h storage.cpp + uuid_manager.cpp + uuid_manager.h ) set(ENGINE_GENERATED_SHARED src/generated/nethash.cpp src/generated/protocol.cpp src/generated/protocol.h) set_src(GAME_SHARED GLOB src/game @@ -1691,6 +1698,7 @@ set_src(TOOLS GLOB src/tools map_resave.cpp map_version.cpp packetgen.cpp + uuid.cpp ) foreach(ABS_T ${TOOLS}) file(RELATIVE_PATH T "${PROJECT_SOURCE_DIR}/src/tools/" ${ABS_T}) @@ -1723,6 +1731,7 @@ if(GTEST_FOUND OR DOWNLOAD_GTEST) bytes_be.cpp compression.cpp datafile.cpp + ex.cpp fs.cpp git_revision.cpp hash.cpp diff --git a/datasrc/compile.py b/datasrc/compile.py index 9ef5eaf7e..94539bb1c 100644 --- a/datasrc/compile.py +++ b/datasrc/compile.py @@ -6,8 +6,7 @@ def create_enum_table(names, num): lines = [] lines += ["enum", "{"] - lines += ["\t%s=0,"%names[0]] - for name in names[1:]: + for name in names: lines += ["\t%s,"%name] lines += ["\t%s" % num, "};"] return lines @@ -109,9 +108,17 @@ def EmitFlags(names, num): for l in create_flags_table(["%s_%s" % (e.name, v) for v in e.values]): print(l) print("") - for l in create_enum_table(["NETOBJ_INVALID"]+[o.enum_name for o in network.Objects], "NUM_NETOBJTYPES"): print(l) + 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(["NETMSG_INVALID"]+[o.enum_name for o in network.Messages], "NUM_NETMSGTYPES"): print(l) + for l in create_enum_table(["__NETMSGTYPE_UUID_HELPER=OFFSET_NETMSGTYPE_UUID-1"]+[o.enum_name for o in extended], "END_NETMSGTYPE_UUID"): print(l) print("") for item in network.Objects + network.Messages: @@ -198,19 +205,20 @@ class CNetObjHandler lines += ["const char *CNetObjHandler::ms_apObjNames[] = {"] lines += ['\t"invalid",'] - lines += ['\t"%s",' % o.name for o in network.Objects] + lines += ['\t"%s",' % o.name for o in network.Objects if o.ex is None] lines += ['\t""', "};", ""] lines += ["int CNetObjHandler::ms_aObjSizes[] = {"] lines += ['\t0,'] - lines += ['\tsizeof(%s),' % o.struct_name for o in network.Objects] + lines += ['\tsizeof(%s),' % o.struct_name for o in network.Objects if o.ex is None] lines += ['\t0', "};", ""] lines += ['const char *CNetObjHandler::ms_apMsgNames[] = {'] lines += ['\t"invalid",'] for msg in network.Messages: - lines += ['\t"%s",' % msg.name] + if msg.ex is None: + lines += ['\t"%s",' % msg.name] lines += ['\t""'] lines += ['};'] lines += [''] @@ -267,6 +275,10 @@ class CNetObjHandler lines += ['{'] lines += ['\tswitch(Type)'] lines += ['\t{'] + lines += ['\tcase NETOBJTYPE_EX:'] + lines += ['\t{'] + lines += ['\t\treturn 0;'] + lines += ['\t}'] for item in network.Objects: base_item = None @@ -333,6 +345,14 @@ class CNetObjHandler 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 += ['}'] + for l in lines: print(l) diff --git a/datasrc/datatypes.py b/datasrc/datatypes.py index da47ef40d..fd1d54873 100644 --- a/datasrc/datatypes.py +++ b/datasrc/datatypes.py @@ -210,7 +210,7 @@ def __init__(self, name, values): self.values = values class NetObject: - def __init__(self, name, variables): + def __init__(self, name, variables, ex=None, fixup=True): l = name.split(":") self.name = l[0] self.base = "" @@ -220,6 +220,10 @@ def __init__(self, name, variables): self.struct_name = "CNetObj_%s" % self.name self.enum_name = "NETOBJTYPE_%s" % self.name.upper() self.variables = variables + if fixup and ex != None: + ex = "object-{}".format(ex) + self.ex = ex + def emit_declaration(self): if self.base: lines = ["struct %s : public %s"%(self.struct_name,self.base_struct_name), "{"] @@ -234,26 +238,24 @@ def emit_validate(self, base_item): lines += ["{"] lines += ["\tconst %s *pObj = (const %s *)pData;"%(self.struct_name, self.struct_name)] lines += ["\tif(sizeof(*pObj) != Size) return -1;"] - variables = self.variables - if base_item: - variables += base_item.variables - for v in variables: + 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): - NetObject.__init__(self, name, variables) + 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): - NetObject.__init__(self, name, variables) + def __init__(self, name, variables, ex=None): + if ex != None: + ex = "message-{}".format(ex) + NetObject.__init__(self, name, variables, ex=ex, fixup=False) self.base_struct_name = "CNetMsg_%s" % self.base self.struct_name = "CNetMsg_%s" % self.name self.enum_name = "NETMSGTYPE_%s" % self.name.upper() @@ -286,6 +288,18 @@ def 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, default=None): diff --git a/datasrc/network.py b/datasrc/network.py index 309460959..5e088d079 100644 --- a/datasrc/network.py +++ b/datasrc/network.py @@ -24,6 +24,7 @@ RawHeader = ''' #include +#include enum { @@ -229,6 +230,10 @@ NetArray(NetIntAny("m_aTuneParams"), 32), ]), + NetObjectEx("MyOwnObject", "my-own-object@heinrich5991.de", [ + NetIntAny("m_Test"), + ]), + ## Events NetEvent("Common", [ @@ -268,6 +273,10 @@ NetIntRange("m_Precision", 0, 3), NetFlag("m_RaceFlags", RaceFlags), ]), + + NetObjectEx("MyOwnEvent", "my-own-event@heinrich5991.de", [ + NetIntAny("m_Test"), + ]), ] Messages = [ @@ -481,4 +490,9 @@ NetStringStrict("m_Arguments") ]), + # Can't add any NetMessages here! + + NetMessageEx("Sv_MyOwnMessage", "my-own-message@heinrich5991.de", [ + NetIntAny("m_Test"), + ]), ] diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 6426d8605..8bc29acab 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -32,8 +32,10 @@ #include #include #include +#include #include #include +#include #include @@ -627,7 +629,7 @@ const void *CClient::SnapGetItem(int SnapID, int Index, CSnapItem *pItem) const dbg_assert(SnapID >= 0 && SnapID < NUM_SNAPSHOT_TYPES, "invalid SnapID"); const CSnapshotItem *i = m_aSnapshots[SnapID]->m_pAltSnap->GetItem(Index); pItem->m_DataSize = m_aSnapshots[SnapID]->m_pAltSnap->GetItemSize(Index); - pItem->m_Type = i->Type(); + pItem->m_Type = m_aSnapshots[SnapID]->m_pAltSnap->GetItemType(Index); pItem->m_ID = i->ID(); return i->Data(); } @@ -646,8 +648,7 @@ const void *CClient::SnapFindItem(int SnapID, int Type, int ID) const return 0x0; CSnapshot* pAltSnap = m_aSnapshots[SnapID]->m_pAltSnap; - int Key = (Type<<16)|(ID&0xffff); - int Index = pAltSnap->GetItemIndex(Key); + int Index = pAltSnap->GetItemIndex(Type, ID); if(Index != -1) return pAltSnap->GetItem(Index)->Data(); @@ -1143,14 +1144,29 @@ void CClient::ProcessConnlessPacket(CNetChunk *pPacket) void CClient::ProcessServerPacket(CNetChunk *pPacket) { - CMsgUnpacker Unpacker(pPacket->m_pData, pPacket->m_DataSize); - if(Unpacker.Error()) + CUnpacker Unpacker; + Unpacker.Reset(pPacket->m_pData, pPacket->m_DataSize); + CMsgPacker Packer(NETMSG_EX); + + // unpack msgid and system flag + int Msg; + bool Sys; + CUuid Uuid; + + int Result = UnpackMessageID(&Msg, &Sys, &Uuid, &Unpacker, &Packer, m_pConfig->m_Debug); + if(Result == UNPACKMESSAGE_ERROR) + { return; + } + else if(Result == UNPACKMESSAGE_ANSWER) + { + SendMsg(&Packer, MSGFLAG_VITAL); + } - if(Unpacker.System()) + if(Sys) { // system message - if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Type() == NETMSG_MAP_CHANGE) + if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_MAP_CHANGE) { const char *pMap = Unpacker.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES); int MapCrc = Unpacker.GetInt(); @@ -1223,7 +1239,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) } } } - else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Type() == NETMSG_MAP_DATA) + else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_MAP_DATA) { if(!m_MapdownloadFileTemp) return; @@ -1273,7 +1289,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client/network", "requested next chunk package"); } } - else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Type() == NETMSG_SERVERINFO) + else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_SERVERINFO) { CServerInfo Info = {0}; net_addr_str(&pPacket->m_Address, Info.m_aAddress, sizeof(Info.m_aAddress), true); @@ -1284,16 +1300,16 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) m_CurrentServerInfo.m_NetAddr = m_ServerAddress; } } - else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Type() == NETMSG_CON_READY) + else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_CON_READY) { GameClient()->OnConnected(); } - else if(Unpacker.Type() == NETMSG_PING) + else if(Msg == NETMSG_PING) { CMsgPacker Msg(NETMSG_PING_REPLY, true); SendMsg(&Msg, MSGFLAG_FLUSH); } - else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Type() == NETMSG_RCON_CMD_ADD) + else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_CMD_ADD) { const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC); const char *pHelp = Unpacker.GetString(CUnpacker::SANITIZE_CC); @@ -1301,30 +1317,30 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) if(Unpacker.Error() == 0) m_pConsole->RegisterTemp(pName, pParams, CFGFLAG_SERVER, pHelp); } - else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Type() == NETMSG_RCON_CMD_REM) + else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_CMD_REM) { const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC); if(Unpacker.Error() == 0) m_pConsole->DeregisterTemp(pName); } - else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Type() == NETMSG_MAPLIST_ENTRY_ADD) + else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_MAPLIST_ENTRY_ADD) { const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC); if(Unpacker.Error() == 0) m_pConsole->RegisterTempMap(pName); } - else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Type() == NETMSG_MAPLIST_ENTRY_REM) + else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_MAPLIST_ENTRY_REM) { const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC); if(Unpacker.Error() == 0) m_pConsole->DeregisterTempMap(pName); } - else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Type() == NETMSG_RCON_AUTH_ON) + else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_AUTH_ON) { m_RconAuthed = 1; m_UseTempRconCommands = 1; } - else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Type() == NETMSG_RCON_AUTH_OFF) + else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_AUTH_OFF) { m_RconAuthed = 0; if(m_UseTempRconCommands) @@ -1332,19 +1348,19 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) m_UseTempRconCommands = 0; m_pConsole->DeregisterTempMapAll(); } - else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Type() == NETMSG_RCON_LINE) + else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_LINE) { const char *pLine = Unpacker.GetString(); if(Unpacker.Error() == 0) GameClient()->OnRconLine(pLine); } - else if(Unpacker.Type() == NETMSG_PING_REPLY) + else if(Msg == NETMSG_PING_REPLY) { char aBuf[256]; str_format(aBuf, sizeof(aBuf), "latency %.2f", (time_get() - m_PingStartTime)*1000 / (float)time_freq()); m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client/network", aBuf); } - else if(Unpacker.Type() == NETMSG_INPUTTIMING) + else if(Msg == NETMSG_INPUTTIMING) { int InputPredTick = Unpacker.GetInt(); int TimeLeft = Unpacker.GetInt(); @@ -1364,7 +1380,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) if(Target) m_PredictedTime.Update(&m_InputtimeMarginGraph, Target, TimeLeft, 1); } - else if(Unpacker.Type() == NETMSG_SNAP || Unpacker.Type() == NETMSG_SNAPSINGLE || Unpacker.Type() == NETMSG_SNAPEMPTY) + else if(Msg == NETMSG_SNAP || Msg == NETMSG_SNAPSINGLE || Msg == NETMSG_SNAPEMPTY) { // we are not allowed to process snapshot yet if(State() < IClient::STATE_LOADING) @@ -1375,7 +1391,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) int NumParts = 1; int Part = 0; - if(Unpacker.Type() == NETMSG_SNAP) + if(Msg == NETMSG_SNAP) { NumParts = Unpacker.GetInt(); Part = Unpacker.GetInt(); @@ -1386,7 +1402,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) int PartSize = 0; int Crc = 0; const char *pData = 0; - if(Unpacker.Type() != NETMSG_SNAPEMPTY) + if(Msg != NETMSG_SNAPEMPTY) { Crc = Unpacker.GetInt(); PartSize = Unpacker.GetInt(); @@ -1477,7 +1493,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) return; } - if(Unpacker.Type() != NETMSG_SNAPEMPTY && pTmpBuffer3->Crc() != Crc) + if(Msg != NETMSG_SNAPEMPTY && pTmpBuffer3->Crc() != Crc) { if(Config()->m_Debug) { @@ -1563,7 +1579,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0) { // game message - GameClient()->OnMessage(Unpacker.Type(), &Unpacker); + GameClient()->OnMessage(Msg, &Unpacker); if(m_RecordGameMessage && m_DemoRecorder.IsRecording()) m_DemoRecorder.RecordMessage(pPacket->m_pData, pPacket->m_DataSize); @@ -1635,12 +1651,19 @@ void CClient::OnDemoPlayerSnapshot(void *pData, int Size) void CClient::OnDemoPlayerMessage(void *pData, int Size) { - CMsgUnpacker Unpacker(pData, Size); + CUnpacker Unpacker; + Unpacker.Reset(pData, Size); + + // unpack msgid and system flag + int Msg = Unpacker.GetInt(); + int Sys = Msg&1; + Msg >>= 1; + if(Unpacker.Error()) return; - if(!Unpacker.System()) - GameClient()->OnMessage(Unpacker.Type(), &Unpacker); + if(!Sys) + GameClient()->OnMessage(Msg, &Unpacker); } void CClient::Update() @@ -1935,6 +1958,11 @@ void CClient::Run() m_LocalStartTime = time_get(); m_SnapshotParts = 0; + if(Config()->m_Debug) + { + g_UuidManager.DebugDump(); + } + // init SDL { if(SDL_Init(0) < 0) diff --git a/src/engine/message.h b/src/engine/message.h index 77d8ed2b4..6be57e624 100644 --- a/src/engine/message.h +++ b/src/engine/message.h @@ -4,6 +4,7 @@ #define ENGINE_MESSAGE_H #include +#include class CMsgPacker : public CPacker { @@ -11,12 +12,13 @@ class CMsgPacker : public CPacker CMsgPacker(int Type, bool System = false) { Reset(); - if(Type < 0 || Type > 0x3FFFFFFF) + // NETMSG_EX, NETMSGTYPE_EX for UUID messages + int NetType = Type < OFFSET_UUID ? Type : 0; + AddInt((NetType<<1)|(System?1:0)); + if(Type >= OFFSET_UUID) { - m_Error = true; - return; + g_UuidManager.PackUuid(Type, this); } - AddInt((Type << 1) | (System ? 1 : 0)); } }; diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 73276bf6a..2d852c2d5 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -803,15 +804,30 @@ void CServer::UpdateClientMapListEntries() void CServer::ProcessClientPacket(CNetChunk *pPacket) { - CMsgUnpacker Unpacker(pPacket->m_pData, pPacket->m_DataSize); - if(Unpacker.Error()) + const int ClientID = pPacket->m_ClientID; + CUnpacker Unpacker; + Unpacker.Reset(pPacket->m_pData, pPacket->m_DataSize); + CMsgPacker Packer(NETMSG_EX); + + // unpack msgid and system flag + int Msg; + bool Sys; + CUuid Uuid; + + int Result = UnpackMessageID(&Msg, &Sys, &Uuid, &Unpacker, &Packer, m_pConfig->m_Debug); + if(Result == UNPACKMESSAGE_ERROR) + { return; + } + else if(Result == UNPACKMESSAGE_ANSWER) + { + SendMsg(&Packer, MSGFLAG_VITAL, ClientID); + } - const int ClientID = pPacket->m_ClientID; - if(Unpacker.System()) + if(Sys) { // system message - if(Unpacker.Type() == NETMSG_INFO) + if(Msg == NETMSG_INFO) { if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && m_aClients[ClientID].m_State == CClient::STATE_AUTH) { @@ -840,7 +856,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) SendMap(ClientID); } } - else if(Unpacker.Type() == NETMSG_REQUEST_MAP_DATA) + else if(Msg == NETMSG_REQUEST_MAP_DATA) { if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && (m_aClients[ClientID].m_State == CClient::STATE_CONNECTING || m_aClients[ClientID].m_State == CClient::STATE_CONNECTING_AS_SPEC)) { @@ -874,7 +890,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) } } } - else if(Unpacker.Type() == NETMSG_READY) + else if(Msg == NETMSG_READY) { if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && (m_aClients[ClientID].m_State == CClient::STATE_CONNECTING || m_aClients[ClientID].m_State == CClient::STATE_CONNECTING_AS_SPEC)) { @@ -891,7 +907,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) SendConnectionReady(ClientID); } } - else if(Unpacker.Type() == NETMSG_ENTERGAME) + else if(Msg == NETMSG_ENTERGAME) { if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && m_aClients[ClientID].m_State == CClient::STATE_READY && GameServer()->IsClientReady(ClientID)) { @@ -906,7 +922,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) GameServer()->OnClientEnter(ClientID); } } - else if(Unpacker.Type() == NETMSG_INPUT) + else if(Msg == NETMSG_INPUT) { CClient::CInput *pInput; int64 TagTime; @@ -963,7 +979,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) if(m_aClients[ClientID].m_State == CClient::STATE_INGAME) GameServer()->OnClientDirectInput(ClientID, m_aClients[ClientID].m_LatestInput.m_aData); } - else if(Unpacker.Type() == NETMSG_RCON_CMD) + else if(Msg == NETMSG_RCON_CMD) { const char *pCmd = Unpacker.GetString(); @@ -981,7 +997,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) m_RconAuthLevel = AUTHED_ADMIN; } } - else if(Unpacker.Type() == NETMSG_RCON_AUTH) + else if(Msg == NETMSG_RCON_AUTH) { const char *pPw = Unpacker.GetString(CUnpacker::SANITIZE_CC); @@ -1048,7 +1064,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) } } } - else if(Unpacker.Type() == NETMSG_PING) + else if(Msg == NETMSG_PING) { CMsgPacker Msg(NETMSG_PING_REPLY, true); SendMsg(&Msg, MSGFLAG_FLUSH, ClientID); @@ -1058,7 +1074,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) if(Config()->m_Debug) { char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "strange message ClientID=%d msg=%d data_size=%d", ClientID, Unpacker.Type(), pPacket->m_DataSize); + str_format(aBuf, sizeof(aBuf), "strange message ClientID=%d msg=%d data_size=%d", ClientID, Msg, pPacket->m_DataSize); Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "server", aBuf); str_hex(aBuf, sizeof(aBuf), pPacket->m_pData, minimum(pPacket->m_DataSize, 32)); Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "server", aBuf); @@ -1069,7 +1085,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) { // game message if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && m_aClients[ClientID].m_State >= CClient::STATE_READY) - GameServer()->OnMessage(Unpacker.Type(), &Unpacker, ClientID); + GameServer()->OnMessage(Msg, &Unpacker, ClientID); } } @@ -1326,6 +1342,11 @@ void CServer::InitInterfaces(IKernel *pKernel) int CServer::Run() { + if(Config()->m_Debug) + { + g_UuidManager.DebugDump(); + } + // m_PrintCBIndex = Console()->RegisterPrintCallback(Config()->m_ConsoleOutputLevel, SendRconLineAuthed, this); @@ -1840,8 +1861,11 @@ void CServer::SnapFreeID(int ID) void *CServer::SnapNewItem(int Type, int ID, int Size) { - dbg_assert(Type >= 0 && Type <=0xffff, "incorrect type"); - dbg_assert(ID >= 0 && ID <=0xffff, "incorrect id"); + if(!(Type >= 0 && Type <= 0xffff)) + { + g_UuidManager.GetUuid(Type); + } + dbg_assert(ID >= 0 && ID <= 0xffff, "incorrect id"); return ID < 0 ? 0 : m_SnapshotBuilder.NewItem(Type, ID, Size); } diff --git a/src/engine/shared/global_uuid_manager.cpp b/src/engine/shared/global_uuid_manager.cpp new file mode 100644 index 000000000..40b56e03c --- /dev/null +++ b/src/engine/shared/global_uuid_manager.cpp @@ -0,0 +1,14 @@ +#include "protocol_ex.h" +#include "uuid_manager.h" + +#include + +static CUuidManager CreateGlobalUuidManager() +{ + CUuidManager Manager; + RegisterUuids(&Manager); + RegisterGameUuids(&Manager); + return Manager; +} + +CUuidManager g_UuidManager = CreateGlobalUuidManager(); diff --git a/src/engine/shared/protocol.h b/src/engine/shared/protocol.h index 5242c4231..30cec76c2 100644 --- a/src/engine/shared/protocol.h +++ b/src/engine/shared/protocol.h @@ -30,7 +30,7 @@ enum { - NETMSG_NULL=0, + NETMSG_EX=0, // the first thing sent by the client // contains the version info for the client @@ -73,6 +73,8 @@ enum NETMSG_MAPLIST_ENTRY_ADD,// todo 0.8: move up NETMSG_MAPLIST_ENTRY_REM, + + NUM_NETMSGS, }; // this should be revised diff --git a/src/engine/shared/protocol_ex.cpp b/src/engine/shared/protocol_ex.cpp new file mode 100644 index 000000000..4803775a4 --- /dev/null +++ b/src/engine/shared/protocol_ex.cpp @@ -0,0 +1,102 @@ +#include "protocol_ex.h" + +#include "config.h" +#include "protocol.h" +#include "uuid_manager.h" + +#include + +void RegisterUuids(class CUuidManager *pManager) +{ + #define UUID(id, name) pManager->RegisterName(id, "system-message-" name); + #include "protocol_ex_msgs.h" + #undef UUID +} + +int UnpackMessageID(int *pID, bool *pSys, struct CUuid *pUuid, CUnpacker *pUnpacker, CMsgPacker *pPacker, bool Debug) +{ + *pID = 0; + *pSys = false; + mem_zero(pUuid, sizeof(*pUuid)); + + int MsgID = pUnpacker->GetInt(); + + if(pUnpacker->Error()) + { + return UNPACKMESSAGE_ERROR; + } + + *pID = MsgID >> 1; + *pSys = MsgID & 1; + + if(*pID < 0 || *pID >= OFFSET_UUID) + { + return UNPACKMESSAGE_ERROR; + } + + if(*pID != 0) // NETMSG_EX, NETMSGTYPE_EX + { + return UNPACKMESSAGE_OK; + } + + *pID = g_UuidManager.UnpackUuid(pUnpacker, pUuid); + + if(*pID == UUID_INVALID || *pID == UUID_UNKNOWN) + { + return UNPACKMESSAGE_ERROR; + } + + if(*pSys) + { + switch(*pID) + { + case NETMSG_WHATIS: + { + CUuid Uuid2; + int ID2 = g_UuidManager.UnpackUuid(pUnpacker, &Uuid2); + if(ID2 == UUID_INVALID) + { + break; + } + if(ID2 == UUID_UNKNOWN) + { + new (pPacker) CMsgPacker(NETMSG_IDONTKNOW, true); + pPacker->AddRaw(&Uuid2, sizeof(Uuid2)); + } + else + { + new (pPacker) CMsgPacker(NETMSG_ITIS, true); + pPacker->AddRaw(&Uuid2, sizeof(Uuid2)); + pPacker->AddString(g_UuidManager.GetName(ID2), 0); + } + return UNPACKMESSAGE_ANSWER; + } + case NETMSG_IDONTKNOW: + if(Debug) + { + CUuid Uuid2; + g_UuidManager.UnpackUuid(pUnpacker, &Uuid2); + if(pUnpacker->Error()) + break; + char aBuf[UUID_MAXSTRSIZE]; + FormatUuid(Uuid2, aBuf, sizeof(aBuf)); + dbg_msg("uuid", "peer: unknown %s", aBuf); + } + break; + case NETMSG_ITIS: + if(Debug) + { + CUuid Uuid2; + g_UuidManager.UnpackUuid(pUnpacker, &Uuid2); + const char *pName = pUnpacker->GetString(CUnpacker::SANITIZE_CC); + if(pUnpacker->Error()) + break; + char aBuf[UUID_MAXSTRSIZE]; + FormatUuid(Uuid2, aBuf, sizeof(aBuf)); + dbg_msg("uuid", "peer: %s %s", aBuf, pName); + } + break; + } + } + return UNPACKMESSAGE_OK; +} diff --git a/src/engine/shared/protocol_ex.h b/src/engine/shared/protocol_ex.h new file mode 100644 index 000000000..e4cf521c8 --- /dev/null +++ b/src/engine/shared/protocol_ex.h @@ -0,0 +1,28 @@ +#ifndef ENGINE_SHARED_PROTOCOL_EX_H +#define ENGINE_SHARED_PROTOCOL_EX_H + +#include + +enum +{ + NETMSG_EX_INVALID=UUID_INVALID, + NETMSG_EX_UNKNOWN=UUID_UNKNOWN, + + OFFSET_NETMSG_UUID=OFFSET_UUID, + + __NETMSG_UUID_HELPER=OFFSET_NETMSG_UUID-1, + #define UUID(id, name) id, + #include "protocol_ex_msgs.h" + #undef UUID + OFFSET_GAME_UUID, + + UNPACKMESSAGE_ERROR=0, + UNPACKMESSAGE_OK, + UNPACKMESSAGE_ANSWER, +}; + +void RegisterUuids(class CUuidManager *pManager); + +int UnpackMessageID(int *pID, bool *pSys, struct CUuid *pUuid, CUnpacker *pUnpacker, CMsgPacker *pPacker, bool Debug); + +#endif // ENGINE_SHARED_PROTOCOL_EX_H diff --git a/src/engine/shared/protocol_ex_msgs.h b/src/engine/shared/protocol_ex_msgs.h new file mode 100644 index 000000000..66640b12c --- /dev/null +++ b/src/engine/shared/protocol_ex_msgs.h @@ -0,0 +1,23 @@ +// UUID(name_in_code, name) +// +// When adding your own extended net messages, choose the name (third +// parameter) as `@` where `` is a name you can choose +// freely and `` is a domain you own. If you don't own a domain, try +// choosing a string that is not a domain and uniquely identifies you, e.g. use +// the name of the client/server you develop. +// +// Example: +// +// 1) `i-unfreeze-you@ddnet.tw` +// 2) `creeper@minetee` +// +// The first example applies if you own the `ddnet.tw` domain, that is, if you +// are adding this message on behalf of the DDNet team. +// +// The second example shows how you could add a message if you don't own a +// domain, but need a message for your minetee client/server. + +UUID(NETMSG_WHATIS, "what-is@ddnet.tw") +UUID(NETMSG_ITIS, "it-is@ddnet.tw") +UUID(NETMSG_IDONTKNOW, "i-dont-know@ddnet.tw") +UUID(NETMSG_MYOWNMESSAGE, "my-own-message@heinrich5991.de") diff --git a/src/engine/shared/snapshot.cpp b/src/engine/shared/snapshot.cpp index 3e26fb3bc..f6391f1b2 100644 --- a/src/engine/shared/snapshot.cpp +++ b/src/engine/shared/snapshot.cpp @@ -7,6 +7,7 @@ #include "snapshot.h" #include "compression.h" +#include "uuid_manager.h" // CSnapshot @@ -22,8 +23,41 @@ int CSnapshot::GetItemSize(int Index) const return (Offsets()[Index+1] - Offsets()[Index]) - sizeof(CSnapshotItem); } -int CSnapshot::GetItemIndex(int Key) const +int CSnapshot::GetItemIndex(int Type, int ID) const { + int InternalType = -1; + if(Type < OFFSET_UUID) + { + InternalType = Type; + } + else + { + CUuid Uuid = g_UuidManager.GetUuid(Type); + int aUuid[sizeof(CUuid) / 4]; + for(int i = 0; i < (int)sizeof(CUuid) / 4; i++) + { + aUuid[i] = + (Uuid.m_aData[i * 4 + 0] << 24) | + (Uuid.m_aData[i * 4 + 1] << 16) | + (Uuid.m_aData[i * 4 + 2] << 8) | + (Uuid.m_aData[i * 4 + 3]); + } + for(int i = 0; i < m_NumItems && SortedKeys()[i] < ((1<<16)|0); i++) + { + if(GetItemSize(i) >= (int)sizeof(aUuid) && + mem_comp(aUuid, GetItem(i)->Data(), sizeof(aUuid)) == 0) + { + InternalType = SortedKeys()[i]&0xffff; + break; + } + } + } + if(InternalType == -1) + { + return -1; + } + + int Key = (InternalType<<16)|ID; plain_range_sorted Keys(SortedKeys(), SortedKeys() + m_NumItems); plain_range_sorted r = ::find_binary(Keys, Key); @@ -31,14 +65,45 @@ int CSnapshot::GetItemIndex(int Key) const return -1; int Index = &r.front() - SortedKeys(); - if(GetItem(Index)->Key() != Key) + if(GetItem(Index)->Key() == -1) return -1; // deleted return Index; } +int CSnapshot::GetItemType(int Index) const +{ + int InternalType = GetItem(Index)->Type(); + if(InternalType < OFFSET_UUID_TYPE) + { + return InternalType; + } + + int TypeItemIndex = GetItemIndex(0, InternalType); // NETOBJTYPE_EX + if(TypeItemIndex == -1 || GetItemSize(TypeItemIndex) < (int)sizeof(CUuid)) + { + return InternalType; + } + + const CSnapshotItem *pTypeItem = GetItem(TypeItemIndex); + CUuid Uuid; + for(int i = 0; i < (int)sizeof(CUuid) / 4; i++) + { + Uuid.m_aData[i * 4 + 0] = pTypeItem->Data()[i] >> 24; + Uuid.m_aData[i * 4 + 1] = pTypeItem->Data()[i] >> 16; + Uuid.m_aData[i * 4 + 2] = pTypeItem->Data()[i] >> 8; + Uuid.m_aData[i * 4 + 3] = pTypeItem->Data()[i]; + } + + return g_UuidManager.LookupUuid(Uuid); +} + void CSnapshot::InvalidateItem(int Index) { - ((CSnapshotItem *)(DataStart() + Offsets()[Index]))->Invalidate(); + CSnapshotItem *pItem = (CSnapshotItem *)(DataStart() + Offsets()[Index]); + if(pItem->Type() != 0) // NETOBJTYPE_EX + { + pItem->Invalidate(); + } } int CSnapshot::Serialize(char *pDstData) const @@ -351,8 +416,8 @@ int CSnapshotDelta::UnpackDelta(const CSnapshot *pFrom, CSnapshot *pTo, const vo return -3; ID = *pData++; - if(ID < 0 || ID > CSnapshot::MAX_ID) - return -3; + //if(ID < 0 || ID > CSnapshot::MAX_ID) + // return -3; if(Type < MAX_NETOBJSIZES && m_aItemSizes[Type]) ItemSize = m_aItemSizes[Type]; @@ -376,7 +441,7 @@ int CSnapshotDelta::UnpackDelta(const CSnapshot *pFrom, CSnapshot *pTo, const vo //if(range_check(pEnd, pNewData, ItemSize)) return -4; - FromIndex = pFrom->GetItemIndex(Key); + FromIndex = pFrom->GetItemIndex(Type, ID); if(FromIndex != -1) { // we got an update so we need to apply the diff @@ -513,11 +578,20 @@ int CSnapshotStorage::Get(int Tick, int64 *pTagtime, CSnapshot **ppData, CSnapsh } // CSnapshotBuilder +CSnapshotBuilder::CSnapshotBuilder() +{ + m_NumExtendedItemTypes = 0; +} void CSnapshotBuilder::Init() { m_DataSize = 0; m_NumItems = 0; + + for(int i = 0; i < m_NumExtendedItemTypes; i++) + { + AddExtendedItemType(i); + } } void CSnapshotBuilder::Init(const CSnapshot *pSnapshot) @@ -648,6 +722,44 @@ int CSnapshotBuilder::Finish(void *pSnapdata) return sizeof(CSnapshot) + KeySize + OffsetSize + m_DataSize; } +static int GetTypeFromIndex(int Index) +{ + return CSnapshot::MAX_TYPE - Index; +} + +void CSnapshotBuilder::AddExtendedItemType(int Index) +{ + dbg_assert(0 <= Index && Index < m_NumExtendedItemTypes, "index out of range"); + int TypeID = m_aExtendedItemTypes[Index]; + CUuid Uuid = g_UuidManager.GetUuid(TypeID); + int *pUuidItem = (int *)NewItem(0, GetTypeFromIndex(Index), sizeof(Uuid)); // NETOBJTYPE_EX + for(int i = 0; i < (int)sizeof(CUuid) / 4; i++) + { + pUuidItem[i] = + (Uuid.m_aData[i * 4 + 0] << 24) | + (Uuid.m_aData[i * 4 + 1] << 16) | + (Uuid.m_aData[i * 4 + 2] << 8) | + (Uuid.m_aData[i * 4 + 3]); + } +} + +int CSnapshotBuilder::GetExtendedItemTypeIndex(int TypeID) +{ + for(int i = 0; i < m_NumExtendedItemTypes; i++) + { + if(m_aExtendedItemTypes[i] == TypeID) + { + return i; + } + } + dbg_assert(m_NumExtendedItemTypes < MAX_EXTENDED_ITEM_TYPES, "too many extended item types"); + int Index = m_NumExtendedItemTypes; + m_aExtendedItemTypes[Index] = TypeID; + m_NumExtendedItemTypes++; + AddExtendedItemType(Index); + return Index; +} + void *CSnapshotBuilder::NewItem(int Type, int ID, int Size) { if(m_DataSize + sizeof(CSnapshot) + sizeof(CSnapshotItem) + Size + (m_NumItems+1) * sizeof(int)*2 >= CSnapshot::MAX_SIZE || @@ -659,6 +771,11 @@ void *CSnapshotBuilder::NewItem(int Type, int ID, int Size) return 0; } + if(Type >= OFFSET_UUID) + { + Type = GetTypeFromIndex(GetExtendedItemTypeIndex(Type)); + } + CSnapshotItem *pObj = (CSnapshotItem *)(m_aData + m_DataSize); mem_zero(pObj, sizeof(CSnapshotItem) + Size); diff --git a/src/engine/shared/snapshot.h b/src/engine/shared/snapshot.h index 26d14c5bc..0251965da 100644 --- a/src/engine/shared/snapshot.h +++ b/src/engine/shared/snapshot.h @@ -37,8 +37,8 @@ class CSnapshot public: enum { - MAX_TYPE = 0x7fff, - MAX_ID = 0xffff, + OFFSET_UUID_TYPE=0x4000, + MAX_TYPE=0x7fff, MAX_PARTS = 64, MAX_SIZE = MAX_PARTS*1024 }; @@ -47,7 +47,9 @@ class CSnapshot int NumItems() const { return m_NumItems; } const CSnapshotItem *GetItem(int Index) const; int GetItemSize(int Index) const; - int GetItemIndex(int Key) const; + int GetItemIndex(int Type, int ID) const; + int GetItemType(int Index) const; + void InvalidateItem(int Index); int Serialize(char *pDstData) const; @@ -127,7 +129,8 @@ class CSnapshotBuilder { enum { - MAX_ITEMS = 1024 + MAX_ITEMS = 1024, + MAX_EXTENDED_ITEM_TYPES = 64, }; char m_aData[CSnapshot::MAX_SIZE]; @@ -136,7 +139,15 @@ class CSnapshotBuilder int m_aOffsets[MAX_ITEMS]; int m_NumItems; + int m_aExtendedItemTypes[MAX_EXTENDED_ITEM_TYPES]; + int m_NumExtendedItemTypes; + + void AddExtendedItemType(int Index); + int GetExtendedItemTypeIndex(int TypeID); + public: + CSnapshotBuilder(); + void Init(); void Init(const CSnapshot *pSnapshot); bool UnserializeSnap(const char *pSrcData, int SrcSize); diff --git a/src/engine/shared/uuid_manager.cpp b/src/engine/shared/uuid_manager.cpp new file mode 100644 index 000000000..90a65a3dd --- /dev/null +++ b/src/engine/shared/uuid_manager.cpp @@ -0,0 +1,143 @@ +#include "uuid_manager.h" + +#include +#include + +#include + +static const CUuid TEEWORLDS_NAMESPACE = {{ + // "e05ddaaa-c4e6-4cfb-b642-5d48e80c0029" + 0xe0, 0x5d, 0xda, 0xaa, 0xc4, 0xe6, 0x4c, 0xfb, + 0xb6, 0x42, 0x5d, 0x48, 0xe8, 0x0c, 0x00, 0x29 +}}; + +CUuid RandomUuid() +{ + CUuid Result; + secure_random_fill(&Result, sizeof(Result)); + + Result.m_aData[6] &= 0x0f; + Result.m_aData[6] |= 0x40; + Result.m_aData[8] &= 0x3f; + Result.m_aData[8] |= 0x80; + + return Result; +} + +CUuid CalculateUuid(const char *pName) +{ + MD5_CTX Md5; + md5_init(&Md5); + + md5_update(&Md5, TEEWORLDS_NAMESPACE.m_aData, sizeof(TEEWORLDS_NAMESPACE.m_aData)); + // Without terminating NUL. + md5_update(&Md5, (const unsigned char *)pName, str_length(pName)); + MD5_DIGEST Digest = md5_finish(&Md5); + + CUuid Result; + for(unsigned i = 0; i < sizeof(Result.m_aData); i++) + { + Result.m_aData[i] = Digest.data[i]; + } + + Result.m_aData[6] &= 0x0f; + Result.m_aData[6] |= 0x30; + Result.m_aData[8] &= 0x3f; + Result.m_aData[8] |= 0x80; + return Result; +} + +void FormatUuid(CUuid Uuid, char *pBuffer, unsigned BufferLength) +{ + unsigned char *p = Uuid.m_aData; + str_format(pBuffer, BufferLength, + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], + p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); +} + +bool CUuid::operator==(const CUuid& Other) +{ + return mem_comp(this, &Other, sizeof(*this)) == 0; +} + +bool CUuid::operator!=(const CUuid& Other) +{ + return !(*this == Other); +} + +static int GetIndex(int ID) +{ + return ID - OFFSET_UUID; +} + +static int GetID(int Index) +{ + return Index + OFFSET_UUID; +} + +void CUuidManager::RegisterName(int ID, const char *pName) +{ + dbg_assert(GetIndex(ID) == m_aNames.size(), "names must be registered with increasing ID"); + CName Name; + Name.m_pName = pName; + Name.m_Uuid = CalculateUuid(pName); + dbg_assert(LookupUuid(Name.m_Uuid) == -1, "duplicate uuid"); + + m_aNames.add(Name); +} + +CUuid CUuidManager::GetUuid(int ID) const +{ + return m_aNames[GetIndex(ID)].m_Uuid; +} + +const char *CUuidManager::GetName(int ID) const +{ + return m_aNames[GetIndex(ID)].m_pName; +} + +int CUuidManager::LookupUuid(CUuid Uuid) const +{ + for(int i = 0; i < m_aNames.size(); i++) + { + if(Uuid == m_aNames[i].m_Uuid) + { + return GetID(i); + } + } + return UUID_UNKNOWN; +} + +int CUuidManager::UnpackUuid(CUnpacker *pUnpacker) const +{ + CUuid Temp; + return UnpackUuid(pUnpacker, &Temp); +} + +int CUuidManager::UnpackUuid(CUnpacker *pUnpacker, CUuid *pOut) const +{ + const CUuid *pUuid = (const CUuid *)pUnpacker->GetRaw(sizeof(*pUuid)); + if(pUuid == NULL) + { + return UUID_INVALID; + } + *pOut = *pUuid; + return LookupUuid(*pUuid); +} + +void CUuidManager::PackUuid(int ID, CPacker *pPacker) const +{ + CUuid Uuid = GetUuid(ID); + pPacker->AddRaw(&Uuid, sizeof(Uuid)); +} + +void CUuidManager::DebugDump() const +{ + for(int i = 0; i < m_aNames.size(); i++) + { + char aBuf[UUID_MAXSTRSIZE]; + FormatUuid(m_aNames[i].m_Uuid, aBuf, sizeof(aBuf)); + dbg_msg("uuid", "%s %s", aBuf, m_aNames[i].m_pName); + } +} diff --git a/src/engine/shared/uuid_manager.h b/src/engine/shared/uuid_manager.h new file mode 100644 index 000000000..c3b4ced7c --- /dev/null +++ b/src/engine/shared/uuid_manager.h @@ -0,0 +1,55 @@ +#ifndef ENGINE_SHARED_UUID_MANAGER_H +#define ENGINE_SHARED_UUID_MANAGER_H + +#include + +enum +{ + UUID_MAXSTRSIZE = 37, // 12345678-0123-5678-0123-567890123456 + + UUID_INVALID=-2, + UUID_UNKNOWN=-1, + + OFFSET_UUID=1<<16, +}; + +struct CUuid +{ + unsigned char m_aData[16]; + + bool operator==(const CUuid &Other); + bool operator!=(const CUuid &Other); +}; + +CUuid RandomUuid(); +CUuid CalculateUuid(const char *pName); +void FormatUuid(CUuid Uuid, char *pBuffer, unsigned BufferLength); + +struct CName +{ + CUuid m_Uuid; + const char *m_pName; +}; + +class CPacker; +class CUnpacker; + +class CUuidManager +{ + array m_aNames; +public: + void RegisterName(int ID, const char *pName); + CUuid GetUuid(int ID) const; + const char *GetName(int ID) const; + int LookupUuid(CUuid Uuid) const; + + int UnpackUuid(CUnpacker *pUnpacker) const; + int UnpackUuid(CUnpacker *pUnpacker, CUuid *pOut) const; + void PackUuid(int ID, CPacker *pPacker) const; + + void DebugDump() const; +}; + +extern CUuidManager g_UuidManager; + +#endif // ENGINE_SHARED_UUID_MANAGER_H diff --git a/src/engine/uuid.h b/src/engine/uuid.h new file mode 100644 index 000000000..591a9a8db --- /dev/null +++ b/src/engine/uuid.h @@ -0,0 +1,4 @@ +#ifndef ENGINE_UUID_H +#define ENGINE_UUID_H +void RegisterGameUuids(CUuidManager *pManager); +#endif // ENGINE_UUID_H diff --git a/src/test/ex.cpp b/src/test/ex.cpp new file mode 100644 index 000000000..fe7b30e8b --- /dev/null +++ b/src/test/ex.cpp @@ -0,0 +1,115 @@ +#include + +#include +#include +#include +#include + +static void TestMessage(bool WantedSys, int WantedID, const void *pData, int Size, CUnpacker *pUnpacker) +{ + pUnpacker->Reset(pData, Size); + + int ID; + bool Sys; + CUuid Uuid; + CMsgPacker Answer(0); + EXPECT_EQ(UnpackMessageID(&ID, &Sys, &Uuid, pUnpacker, &Answer, false), (int)UNPACKMESSAGE_OK); + EXPECT_EQ(ID, WantedID); + EXPECT_EQ(Sys, WantedSys); +} + +TEST(Ex, MessageSys) +{ + CMsgPacker Packer(NETMSG_MYOWNMESSAGE, true); + Packer.AddString("canary", 0); + CUnpacker Unpacker; + TestMessage(true, NETMSG_MYOWNMESSAGE, Packer.Data(), Packer.Size(), &Unpacker); + EXPECT_STREQ(Unpacker.GetString(), "canary"); +} + +TEST(Ex, MessageGame) +{ + CNetMsg_Sv_MyOwnMessage Msg; + Msg.m_Test = 1234567890; + CMsgPacker Packer(NETMSGTYPE_SV_MYOWNMESSAGE); + Msg.Pack(&Packer); + + CUnpacker Unpacker; + CNetObjHandler Handler; + TestMessage(false, NETMSGTYPE_SV_MYOWNMESSAGE, Packer.Data(), Packer.Size(), &Unpacker); + CNetMsg_Sv_MyOwnMessage *pMsg = (CNetMsg_Sv_MyOwnMessage *)Handler.SecureUnpackMsg(NETMSGTYPE_SV_MYOWNMESSAGE, &Unpacker); + ASSERT_NE(pMsg, nullptr); + EXPECT_EQ(pMsg->m_Test, 1234567890); +} + +TEST(Ex, SnapshotObject) +{ + CSnapshotBuilder Builder; + Builder.Init(); + CNetObj_MyOwnObject *pObj = (CNetObj_MyOwnObject *)Builder.NewItem(NETOBJTYPE_MYOWNOBJECT, 0, sizeof(*pObj)); + CNetObj_MyOwnEvent *pEvent = (CNetObj_MyOwnEvent *)Builder.NewItem(NETOBJTYPE_MYOWNEVENT, 1, sizeof(*pEvent)); + ASSERT_NE(pObj, nullptr); + ASSERT_NE(pEvent, nullptr); + pObj->m_Test = 1234567890; + pEvent->m_Test = 1357924680; + + unsigned char aData[CSnapshot::MAX_SIZE]; + Builder.Finish(aData); + CSnapshot *pSnap = (CSnapshot *)aData; + + pSnap->DebugDump(); + + int IndexObj = -1; + int IndexEvent = -1; + for(int i = 0; i < pSnap->NumItems(); i++) + { + int Type = pSnap->GetItemType(i); + if(Type == NETOBJTYPE_MYOWNOBJECT) + { + EXPECT_EQ(IndexObj, -1); + EXPECT_EQ(((const CNetObj_MyOwnObject *)pSnap->GetItem(i)->Data())->m_Test, 1234567890); + IndexObj = i; + } + else if(Type == NETOBJTYPE_MYOWNEVENT) + { + EXPECT_EQ(IndexEvent, -1); + EXPECT_EQ(((const CNetObj_MyOwnEvent *)pSnap->GetItem(i)->Data())->m_Test, 1357924680); + IndexEvent = i; + } + else + { + pSnap->InvalidateItem(i); + } + } + EXPECT_NE(IndexObj, -1); + EXPECT_NE(IndexEvent, -1); + + EXPECT_EQ(pSnap->GetItemIndex(NETOBJTYPE_MYOWNOBJECT, 0), IndexObj); + EXPECT_EQ(pSnap->GetItemIndex(NETOBJTYPE_MYOWNEVENT, 1), IndexEvent); +} + +static void GetWhatIsAnswer(int Uuid, CMsgPacker *pPacker) +{ + CMsgPacker Packer(NETMSG_WHATIS, true); + g_UuidManager.PackUuid(Uuid, &Packer); + CUnpacker Unpacker; + Unpacker.Reset(Packer.Data(), Packer.Size()); + int ID; + bool Sys; + CUuid TmpUuid; + ASSERT_EQ(UnpackMessageID(&ID, &Sys, &TmpUuid, &Unpacker, pPacker, false), (int)UNPACKMESSAGE_ANSWER); + EXPECT_EQ(Sys, true); + EXPECT_EQ(ID, (int)NETMSG_WHATIS); +} + +TEST(Ex, WhatIsKnown) +{ + CMsgPacker Buffer(0); + CUnpacker Unpacker; + GetWhatIsAnswer(NETMSG_MYOWNMESSAGE, &Buffer); + TestMessage(true, NETMSG_ITIS, Buffer.Data(), Buffer.Size(), &Unpacker); + CUuid Uuid; + EXPECT_EQ(g_UuidManager.UnpackUuid(&Unpacker, &Uuid), (int)NETMSG_MYOWNMESSAGE); + EXPECT_STREQ(Unpacker.GetString(CUnpacker::SANITIZE_CC), "system-message-my-own-message@heinrich5991.de"); + EXPECT_FALSE(Unpacker.Error()); +} diff --git a/src/tools/uuid.cpp b/src/tools/uuid.cpp new file mode 100644 index 000000000..4c435fc89 --- /dev/null +++ b/src/tools/uuid.cpp @@ -0,0 +1,14 @@ +#include +int main(int argc, char **argv) +{ + dbg_logger_stdout(); + if(argc != 2) + { + dbg_msg("usage", "uuid "); + return -1; + } + CUuid Uuid = CalculateUuid(argv[1]); + char aBuf[UUID_MAXSTRSIZE]; + FormatUuid(Uuid, aBuf, sizeof(aBuf)); + dbg_msg("uuid", "%s", aBuf); +}