Send DDNet version early in the connection process

This gets rid of the problem that we don't know whether we should send
full snapshots to clients because they haven't told us about them being
DDNet yet.
This commit is contained in:
heinrich5991 2020-05-22 17:58:41 +02:00
parent 3623f5e4cd
commit 0d7872c79e
25 changed files with 319 additions and 123 deletions

View file

@ -240,6 +240,8 @@ public:
virtual const char *GetItemName(int Type) = 0; virtual const char *GetItemName(int Type) = 0;
virtual const char *Version() = 0; virtual const char *Version() = 0;
virtual const char *NetVersion() = 0; virtual const char *NetVersion() = 0;
virtual int DDNetVersion() = 0;
virtual const char *DDNetVersionStr() = 0;
virtual void OnDummyDisconnect() = 0; virtual void OnDummyDisconnect() = 0;
virtual void Echo(const char *pString) = 0; virtual void Echo(const char *pString) = 0;

View file

@ -401,6 +401,12 @@ int CClient::SendMsg(CMsgPacker *pMsg, int Flags)
void CClient::SendInfo() void CClient::SendInfo()
{ {
CMsgPacker MsgVer(NETMSG_CLIENTVER, true);
MsgVer.AddRaw(&m_ConnectionID, sizeof(m_ConnectionID));
MsgVer.AddInt(GameClient()->DDNetVersion());
MsgVer.AddString(GameClient()->DDNetVersionStr(), 0);
SendMsg(&MsgVer, MSGFLAG_VITAL);
CMsgPacker Msg(NETMSG_INFO, true); CMsgPacker Msg(NETMSG_INFO, true);
Msg.AddString(GameClient()->NetVersion(), 128); Msg.AddString(GameClient()->NetVersion(), 128);
Msg.AddString(m_Password, 128); Msg.AddString(m_Password, 128);
@ -673,6 +679,7 @@ void CClient::Connect(const char *pAddress, const char *pPassword)
Disconnect(); Disconnect();
m_ConnectionID = RandomUuid();
str_copy(m_aServerAddressStr, pAddress, sizeof(m_aServerAddressStr)); str_copy(m_aServerAddressStr, pAddress, sizeof(m_aServerAddressStr));
str_format(aBuf, sizeof(aBuf), "connecting to '%s'", m_aServerAddressStr); str_format(aBuf, sizeof(aBuf), "connecting to '%s'", m_aServerAddressStr);
@ -2965,6 +2972,12 @@ void CClient::Run()
m_DummySendConnInfo = false; m_DummySendConnInfo = false;
// send client info // send client info
CMsgPacker MsgVer(NETMSG_CLIENTVER, true);
MsgVer.AddRaw(&m_ConnectionID, sizeof(m_ConnectionID));
MsgVer.AddInt(GameClient()->DDNetVersion());
MsgVer.AddString(GameClient()->DDNetVersionStr(), 0);
SendMsg(&MsgVer, MSGFLAG_VITAL);
CMsgPacker MsgInfo(NETMSG_INFO, true); CMsgPacker MsgInfo(NETMSG_INFO, true);
MsgInfo.AddString(GameClient()->NetVersion(), 128); MsgInfo.AddString(GameClient()->NetVersion(), 128);
MsgInfo.AddString(m_Password, 128); MsgInfo.AddString(m_Password, 128);

View file

@ -103,6 +103,8 @@ class CClient : public IClient, public CDemoPlayer::IListener
char m_aServerAddressStr[256]; char m_aServerAddressStr[256];
CUuid m_ConnectionID;
unsigned m_SnapshotParts[2]; unsigned m_SnapshotParts[2];
int64 m_LocalStartTime; int64 m_LocalStartTime;

View file

@ -28,7 +28,10 @@ public:
{ {
const char *m_pName; const char *m_pName;
int m_Latency; int m_Latency;
int m_ClientVersion; bool m_GotDDNetVersion;
int m_DDNetVersion;
const char *m_pDDNetVersionStr;
const CUuid *m_pConnectionID;
}; };
int Tick() const { return m_CurrentGameTick; } int Tick() const { return m_CurrentGameTick; }
@ -43,6 +46,7 @@ public:
virtual bool ClientIngame(int ClientID) = 0; virtual bool ClientIngame(int ClientID) = 0;
virtual bool ClientAuthed(int ClientID) = 0; virtual bool ClientAuthed(int ClientID) = 0;
virtual int GetClientInfo(int ClientID, CClientInfo *pInfo) = 0; virtual int GetClientInfo(int ClientID, CClientInfo *pInfo) = 0;
virtual void SetClientDDNetVersion(int ClientID, int DDNetVersion) = 0;
virtual void GetClientAddr(int ClientID, char *pAddrStr, int Size) = 0; virtual void GetClientAddr(int ClientID, char *pAddrStr, int Size) = 0;
virtual void RestrictRconOutput(int ClientID) = 0; virtual void RestrictRconOutput(int ClientID) = 0;
@ -112,7 +116,7 @@ public:
{ {
CClientInfo Info; CClientInfo Info;
GetClientInfo(Client, &Info); GetClientInfo(Client, &Info);
if (Info.m_ClientVersion >= VERSION_DDNET_OLD) if (Info.m_DDNetVersion >= VERSION_DDNET_OLD)
return true; return true;
int *pMap = GetIdMap(Client); int *pMap = GetIdMap(Client);
bool Found = false; bool Found = false;
@ -132,7 +136,7 @@ public:
{ {
CClientInfo Info; CClientInfo Info;
GetClientInfo(Client, &Info); GetClientInfo(Client, &Info);
if (Info.m_ClientVersion >= VERSION_DDNET_OLD) if (Info.m_DDNetVersion >= VERSION_DDNET_OLD)
return true; return true;
Target = clamp(Target, 0, VANILLA_MAX_CLIENTS-1); Target = clamp(Target, 0, VANILLA_MAX_CLIENTS-1);
int *pMap = GetIdMap(Client); int *pMap = GetIdMap(Client);
@ -234,8 +238,6 @@ public:
// DDRace // DDRace
virtual void OnSetAuthed(int ClientID, int Level) = 0; virtual void OnSetAuthed(int ClientID, int Level) = 0;
virtual int GetClientVersion(int ClientID) = 0;
virtual void SetClientVersion(int ClientID, int Version) = 0;
virtual bool PlayerExists(int ClientID) = 0; virtual bool PlayerExists(int ClientID) = 0;
virtual void OnClientEngineJoin(int ClientID) = 0; virtual void OnClientEngineJoin(int ClientID) = 0;

View file

@ -256,6 +256,9 @@ void CServer::CClient::Reset()
m_Score = 0; m_Score = 0;
m_NextMapChunk = 0; m_NextMapChunk = 0;
m_Flags = 0; m_Flags = 0;
m_DDNetVersion = VERSION_NONE;
m_GotDDNetVersionPacket = false;
m_DDNetVersionSettled = false;
} }
CServer::CServer() CServer::CServer()
@ -516,12 +519,34 @@ int CServer::GetClientInfo(int ClientID, CClientInfo *pInfo)
{ {
pInfo->m_pName = m_aClients[ClientID].m_aName; pInfo->m_pName = m_aClients[ClientID].m_aName;
pInfo->m_Latency = m_aClients[ClientID].m_Latency; pInfo->m_Latency = m_aClients[ClientID].m_Latency;
pInfo->m_ClientVersion = GameServer()->GetClientVersion(ClientID); pInfo->m_GotDDNetVersion = m_aClients[ClientID].m_DDNetVersionSettled;
pInfo->m_DDNetVersion = m_aClients[ClientID].m_DDNetVersion >= 0 ? m_aClients[ClientID].m_DDNetVersion : VERSION_VANILLA;
if(m_aClients[ClientID].m_GotDDNetVersionPacket)
{
pInfo->m_pConnectionID = &m_aClients[ClientID].m_ConnectionID;
pInfo->m_pDDNetVersionStr = m_aClients[ClientID].m_aDDNetVersionStr;
}
else
{
pInfo->m_pConnectionID = 0;
pInfo->m_pDDNetVersionStr = 0;
}
return 1; return 1;
} }
return 0; return 0;
} }
void CServer::SetClientDDNetVersion(int ClientID, int DDNetVersion)
{
dbg_assert(ClientID >= 0 && ClientID < MAX_CLIENTS, "client_id is not valid");
if(m_aClients[ClientID].m_State == CClient::STATE_INGAME)
{
m_aClients[ClientID].m_DDNetVersion = DDNetVersion;
m_aClients[ClientID].m_DDNetVersionSettled = true;
}
}
void CServer::GetClientAddr(int ClientID, char *pAddrStr, int Size) void CServer::GetClientAddr(int ClientID, char *pAddrStr, int Size)
{ {
if(ClientID >= 0 && ClientID < MAX_CLIENTS && m_aClients[ClientID].m_State == CClient::STATE_INGAME) if(ClientID >= 0 && ClientID < MAX_CLIENTS && m_aClients[ClientID].m_State == CClient::STATE_INGAME)
@ -873,7 +898,7 @@ int CServer::NewClientNoAuthCallback(int ClientID, void *pUser)
int CServer::NewClientCallback(int ClientID, void *pUser) int CServer::NewClientCallback(int ClientID, void *pUser)
{ {
CServer *pThis = (CServer *)pUser; CServer *pThis = (CServer *)pUser;
pThis->m_aClients[ClientID].m_State = CClient::STATE_AUTH; pThis->m_aClients[ClientID].m_State = CClient::STATE_PREAUTH;
pThis->m_aClients[ClientID].m_SupportsMapSha256 = false; pThis->m_aClients[ClientID].m_SupportsMapSha256 = false;
pThis->m_aClients[ClientID].m_DnsblState = CClient::DNSBL_STATE_NONE; pThis->m_aClients[ClientID].m_DnsblState = CClient::DNSBL_STATE_NONE;
pThis->m_aClients[ClientID].m_aName[0] = 0; pThis->m_aClients[ClientID].m_aName[0] = 0;
@ -1195,9 +1220,28 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
if(Sys) if(Sys)
{ {
// system message // system message
if(Msg == NETMSG_INFO) if(Msg == NETMSG_CLIENTVER)
{ {
if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && m_aClients[ClientID].m_State == CClient::STATE_AUTH) if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && m_aClients[ClientID].m_State == CClient::STATE_PREAUTH)
{
CUuid *pConnectionID = (CUuid *)Unpacker.GetRaw(sizeof(*pConnectionID));
int DDNetVersion = Unpacker.GetInt();
const char *pDDNetVersionStr = Unpacker.GetString(CUnpacker::SANITIZE_CC);
if(Unpacker.Error() || !str_utf8_check(pDDNetVersionStr) || DDNetVersion < 0)
{
return;
}
m_aClients[ClientID].m_ConnectionID = *pConnectionID;
m_aClients[ClientID].m_DDNetVersion = DDNetVersion;
str_copy(m_aClients[ClientID].m_aDDNetVersionStr, pDDNetVersionStr, sizeof(m_aClients[ClientID].m_aDDNetVersionStr));
m_aClients[ClientID].m_DDNetVersionSettled = true;
m_aClients[ClientID].m_GotDDNetVersionPacket = true;
m_aClients[ClientID].m_State = CClient::STATE_AUTH;
}
}
else if(Msg == NETMSG_INFO)
{
if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && (m_aClients[ClientID].m_State == CClient::STATE_PREAUTH || m_aClients[ClientID].m_State == CClient::STATE_AUTH))
{ {
const char *pVersion = Unpacker.GetString(CUnpacker::SANITIZE_CC); const char *pVersion = Unpacker.GetString(CUnpacker::SANITIZE_CC);
if(!str_utf8_check(pVersion)) if(!str_utf8_check(pVersion))
@ -1351,11 +1395,13 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
} }
if(Unpacker.Error() == 0 && !str_comp(pCmd, "crashmeplx")) if(Unpacker.Error() == 0 && !str_comp(pCmd, "crashmeplx"))
{ {
int version = GameServer()->GetClientVersion(ClientID); int Version = m_aClients[ClientID].m_DDNetVersion;
if (GameServer()->PlayerExists(ClientID) && version < VERSION_DDNET_OLD) if (GameServer()->PlayerExists(ClientID) && Version < VERSION_DDNET_OLD)
GameServer()->SetClientVersion(ClientID, VERSION_DDNET_OLD); {
} else m_aClients[ClientID].m_DDNetVersion = VERSION_DDNET_OLD;
if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Error() == 0 && m_aClients[ClientID].m_Authed) }
}
else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Error() == 0 && m_aClients[ClientID].m_Authed)
{ {
if (GameServer()->PlayerExists(ClientID)) if (GameServer()->PlayerExists(ClientID))
{ {
@ -2332,7 +2378,7 @@ void CServer::ConStatus(IConsole::IResult *pResult, void *pUser)
} }
str_format(aBuf, sizeof(aBuf), "id=%d addr=<{%s}> name='%s' client=%d secure=%s flags=%d%s%s", str_format(aBuf, sizeof(aBuf), "id=%d addr=<{%s}> name='%s' client=%d secure=%s flags=%d%s%s",
i, aAddrStr, pThis->m_aClients[i].m_aName, pThis->GameServer()->GetClientVersion(i), i, aAddrStr, pThis->m_aClients[i].m_aName, pThis->m_aClients[i].m_DDNetVersion,
pThis->m_NetServer.HasSecurityToken(i) ? "yes" : "no", pThis->m_aClients[i].m_Flags, aDnsblStr, aAuthStr); pThis->m_NetServer.HasSecurityToken(i) ? "yes" : "no", pThis->m_aClients[i].m_Flags, aDnsblStr, aAuthStr);
} }
else else

View file

@ -125,6 +125,7 @@ public:
enum enum
{ {
STATE_EMPTY = 0, STATE_EMPTY = 0,
STATE_PREAUTH,
STATE_AUTH, STATE_AUTH,
STATE_CONNECTING, STATE_CONNECTING,
STATE_READY, STATE_READY,
@ -182,6 +183,11 @@ public:
// DDRace // DDRace
NETADDR m_Addr; NETADDR m_Addr;
bool m_GotDDNetVersionPacket;
bool m_DDNetVersionSettled;
int m_DDNetVersion;
char m_aDDNetVersionStr[64];
CUuid m_ConnectionID;
// DNSBL // DNSBL
int m_DnsblState; int m_DnsblState;
@ -261,6 +267,7 @@ public:
const char *GetAuthName(int ClientID); const char *GetAuthName(int ClientID);
void GetMapInfo(char *pMapName, int MapNameSize, int *pMapSize, SHA256_DIGEST *pMapSha256, int *pMapCrc); void GetMapInfo(char *pMapName, int MapNameSize, int *pMapSize, SHA256_DIGEST *pMapSha256, int *pMapCrc);
int GetClientInfo(int ClientID, CClientInfo *pInfo); int GetClientInfo(int ClientID, CClientInfo *pInfo);
void SetClientDDNetVersion(int ClientID, int DDNetVersion);
void GetClientAddr(int ClientID, char *pAddrStr, int Size); void GetClientAddr(int ClientID, char *pAddrStr, int Size);
const char *ClientName(int ClientID); const char *ClientName(int ClientID);
const char *ClientClan(int ClientID); const char *ClientClan(int ClientID);

View file

@ -99,6 +99,7 @@ enum
enum enum
{ {
VERSION_NONE = -1,
VERSION_VANILLA = 0, VERSION_VANILLA = 0,
VERSION_DDRACE = 1, VERSION_DDRACE = 1,
VERSION_DDNET_OLD = 2, VERSION_DDNET_OLD = 2,

View file

@ -26,3 +26,4 @@ UUID(NETMSG_IDONTKNOW, "i-dont-know@ddnet.tw")
UUID(NETMSG_RCONTYPE, "rcon-type@ddnet.tw") UUID(NETMSG_RCONTYPE, "rcon-type@ddnet.tw")
UUID(NETMSG_MAP_DETAILS, "map-details@ddnet.tw") UUID(NETMSG_MAP_DETAILS, "map-details@ddnet.tw")
UUID(NETMSG_CAPABILITIES, "capabilities@ddnet.tw") UUID(NETMSG_CAPABILITIES, "capabilities@ddnet.tw")
UUID(NETMSG_CLIENTVER, "clientver@ddnet.tw")

View file

@ -1,6 +1,8 @@
// This file can be included several times. // This file can be included several times.
UUID(TEEHISTORIAN_TEST, "teehistorian-test@ddnet.tw") UUID(TEEHISTORIAN_TEST, "teehistorian-test@ddnet.tw")
UUID(TEEHISTORIAN_DDNETVER_OLD, "teehistorian-ddnetver-old@ddnet.tw")
UUID(TEEHISTORIAN_DDNETVER, "teehistorian-ddnetver@ddnet.tw")
UUID(TEEHISTORIAN_AUTH_INIT, "teehistorian-auth-init@ddnet.tw") UUID(TEEHISTORIAN_AUTH_INIT, "teehistorian-auth-init@ddnet.tw")
UUID(TEEHISTORIAN_AUTH_LOGIN, "teehistorian-auth-login@ddnet.tw") UUID(TEEHISTORIAN_AUTH_LOGIN, "teehistorian-auth-login@ddnet.tw")
UUID(TEEHISTORIAN_AUTH_LOGOUT, "teehistorian-auth-logout@ddnet.tw") UUID(TEEHISTORIAN_AUTH_LOGOUT, "teehistorian-auth-logout@ddnet.tw")

View file

@ -112,6 +112,8 @@ void CGameClient::CStack::Add(class CComponent *pComponent) { m_paComponents[m_N
const char *CGameClient::Version() { return GAME_VERSION; } const char *CGameClient::Version() { return GAME_VERSION; }
const char *CGameClient::NetVersion() { return GAME_NETVERSION; } const char *CGameClient::NetVersion() { return GAME_NETVERSION; }
int CGameClient::DDNetVersion() { return CLIENT_VERSIONNR; }
const char *CGameClient::DDNetVersionStr() { return m_aDDNetVersionStr; }
const char *CGameClient::GetItemName(int Type) { return m_NetObjHandler.GetObjName(Type); } const char *CGameClient::GetItemName(int Type) { return m_NetObjHandler.GetObjName(Type); }
void CGameClient::OnConsoleInit() void CGameClient::OnConsoleInit()
@ -287,6 +289,15 @@ void CGameClient::OnInit()
int64 Start = time_get(); int64 Start = time_get();
if(GIT_SHORTREV_HASH)
{
str_format(m_aDDNetVersionStr, sizeof(m_aDDNetVersionStr), "%s %s (%s)", GAME_NAME, GAME_RELEASE_VERSION, GIT_SHORTREV_HASH);
}
else
{
str_format(m_aDDNetVersionStr, sizeof(m_aDDNetVersionStr), "%s %s", GAME_NAME, GAME_RELEASE_VERSION);
}
// set the language // set the language
g_Localization.Load(g_Config.m_ClLanguagefile, Storage(), Console()); g_Localization.Load(g_Config.m_ClLanguagefile, Storage(), Console());

View file

@ -108,6 +108,8 @@ class CGameClient : public IGameClient
int m_CheckInfo[2]; int m_CheckInfo[2];
char m_aDDNetVersionStr[64];
static void ConTeam(IConsole::IResult *pResult, void *pUserData); static void ConTeam(IConsole::IResult *pResult, void *pUserData);
static void ConKill(IConsole::IResult *pResult, void *pUserData); static void ConKill(IConsole::IResult *pResult, void *pUserData);
@ -360,6 +362,8 @@ public:
virtual const char *GetItemName(int Type); virtual const char *GetItemName(int Type);
virtual const char *Version(); virtual const char *Version();
virtual const char *NetVersion(); virtual const char *NetVersion();
virtual int DDNetVersion();
virtual const char *DDNetVersionStr();
// actions // actions
// TODO: move these // TODO: move these

View file

@ -1310,7 +1310,7 @@ void CGameContext::ConSetTimerType(IConsole::IResult *pResult, void *pUserData)
if(str_comp_nocase(pResult->GetString(0), "gametimer") == 0) if(str_comp_nocase(pResult->GetString(0), "gametimer") == 0)
{ {
if(pPlayer->m_ClientVersion >= VERSION_DDNET_GAMETICK) if(pPlayer->GetClientVersion() >= VERSION_DDNET_GAMETICK)
pPlayer->m_TimerType = CPlayer::TIMERTYPE_GAMETIMER; pPlayer->m_TimerType = CPlayer::TIMERTYPE_GAMETIMER;
else else
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "timer", "gametimer is not supported by your client."); pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "timer", "gametimer is not supported by your client.");
@ -1319,7 +1319,7 @@ void CGameContext::ConSetTimerType(IConsole::IResult *pResult, void *pUserData)
pPlayer->m_TimerType = CPlayer::TIMERTYPE_BROADCAST; pPlayer->m_TimerType = CPlayer::TIMERTYPE_BROADCAST;
else if(str_comp_nocase(pResult->GetString(0), "both") == 0) else if(str_comp_nocase(pResult->GetString(0), "both") == 0)
{ {
if(pPlayer->m_ClientVersion >= VERSION_DDNET_GAMETICK) if(pPlayer->GetClientVersion() >= VERSION_DDNET_GAMETICK)
pPlayer->m_TimerType = CPlayer::TIMERTYPE_GAMETIMER_AND_BROADCAST; pPlayer->m_TimerType = CPlayer::TIMERTYPE_GAMETIMER_AND_BROADCAST;
else else
{ {
@ -1331,7 +1331,7 @@ void CGameContext::ConSetTimerType(IConsole::IResult *pResult, void *pUserData)
pPlayer->m_TimerType = CPlayer::TIMERTYPE_NONE; pPlayer->m_TimerType = CPlayer::TIMERTYPE_NONE;
else if(str_comp_nocase(pResult->GetString(0), "cycle") == 0) else if(str_comp_nocase(pResult->GetString(0), "cycle") == 0)
{ {
if(pPlayer->m_ClientVersion >= VERSION_DDNET_GAMETICK) if(pPlayer->GetClientVersion() >= VERSION_DDNET_GAMETICK)
{ {
if(pPlayer->m_TimerType < CPlayer::TIMERTYPE_NONE) if(pPlayer->m_TimerType < CPlayer::TIMERTYPE_NONE)
pPlayer->m_TimerType++; pPlayer->m_TimerType++;

View file

@ -1306,7 +1306,7 @@ void CCharacter::HandleBroadcast()
CPlayerData *pData = GameServer()->Score()->PlayerData(m_pPlayer->GetCID()); CPlayerData *pData = GameServer()->Score()->PlayerData(m_pPlayer->GetCID());
if(m_DDRaceState == DDRACE_STARTED && m_CpLastBroadcast != m_CpActive && if(m_DDRaceState == DDRACE_STARTED && m_CpLastBroadcast != m_CpActive &&
m_CpActive > -1 && m_CpTick > Server()->Tick() && m_pPlayer->m_ClientVersion == VERSION_VANILLA && m_CpActive > -1 && m_CpTick > Server()->Tick() && m_pPlayer->GetClientVersion() == VERSION_VANILLA &&
pData->m_BestTime && pData->m_aBestCpTime[m_CpActive] != 0) pData->m_BestTime && pData->m_aBestCpTime[m_CpActive] != 0)
{ {
char aBroadcast[128]; char aBroadcast[128];
@ -1452,7 +1452,7 @@ void CCharacter::HandleTiles(int Index)
m_CpActive = cp; m_CpActive = cp;
m_CpCurrent[cp] = m_Time; m_CpCurrent[cp] = m_Time;
m_CpTick = Server()->Tick() + Server()->TickSpeed() * 2; m_CpTick = Server()->Tick() + Server()->TickSpeed() * 2;
if(m_pPlayer->m_ClientVersion >= VERSION_DDRACE) { if(m_pPlayer->GetClientVersion() >= VERSION_DDRACE) {
CPlayerData *pData = GameServer()->Score()->PlayerData(m_pPlayer->GetCID()); CPlayerData *pData = GameServer()->Score()->PlayerData(m_pPlayer->GetCID());
CNetMsg_Sv_DDRaceTime Msg; CNetMsg_Sv_DDRaceTime Msg;
Msg.m_Time = (int)m_Time; Msg.m_Time = (int)m_Time;
@ -1477,7 +1477,7 @@ void CCharacter::HandleTiles(int Index)
m_CpActive = cpf; m_CpActive = cpf;
m_CpCurrent[cpf] = m_Time; m_CpCurrent[cpf] = m_Time;
m_CpTick = Server()->Tick() + Server()->TickSpeed()*2; m_CpTick = Server()->Tick() + Server()->TickSpeed()*2;
if(m_pPlayer->m_ClientVersion >= VERSION_DDRACE) { if(m_pPlayer->GetClientVersion() >= VERSION_DDRACE) {
CPlayerData *pData = GameServer()->Score()->PlayerData(m_pPlayer->GetCID()); CPlayerData *pData = GameServer()->Score()->PlayerData(m_pPlayer->GetCID());
CNetMsg_Sv_DDRaceTime Msg; CNetMsg_Sv_DDRaceTime Msg;
Msg.m_Time = (int)m_Time; Msg.m_Time = (int)m_Time;

View file

@ -325,7 +325,7 @@ void CProjectile::Snap(int SnappingClient)
CNetObj_Projectile *pProj = static_cast<CNetObj_Projectile *>(Server()->SnapNewItem(NETOBJTYPE_PROJECTILE, m_ID, sizeof(CNetObj_Projectile))); CNetObj_Projectile *pProj = static_cast<CNetObj_Projectile *>(Server()->SnapNewItem(NETOBJTYPE_PROJECTILE, m_ID, sizeof(CNetObj_Projectile)));
if(pProj) if(pProj)
{ {
if(SnappingClient > -1 && GameServer()->m_apPlayers[SnappingClient] && GameServer()->m_apPlayers[SnappingClient]->m_ClientVersion >= VERSION_DDNET_ANTIPING_PROJECTILE) if(SnappingClient > -1 && GameServer()->m_apPlayers[SnappingClient] && GameServer()->m_apPlayers[SnappingClient]->GetClientVersion() >= VERSION_DDNET_ANTIPING_PROJECTILE)
FillExtraInfo(pProj); FillExtraInfo(pProj);
else else
FillInfo(pProj); FillInfo(pProj);

View file

@ -517,7 +517,7 @@ void CGameContext::SendVoteSet(int ClientID)
void CGameContext::SendVoteStatus(int ClientID, int Total, int Yes, int No) void CGameContext::SendVoteStatus(int ClientID, int Total, int Yes, int No)
{ {
if (Total > VANILLA_MAX_CLIENTS && m_apPlayers[ClientID] && m_apPlayers[ClientID]->m_ClientVersion <= VERSION_DDRACE) if (Total > VANILLA_MAX_CLIENTS && m_apPlayers[ClientID] && m_apPlayers[ClientID]->GetClientVersion() <= VERSION_DDRACE)
{ {
Yes = float(Yes) * VANILLA_MAX_CLIENTS / float(Total); Yes = float(Yes) * VANILLA_MAX_CLIENTS / float(Total);
No = float(No) * VANILLA_MAX_CLIENTS / float(Total); No = float(No) * VANILLA_MAX_CLIENTS / float(Total);
@ -592,15 +592,19 @@ void CGameContext::SendTuningParams(int ClientID, int Zone)
else else
pParams = (int *)&(m_aTuningList[Zone]); pParams = (int *)&(m_aTuningList[Zone]);
unsigned int last = sizeof(m_Tuning)/sizeof(int); unsigned int Last = sizeof(m_Tuning)/sizeof(int);
if (m_apPlayers[ClientID] && m_apPlayers[ClientID]->m_ClientVersion < VERSION_DDNET_EXTRATUNES) if(m_apPlayers[ClientID])
last = 33; {
else if (m_apPlayers[ClientID] && m_apPlayers[ClientID]->m_ClientVersion < VERSION_DDNET_HOOKDURATION_TUNE) int ClientVersion = m_apPlayers[ClientID]->GetClientVersion();
last = 37; if(ClientVersion < VERSION_DDNET_EXTRATUNES)
else if (m_apPlayers[ClientID] && m_apPlayers[ClientID]->m_ClientVersion < VERSION_DDNET_FIREDELAY_TUNE) Last = 33;
last = 38; else if(ClientVersion < VERSION_DDNET_HOOKDURATION_TUNE)
Last = 37;
else if(ClientVersion < VERSION_DDNET_FIREDELAY_TUNE)
Last = 38;
}
for(unsigned i = 0; i < last; i++) for(unsigned i = 0; i < Last; i++)
{ {
if (m_apPlayers[ClientID] && m_apPlayers[ClientID]->GetCharacter()) if (m_apPlayers[ClientID] && m_apPlayers[ClientID]->GetCharacter())
{ {
@ -1095,6 +1099,13 @@ void CGameContext::OnClientEnter(int ClientID)
if(!Server()->ClientPrevIngame(ClientID)) if(!Server()->ClientPrevIngame(ClientID))
{ {
IServer::CClientInfo Info;
Server()->GetClientInfo(ClientID, &Info);
if(Info.m_GotDDNetVersion)
{
OnClientDDNetVersionKnown(ClientID);
}
char aBuf[512]; char aBuf[512];
str_format(aBuf, sizeof(aBuf), "'%s' entered and joined the %s", Server()->ClientName(ClientID), m_pController->GetTeamName(m_apPlayers[ClientID]->GetTeam())); str_format(aBuf, sizeof(aBuf), "'%s' entered and joined the %s", Server()->ClientName(ClientID), m_pController->GetTeamName(m_apPlayers[ClientID]->GetTeam()));
SendChat(-1, CGameContext::CHAT_ALL, aBuf); SendChat(-1, CGameContext::CHAT_ALL, aBuf);
@ -1218,6 +1229,79 @@ void CGameContext::OnClientEngineDrop(int ClientID, const char *pReason)
} }
} }
void CGameContext::OnClientDDNetVersionKnown(int ClientID)
{
IServer::CClientInfo Info;
Server()->GetClientInfo(ClientID, &Info);
int ClientVersion = Info.m_DDNetVersion;
dbg_msg("ddnet", "cid=%d version=%d", ClientID, ClientVersion);
if(m_TeeHistorianActive)
{
if(Info.m_pConnectionID && Info.m_pDDNetVersionStr)
{
m_TeeHistorian.RecordDDNetVersion(ClientID, *Info.m_pConnectionID, ClientVersion, Info.m_pDDNetVersionStr);
}
else
{
m_TeeHistorian.RecordDDNetVersionOld(ClientID, ClientVersion);
}
}
CPlayer *pPlayer = m_apPlayers[ClientID];
if(ClientVersion >= VERSION_DDNET_GAMETICK)
pPlayer->m_TimerType = g_Config.m_SvDefaultTimerType;
//first update his teams state
((CGameControllerDDRace *)m_pController)->m_Teams.SendTeamsState(ClientID);
//second give him records
SendRecord(ClientID);
//third give him others current time for table score
if(g_Config.m_SvHideScore)
{
return;
}
for(int i = 0; i < MAX_CLIENTS; i++)
{
if(m_apPlayers[i] && Score()->PlayerData(i)->m_CurrentTime > 0)
{
CNetMsg_Sv_PlayerTime Msg;
Msg.m_Time = Score()->PlayerData(i)->m_CurrentTime * 100;
Msg.m_ClientID = i;
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, ClientID);
//also send its time to others
}
}
//also send its time to others
if(Score()->PlayerData(ClientID)->m_CurrentTime > 0)
{
//TODO: make function for this fucking steps
CNetMsg_Sv_PlayerTime Msg;
Msg.m_Time = Score()->PlayerData(ClientID)->m_CurrentTime * 100;
Msg.m_ClientID = ClientID;
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, -1);
}
//and give him correct tunings
if (ClientVersion >= VERSION_DDNET_EXTRATUNES)
SendTuningParams(ClientID, pPlayer->m_TuneZone);
//tell old clients to update
if (ClientVersion < VERSION_DDNET_UPDATER_FIXED && g_Config.m_SvClientSuggestionOld[0] != '\0')
SendBroadcast(g_Config.m_SvClientSuggestionOld, ClientID);
//tell known bot clients that they're botting and we know it
if (((ClientVersion >= 15 && ClientVersion < 100) || ClientVersion == 502) && g_Config.m_SvClientSuggestionBot[0] != '\0')
SendBroadcast(g_Config.m_SvClientSuggestionBot, ClientID);
//autoban known bot versions
if(g_Config.m_SvBannedVersions[0] != '\0' && IsVersionBanned(ClientVersion))
{
Server()->Kick(ClientID, "unsupported client");
}
}
void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
{ {
void *pRawMsg = m_NetObjHandler.SecureUnpackMsg(MsgID, pUnpacker); void *pRawMsg = m_NetObjHandler.SecureUnpackMsg(MsgID, pUnpacker);
@ -1752,66 +1836,19 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
} }
else if (MsgID == NETMSGTYPE_CL_ISDDNET) else if (MsgID == NETMSGTYPE_CL_ISDDNET)
{ {
int Version = pUnpacker->GetInt(); IServer::CClientInfo Info;
Server()->GetClientInfo(ClientID, &Info);
if (pUnpacker->Error()) if(Info.m_GotDDNetVersion)
{ {
if (pPlayer->m_ClientVersion < VERSION_DDRACE) return;
pPlayer->m_ClientVersion = VERSION_DDRACE;
} }
else if(pPlayer->m_ClientVersion < Version) int DDNetVersion = pUnpacker->GetInt();
pPlayer->m_ClientVersion = Version; if(pUnpacker->Error() || DDNetVersion < 0)
if(pPlayer->m_ClientVersion >= VERSION_DDNET_GAMETICK)
pPlayer->m_TimerType = g_Config.m_SvDefaultTimerType;
dbg_msg("ddnet", "%d using Custom Client %d", ClientID, pPlayer->m_ClientVersion);
//first update his teams state
((CGameControllerDDRace*)m_pController)->m_Teams.SendTeamsState(ClientID);
//second give him records
SendRecord(ClientID);
//third give him others current time for table score
if(g_Config.m_SvHideScore) return;
for(int i = 0; i < MAX_CLIENTS; i++)
{ {
if(m_apPlayers[i] && Score()->PlayerData(i)->m_CurrentTime > 0) DDNetVersion = VERSION_DDRACE;
{
CNetMsg_Sv_PlayerTime Msg;
Msg.m_Time = Score()->PlayerData(i)->m_CurrentTime * 100;
Msg.m_ClientID = i;
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, ClientID);
//also send its time to others
}
}
//also send its time to others
if(Score()->PlayerData(ClientID)->m_CurrentTime > 0)
{
//TODO: make function for this fucking steps
CNetMsg_Sv_PlayerTime Msg;
Msg.m_Time = Score()->PlayerData(ClientID)->m_CurrentTime * 100;
Msg.m_ClientID = ClientID;
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, -1);
}
//and give him correct tunings
if (Version >= VERSION_DDNET_EXTRATUNES)
SendTuningParams(ClientID, pPlayer->m_TuneZone);
//tell old clients to update
if (Version < VERSION_DDNET_UPDATER_FIXED && g_Config.m_SvClientSuggestionOld[0] != '\0')
SendBroadcast(g_Config.m_SvClientSuggestionOld, ClientID);
//tell known bot clients that they're botting and we know it
if (((Version >= 15 && Version < 100) || Version == 502) && g_Config.m_SvClientSuggestionBot[0] != '\0')
SendBroadcast(g_Config.m_SvClientSuggestionBot, ClientID);
//autoban known bot versions
if(g_Config.m_SvBannedVersions[0] != '\0' && IsVersionBanned(Version))
{
Server()->Kick(ClientID, "unsupported client");
} }
Server()->SetClientDDNetVersion(ClientID, DDNetVersion);
OnClientDDNetVersionKnown(ClientID);
} }
else if (MsgID == NETMSGTYPE_CL_SHOWOTHERS) else if (MsgID == NETMSGTYPE_CL_SHOWOTHERS)
{ {
@ -3430,18 +3467,18 @@ void CGameContext::Whisper(int ClientID, char *pStr)
void CGameContext::WhisperID(int ClientID, int VictimID, char *pMessage) void CGameContext::WhisperID(int ClientID, int VictimID, char *pMessage)
{ {
if (!CheckClientID2(ClientID)) if(!CheckClientID2(ClientID))
return; return;
if (!CheckClientID2(VictimID)) if(!CheckClientID2(VictimID))
return; return;
if (m_apPlayers[ClientID]) if(m_apPlayers[ClientID])
m_apPlayers[ClientID]->m_LastWhisperTo = VictimID; m_apPlayers[ClientID]->m_LastWhisperTo = VictimID;
char aBuf[256]; char aBuf[256];
if (m_apPlayers[ClientID] && m_apPlayers[ClientID]->m_ClientVersion >= VERSION_DDNET_WHISPER) if(GetClientVersion(ClientID) >= VERSION_DDNET_WHISPER)
{ {
CNetMsg_Sv_Chat Msg; CNetMsg_Sv_Chat Msg;
Msg.m_Team = CHAT_WHISPER_SEND; Msg.m_Team = CHAT_WHISPER_SEND;
@ -3458,7 +3495,7 @@ void CGameContext::WhisperID(int ClientID, int VictimID, char *pMessage)
SendChatTarget(ClientID, aBuf); SendChatTarget(ClientID, aBuf);
} }
if (m_apPlayers[VictimID] && m_apPlayers[VictimID]->m_ClientVersion >= VERSION_DDNET_WHISPER) if(GetClientVersion(VictimID) >= VERSION_DDNET_WHISPER)
{ {
CNetMsg_Sv_Chat Msg2; CNetMsg_Sv_Chat Msg2;
Msg2.m_Team = CHAT_WHISPER_RECV; Msg2.m_Team = CHAT_WHISPER_RECV;
@ -3544,18 +3581,9 @@ void CGameContext::List(int ClientID, const char *pFilter)
int CGameContext::GetClientVersion(int ClientID) int CGameContext::GetClientVersion(int ClientID)
{ {
return m_apPlayers[ClientID] IServer::CClientInfo Info = {0};
? m_apPlayers[ClientID]->m_ClientVersion Server()->GetClientInfo(ClientID, &Info);
: 0; return Info.m_DDNetVersion;
}
void CGameContext::SetClientVersion(int ClientID, int Version)
{
if(!m_apPlayers[ClientID])
{
return;
}
m_apPlayers[ClientID]->m_ClientVersion = Version;
} }
bool CGameContext::PlayerModerating() bool CGameContext::PlayerModerating()

View file

@ -250,6 +250,7 @@ public:
virtual const char *NetVersion(); virtual const char *NetVersion();
// DDRace // DDRace
void OnClientDDNetVersionKnown(int ClientID);
virtual void FillAntibot(CAntibotRoundData *pData); virtual void FillAntibot(CAntibotRoundData *pData);
int ProcessSpamProtection(int ClientID); int ProcessSpamProtection(int ClientID);
int GetDDRaceTeam(int ClientID); int GetDDRaceTeam(int ClientID);
@ -257,7 +258,6 @@ public:
int64 m_NonEmptySince; int64 m_NonEmptySince;
int64 m_LastMapVote; int64 m_LastMapVote;
int GetClientVersion(int ClientID); int GetClientVersion(int ClientID);
void SetClientVersion(int ClientID, int Version);
bool PlayerExists(int ClientID) { return m_apPlayers[ClientID]; }; bool PlayerExists(int ClientID) { return m_apPlayers[ClientID]; };
// Returns true if someone is actively moderating. // Returns true if someone is actively moderating.
bool PlayerModerating(); bool PlayerModerating();

View file

@ -516,7 +516,7 @@ void IGameController::Snap(int SnappingClient)
CPlayer *pPlayer = SnappingClient > -1 ? GameServer()->m_apPlayers[SnappingClient] : 0; CPlayer *pPlayer = SnappingClient > -1 ? GameServer()->m_apPlayers[SnappingClient] : 0;
CPlayer *pPlayer2; CPlayer *pPlayer2;
if(pPlayer && (pPlayer->m_TimerType == CPlayer::TIMERTYPE_GAMETIMER || pPlayer->m_TimerType == CPlayer::TIMERTYPE_GAMETIMER_AND_BROADCAST) && pPlayer->m_ClientVersion >= VERSION_DDNET_GAMETICK) if(pPlayer && (pPlayer->m_TimerType == CPlayer::TIMERTYPE_GAMETIMER || pPlayer->m_TimerType == CPlayer::TIMERTYPE_GAMETIMER_AND_BROADCAST) && pPlayer->GetClientVersion() >= VERSION_DDNET_GAMETICK)
{ {
if((pPlayer->GetTeam() == -1 || pPlayer->IsPaused()) if((pPlayer->GetTeam() == -1 || pPlayer->IsPaused())
&& pPlayer->m_SpectatorID != SPEC_FREEVIEW && pPlayer->m_SpectatorID != SPEC_FREEVIEW

View file

@ -186,8 +186,8 @@ void CGameWorld::UpdatePlayerMaps()
!GameServer()->m_apPlayers[i]->IsPaused() && GameServer()->m_apPlayers[i]->GetTeam() != -1 && !GameServer()->m_apPlayers[i]->IsPaused() && GameServer()->m_apPlayers[i]->GetTeam() != -1 &&
!ch->CanCollide(i) && !ch->CanCollide(i) &&
(!GameServer()->m_apPlayers[i] || (!GameServer()->m_apPlayers[i] ||
GameServer()->m_apPlayers[i]->m_ClientVersion == VERSION_VANILLA || GameServer()->m_apPlayers[i]->GetClientVersion() == VERSION_VANILLA ||
(GameServer()->m_apPlayers[i]->m_ClientVersion >= VERSION_DDRACE && (GameServer()->m_apPlayers[i]->GetClientVersion() >= VERSION_DDRACE &&
!GameServer()->m_apPlayers[i]->m_ShowOthers !GameServer()->m_apPlayers[i]->m_ShowOthers
) )
) )

View file

@ -103,7 +103,6 @@ void CPlayer::Reset()
GameServer()->Score()->PlayerData(m_ClientID)->Reset(); GameServer()->Score()->PlayerData(m_ClientID)->Reset();
m_ClientVersion = VERSION_VANILLA;
m_ShowOthers = g_Config.m_SvShowOthersDefault; m_ShowOthers = g_Config.m_SvShowOthersDefault;
m_ShowAll = g_Config.m_SvShowAllDefault; m_ShowAll = g_Config.m_SvShowAllDefault;
m_SpecTeam = 0; m_SpecTeam = 0;
@ -296,12 +295,13 @@ void CPlayer::Snap(int SnappingClient)
if(!pPlayerInfo) if(!pPlayerInfo)
return; return;
int ClientVersion = GetClientVersion();
pPlayerInfo->m_Latency = SnappingClient == -1 ? m_Latency.m_Min : GameServer()->m_apPlayers[SnappingClient]->m_aActLatency[m_ClientID]; pPlayerInfo->m_Latency = SnappingClient == -1 ? m_Latency.m_Min : GameServer()->m_apPlayers[SnappingClient]->m_aActLatency[m_ClientID];
pPlayerInfo->m_Local = (int)(m_ClientID == SnappingClient && (m_Paused != PAUSE_PAUSED || m_ClientVersion >= VERSION_DDNET_OLD)); pPlayerInfo->m_Local = (int)(m_ClientID == SnappingClient && (m_Paused != PAUSE_PAUSED || ClientVersion >= VERSION_DDNET_OLD));
pPlayerInfo->m_ClientID = id; pPlayerInfo->m_ClientID = id;
pPlayerInfo->m_Team = (m_ClientVersion < VERSION_DDNET_OLD || m_Paused != PAUSE_PAUSED || m_ClientID != SnappingClient) && m_Paused < PAUSE_SPEC ? m_Team : TEAM_SPECTATORS; pPlayerInfo->m_Team = (ClientVersion < VERSION_DDNET_OLD || m_Paused != PAUSE_PAUSED || m_ClientID != SnappingClient) && m_Paused < PAUSE_SPEC ? m_Team : TEAM_SPECTATORS;
if(m_ClientID == SnappingClient && m_Paused == PAUSE_PAUSED && m_ClientVersion < VERSION_DDNET_OLD) if(m_ClientID == SnappingClient && m_Paused == PAUSE_PAUSED && ClientVersion < VERSION_DDNET_OLD)
pPlayerInfo->m_Team = TEAM_SPECTATORS; pPlayerInfo->m_Team = TEAM_SPECTATORS;
// send 0 if times of others are not shown // send 0 if times of others are not shown
@ -337,10 +337,7 @@ void CPlayer::Snap(int SnappingClient)
void CPlayer::FakeSnap() void CPlayer::FakeSnap()
{ {
// This is problematic when it's sent before we know whether it's a non-64-player-client if(GetClientVersion() >= VERSION_DDNET_OLD)
// Then we can't spectate players at the start
if(m_ClientVersion >= VERSION_DDNET_OLD)
return; return;
int FakeID = VANILLA_MAX_CLIENTS - 1; int FakeID = VANILLA_MAX_CLIENTS - 1;
@ -421,7 +418,7 @@ void CPlayer::OnPredictedInput(CNetObj_PlayerInput *NewInput)
// Magic number when we can hope that client has successfully identified itself // Magic number when we can hope that client has successfully identified itself
if(m_NumInputs == 20) if(m_NumInputs == 20)
{ {
if(g_Config.m_SvClientSuggestion[0] != '\0' && m_ClientVersion <= VERSION_DDNET_OLD) if(g_Config.m_SvClientSuggestion[0] != '\0' && GetClientVersion() <= VERSION_DDNET_OLD)
GameServer()->SendBroadcast(g_Config.m_SvClientSuggestion, m_ClientID); GameServer()->SendBroadcast(g_Config.m_SvClientSuggestion, m_ClientID);
} }
} }
@ -481,6 +478,11 @@ void CPlayer::OnPredictedEarlyInput(CNetObj_PlayerInput *NewInput)
m_pCharacter->OnDirectInput(NewInput); m_pCharacter->OnDirectInput(NewInput);
} }
int CPlayer::GetClientVersion() const
{
return m_pGameServer->GetClientVersion(m_ClientID);
}
CCharacter *CPlayer::GetCharacter() CCharacter *CPlayer::GetCharacter()
{ {
if(m_pCharacter && m_pCharacter->IsAlive()) if(m_pCharacter && m_pCharacter->IsAlive())

View file

@ -26,6 +26,7 @@ public:
void SetTeam(int Team, bool DoChatMsg=true); void SetTeam(int Team, bool DoChatMsg=true);
int GetTeam() const { return m_Team; }; int GetTeam() const { return m_Team; };
int GetCID() const { return m_ClientID; }; int GetCID() const { return m_ClientID; };
int GetClientVersion() const;
void Tick(); void Tick();
void PostTick(); void PostTick();
@ -162,7 +163,6 @@ public:
bool IsPlaying(); bool IsPlaying();
int64 m_Last_KickVote; int64 m_Last_KickVote;
int64 m_Last_Team; int64 m_Last_Team;
int m_ClientVersion;
bool m_ShowOthers; bool m_ShowOthers;
bool m_ShowAll; bool m_ShowAll;
bool m_SpecTeam; bool m_SpecTeam;

View file

@ -385,7 +385,7 @@ void CGameTeams::SendTeamsState(int ClientID)
if (g_Config.m_SvTeam == 3) if (g_Config.m_SvTeam == 3)
return; return;
if (!m_pGameContext->m_apPlayers[ClientID] || m_pGameContext->m_apPlayers[ClientID]->m_ClientVersion <= VERSION_DDRACE) if (!m_pGameContext->m_apPlayers[ClientID] || m_pGameContext->m_apPlayers[ClientID]->GetClientVersion() <= VERSION_DDRACE)
return; return;
CMsgPacker Msg(NETMSGTYPE_SV_TEAMSSTATE); CMsgPacker Msg(NETMSGTYPE_SV_TEAMSSTATE);
@ -587,7 +587,7 @@ void CGameTeams::OnFinish(CPlayer* Player, float Time, const char *pTimestamp)
NeedToSendNewRecord = true; NeedToSendNewRecord = true;
for (int i = 0; i < MAX_CLIENTS; i++) for (int i = 0; i < MAX_CLIENTS; i++)
{ {
if (GetPlayer(i) && GetPlayer(i)->m_ClientVersion >= VERSION_DDRACE) if (GetPlayer(i) && GetPlayer(i)->GetClientVersion() >= VERSION_DDRACE)
{ {
if (!g_Config.m_SvHideScore || i == Player->GetCID()) if (!g_Config.m_SvHideScore || i == Player->GetCID())
{ {
@ -600,19 +600,19 @@ void CGameTeams::OnFinish(CPlayer* Player, float Time, const char *pTimestamp)
} }
} }
if (NeedToSendNewRecord && Player->m_ClientVersion >= VERSION_DDRACE) if (NeedToSendNewRecord && Player->GetClientVersion() >= VERSION_DDRACE)
{ {
for (int i = 0; i < MAX_CLIENTS; i++) for (int i = 0; i < MAX_CLIENTS; i++)
{ {
if (GameServer()->m_apPlayers[i] if (GameServer()->m_apPlayers[i]
&& GameServer()->m_apPlayers[i]->m_ClientVersion >= VERSION_DDRACE) && GameServer()->m_apPlayers[i]->GetClientVersion() >= VERSION_DDRACE)
{ {
GameServer()->SendRecord(i); GameServer()->SendRecord(i);
} }
} }
} }
if (Player->m_ClientVersion >= VERSION_DDRACE) if (Player->GetClientVersion() >= VERSION_DDRACE)
{ {
CNetMsg_Sv_DDRaceTime Msg; CNetMsg_Sv_DDRaceTime Msg;
Msg.m_Time = (int)(Time * 100.0f); Msg.m_Time = (int)(Time * 100.0f);

View file

@ -488,6 +488,40 @@ void CTeeHistorian::EndTick()
m_State = STATE_BEFORE_TICK; m_State = STATE_BEFORE_TICK;
} }
void CTeeHistorian::RecordDDNetVersionOld(int ClientID, int DDNetVersion)
{
CPacker Buffer;
Buffer.Reset();
Buffer.AddInt(ClientID);
Buffer.AddInt(DDNetVersion);
if(m_Debug)
{
dbg_msg("teehistorian", "ddnetver_old cid=%d ddnet_version=%d", ClientID, DDNetVersion);
}
WriteExtra(UUID_TEEHISTORIAN_DDNETVER_OLD, Buffer.Data(), Buffer.Size());
}
void CTeeHistorian::RecordDDNetVersion(int ClientID, CUuid ConnectionID, int DDNetVersion, const char *pDDNetVersionStr)
{
CPacker Buffer;
Buffer.Reset();
Buffer.AddInt(ClientID);
Buffer.AddRaw(&ConnectionID, sizeof(ConnectionID));
Buffer.AddInt(DDNetVersion);
Buffer.AddString(pDDNetVersionStr, 0);
if(m_Debug)
{
char aConnnectionID[UUID_MAXSTRSIZE];
FormatUuid(ConnectionID, aConnnectionID, sizeof(aConnnectionID));
dbg_msg("teehistorian", "ddnetver cid=%d connection_id=%s ddnet_version=%d ddnet_version_str=%s", ClientID, aConnnectionID, DDNetVersion, pDDNetVersionStr);
}
WriteExtra(UUID_TEEHISTORIAN_DDNETVER, Buffer.Data(), Buffer.Size());
}
void CTeeHistorian::RecordAuthInitial(int ClientID, int Level, const char *pAuthName) void CTeeHistorian::RecordAuthInitial(int ClientID, int Level, const char *pAuthName)
{ {
CPacker Buffer; CPacker Buffer;

View file

@ -63,6 +63,9 @@ public:
void EndTick(); void EndTick();
void RecordDDNetVersionOld(int ClientID, int DDNetVersion);
void RecordDDNetVersion(int ClientID, CUuid ConnectionID, int DDNetVersion, const char *pDDNetVersionStr);
void RecordAuthInitial(int ClientID, int Level, const char *pAuthName); void RecordAuthInitial(int ClientID, int Level, const char *pAuthName);
void RecordAuthLogin(int ClientID, int Level, const char *pAuthName); void RecordAuthLogin(int ClientID, int Level, const char *pAuthName);
void RecordAuthLogout(int ClientID); void RecordAuthLogout(int ClientID);

View file

@ -4,6 +4,7 @@
#define GAME_VERSION_H #define GAME_VERSION_H
#define GAME_VERSION "0.6.4, 13.1" #define GAME_VERSION "0.6.4, 13.1"
#define GAME_NETVERSION "0.6 626fce9a778df4d4" #define GAME_NETVERSION "0.6 626fce9a778df4d4"
#define GAME_NAME "DDNet"
#define GAME_RELEASE_VERSION "13.1" #define GAME_RELEASE_VERSION "13.1"
#define CLIENT_VERSIONNR 13010 #define CLIENT_VERSIONNR 13010
extern const char *GIT_SHORTREV_HASH; extern const char *GIT_SHORTREV_HASH;

View file

@ -319,6 +319,43 @@ TEST_F(TeeHistorian, ExtraMessage)
Expect(EXPECTED, sizeof(EXPECTED)); Expect(EXPECTED, sizeof(EXPECTED));
} }
TEST_F(TeeHistorian, DDNetVersion)
{
const unsigned char EXPECTED[] = {
// EX uuid=60daba5c-52c4-3aeb-b8ba-b2953fb55a17 data_len=50
0x4a,
0x13, 0x97, 0xb6, 0x3e, 0xee, 0x4e, 0x39, 0x19,
0xb8, 0x6a, 0xb0, 0x58, 0x88, 0x7f, 0xca, 0xf5,
0x32,
// (DDNETVER) cid=0 connection_id=fb13a576-d35f-4893-b815-eedc6d98015b
// ddnet_version=13010 ddnet_version_str=DDNet 13.1 (3623f5e4cd184556)
0x00,
0xfb, 0x13, 0xa5, 0x76, 0xd3, 0x5f, 0x48, 0x93,
0xb8, 0x15, 0xee, 0xdc, 0x6d, 0x98, 0x01, 0x5b,
0x92, 0xcb, 0x01, 'D', 'D', 'N', 'e', 't',
' ', '1', '3', '.', '1', ' ', '(', '3',
'6', '2', '3', 'f', '5', 'e', '4', 'c',
'd', '1', '8', '4', '5', '5', '6', ')',
0x00,
// EX uuid=1397b63e-ee4e-3919-b86a-b058887fcaf5 data_len=4
0x4a,
0x41, 0xb4, 0x95, 0x41, 0xf2, 0x6f, 0x32, 0x5d,
0x87, 0x15, 0x9b, 0xaf, 0x4b, 0x54, 0x4e, 0xf9,
0x04,
// (DDNETVER_OLD) cid=1 ddnet_version=13010
0x01, 0x92, 0xcb, 0x01,
0x40, // FINISH
};
CUuid ConnectionID = {
0xfb, 0x13, 0xa5, 0x76, 0xd3, 0x5f, 0x48, 0x93,
0xb8, 0x15, 0xee, 0xdc, 0x6d, 0x98, 0x01, 0x5b,
};
m_TH.RecordDDNetVersion(0, ConnectionID, 13010, "DDNet 13.1 (3623f5e4cd184556)");
m_TH.RecordDDNetVersionOld(1, 13010);
Finish();
Expect(EXPECTED, sizeof(EXPECTED));
}
TEST_F(TeeHistorian, Auth) TEST_F(TeeHistorian, Auth)
{ {
const unsigned char EXPECTED[] = { const unsigned char EXPECTED[] = {