2202: Send DDNet version early in the connection process r=Learath2 a=heinrich5991

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.

Co-authored-by: heinrich5991 <heinrich5991@gmail.com>
This commit is contained in:
bors[bot] 2020-05-27 17:49:31 +00:00 committed by GitHub
commit 92fc95d742
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
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 *Version() = 0;
virtual const char *NetVersion() = 0;
virtual int DDNetVersion() = 0;
virtual const char *DDNetVersionStr() = 0;
virtual void OnDummyDisconnect() = 0;
virtual void Echo(const char *pString) = 0;

View file

@ -401,6 +401,12 @@ int CClient::SendMsg(CMsgPacker *pMsg, int Flags)
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);
Msg.AddString(GameClient()->NetVersion(), 128);
Msg.AddString(m_Password, 128);
@ -673,6 +679,7 @@ void CClient::Connect(const char *pAddress, const char *pPassword)
Disconnect();
m_ConnectionID = RandomUuid();
str_copy(m_aServerAddressStr, pAddress, sizeof(m_aServerAddressStr));
str_format(aBuf, sizeof(aBuf), "connecting to '%s'", m_aServerAddressStr);
@ -2965,6 +2972,12 @@ void CClient::Run()
m_DummySendConnInfo = false;
// 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);
MsgInfo.AddString(GameClient()->NetVersion(), 128);
MsgInfo.AddString(m_Password, 128);

View file

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

View file

@ -28,7 +28,10 @@ public:
{
const char *m_pName;
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; }
@ -43,6 +46,7 @@ public:
virtual bool ClientIngame(int ClientID) = 0;
virtual bool ClientAuthed(int ClientID) = 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 RestrictRconOutput(int ClientID) = 0;
@ -112,7 +116,7 @@ public:
{
CClientInfo Info;
GetClientInfo(Client, &Info);
if (Info.m_ClientVersion >= VERSION_DDNET_OLD)
if (Info.m_DDNetVersion >= VERSION_DDNET_OLD)
return true;
int *pMap = GetIdMap(Client);
bool Found = false;
@ -132,7 +136,7 @@ public:
{
CClientInfo Info;
GetClientInfo(Client, &Info);
if (Info.m_ClientVersion >= VERSION_DDNET_OLD)
if (Info.m_DDNetVersion >= VERSION_DDNET_OLD)
return true;
Target = clamp(Target, 0, VANILLA_MAX_CLIENTS-1);
int *pMap = GetIdMap(Client);
@ -234,8 +238,6 @@ public:
// DDRace
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 void OnClientEngineJoin(int ClientID) = 0;

View file

@ -256,6 +256,9 @@ void CServer::CClient::Reset()
m_Score = 0;
m_NextMapChunk = 0;
m_Flags = 0;
m_DDNetVersion = VERSION_NONE;
m_GotDDNetVersionPacket = false;
m_DDNetVersionSettled = false;
}
CServer::CServer()
@ -516,12 +519,34 @@ int CServer::GetClientInfo(int ClientID, CClientInfo *pInfo)
{
pInfo->m_pName = m_aClients[ClientID].m_aName;
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 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)
{
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)
{
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_DnsblState = CClient::DNSBL_STATE_NONE;
pThis->m_aClients[ClientID].m_aName[0] = 0;
@ -1195,9 +1220,28 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
if(Sys)
{
// 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);
if(!str_utf8_check(pVersion))
@ -1351,11 +1395,13 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
}
if(Unpacker.Error() == 0 && !str_comp(pCmd, "crashmeplx"))
{
int version = GameServer()->GetClientVersion(ClientID);
if (GameServer()->PlayerExists(ClientID) && version < VERSION_DDNET_OLD)
GameServer()->SetClientVersion(ClientID, VERSION_DDNET_OLD);
} else
if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Error() == 0 && m_aClients[ClientID].m_Authed)
int Version = m_aClients[ClientID].m_DDNetVersion;
if (GameServer()->PlayerExists(ClientID) && Version < VERSION_DDNET_OLD)
{
m_aClients[ClientID].m_DDNetVersion = VERSION_DDNET_OLD;
}
}
else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Error() == 0 && m_aClients[ClientID].m_Authed)
{
if (GameServer()->PlayerExists(ClientID))
{
@ -2340,7 +2386,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",
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);
}
else

View file

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

View file

@ -99,6 +99,7 @@ enum
enum
{
VERSION_NONE = -1,
VERSION_VANILLA = 0,
VERSION_DDRACE = 1,
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_MAP_DETAILS, "map-details@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.
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_LOGIN, "teehistorian-auth-login@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::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); }
void CGameClient::OnConsoleInit()
@ -287,6 +289,15 @@ void CGameClient::OnInit()
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
g_Localization.Load(g_Config.m_ClLanguagefile, Storage(), Console());

View file

@ -108,6 +108,8 @@ class CGameClient : public IGameClient
int m_CheckInfo[2];
char m_aDDNetVersionStr[64];
static void ConTeam(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 *Version();
virtual const char *NetVersion();
virtual int DDNetVersion();
virtual const char *DDNetVersionStr();
// actions
// TODO: move these

View file

@ -1413,7 +1413,7 @@ void CGameContext::ConSetTimerType(IConsole::IResult *pResult, void *pUserData)
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;
else
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "timer", "gametimer is not supported by your client.");
@ -1422,7 +1422,7 @@ void CGameContext::ConSetTimerType(IConsole::IResult *pResult, void *pUserData)
pPlayer->m_TimerType = CPlayer::TIMERTYPE_BROADCAST;
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;
else
{
@ -1434,7 +1434,7 @@ void CGameContext::ConSetTimerType(IConsole::IResult *pResult, void *pUserData)
pPlayer->m_TimerType = CPlayer::TIMERTYPE_NONE;
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)
pPlayer->m_TimerType++;

View file

@ -1306,7 +1306,7 @@ void CCharacter::HandleBroadcast()
CPlayerData *pData = GameServer()->Score()->PlayerData(m_pPlayer->GetCID());
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)
{
char aBroadcast[128];
@ -1452,7 +1452,7 @@ void CCharacter::HandleTiles(int Index)
m_CpActive = cp;
m_CpCurrent[cp] = m_Time;
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());
CNetMsg_Sv_DDRaceTime Msg;
Msg.m_Time = (int)m_Time;
@ -1477,7 +1477,7 @@ void CCharacter::HandleTiles(int Index)
m_CpActive = cpf;
m_CpCurrent[cpf] = m_Time;
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());
CNetMsg_Sv_DDRaceTime Msg;
Msg.m_Time = (int)m_Time;

View file

@ -326,7 +326,7 @@ void CProjectile::Snap(int SnappingClient)
CNetObj_Projectile *pProj = static_cast<CNetObj_Projectile *>(Server()->SnapNewItem(NETOBJTYPE_PROJECTILE, m_ID, sizeof(CNetObj_Projectile)));
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);
else
FillInfo(pProj);

View file

@ -517,7 +517,7 @@ void CGameContext::SendVoteSet(int ClientID)
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);
No = float(No) * VANILLA_MAX_CLIENTS / float(Total);
@ -592,15 +592,19 @@ void CGameContext::SendTuningParams(int ClientID, int Zone)
else
pParams = (int *)&(m_aTuningList[Zone]);
unsigned int last = sizeof(m_Tuning)/sizeof(int);
if (m_apPlayers[ClientID] && m_apPlayers[ClientID]->m_ClientVersion < VERSION_DDNET_EXTRATUNES)
last = 33;
else if (m_apPlayers[ClientID] && m_apPlayers[ClientID]->m_ClientVersion < VERSION_DDNET_HOOKDURATION_TUNE)
last = 37;
else if (m_apPlayers[ClientID] && m_apPlayers[ClientID]->m_ClientVersion < VERSION_DDNET_FIREDELAY_TUNE)
last = 38;
unsigned int Last = sizeof(m_Tuning)/sizeof(int);
if(m_apPlayers[ClientID])
{
int ClientVersion = m_apPlayers[ClientID]->GetClientVersion();
if(ClientVersion < VERSION_DDNET_EXTRATUNES)
Last = 33;
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())
{
@ -1095,6 +1099,13 @@ void CGameContext::OnClientEnter(int ClientID)
if(!Server()->ClientPrevIngame(ClientID))
{
IServer::CClientInfo Info;
Server()->GetClientInfo(ClientID, &Info);
if(Info.m_GotDDNetVersion)
{
OnClientDDNetVersionKnown(ClientID);
}
char aBuf[512];
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);
@ -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 *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)
{
int Version = pUnpacker->GetInt();
if (pUnpacker->Error())
IServer::CClientInfo Info;
Server()->GetClientInfo(ClientID, &Info);
if(Info.m_GotDDNetVersion)
{
if (pPlayer->m_ClientVersion < VERSION_DDRACE)
pPlayer->m_ClientVersion = VERSION_DDRACE;
return;
}
else if(pPlayer->m_ClientVersion < Version)
pPlayer->m_ClientVersion = Version;
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++)
int DDNetVersion = pUnpacker->GetInt();
if(pUnpacker->Error() || DDNetVersion < 0)
{
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 (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");
DDNetVersion = VERSION_DDRACE;
}
Server()->SetClientDDNetVersion(ClientID, DDNetVersion);
OnClientDDNetVersionKnown(ClientID);
}
else if (MsgID == NETMSGTYPE_CL_SHOWOTHERS)
{
@ -3436,18 +3473,18 @@ void CGameContext::Whisper(int ClientID, char *pStr)
void CGameContext::WhisperID(int ClientID, int VictimID, char *pMessage)
{
if (!CheckClientID2(ClientID))
if(!CheckClientID2(ClientID))
return;
if (!CheckClientID2(VictimID))
if(!CheckClientID2(VictimID))
return;
if (m_apPlayers[ClientID])
if(m_apPlayers[ClientID])
m_apPlayers[ClientID]->m_LastWhisperTo = VictimID;
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;
Msg.m_Team = CHAT_WHISPER_SEND;
@ -3464,7 +3501,7 @@ void CGameContext::WhisperID(int ClientID, int VictimID, char *pMessage)
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;
Msg2.m_Team = CHAT_WHISPER_RECV;
@ -3550,18 +3587,9 @@ void CGameContext::List(int ClientID, const char *pFilter)
int CGameContext::GetClientVersion(int ClientID)
{
return m_apPlayers[ClientID]
? m_apPlayers[ClientID]->m_ClientVersion
: 0;
}
void CGameContext::SetClientVersion(int ClientID, int Version)
{
if(!m_apPlayers[ClientID])
{
return;
}
m_apPlayers[ClientID]->m_ClientVersion = Version;
IServer::CClientInfo Info = {0};
Server()->GetClientInfo(ClientID, &Info);
return Info.m_DDNetVersion;
}
bool CGameContext::PlayerModerating()

View file

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

View file

@ -516,7 +516,7 @@ void IGameController::Snap(int SnappingClient)
CPlayer *pPlayer = SnappingClient > -1 ? GameServer()->m_apPlayers[SnappingClient] : 0;
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())
&& 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 &&
!ch->CanCollide(i) &&
(!GameServer()->m_apPlayers[i] ||
GameServer()->m_apPlayers[i]->m_ClientVersion == VERSION_VANILLA ||
(GameServer()->m_apPlayers[i]->m_ClientVersion >= VERSION_DDRACE &&
GameServer()->m_apPlayers[i]->GetClientVersion() == VERSION_VANILLA ||
(GameServer()->m_apPlayers[i]->GetClientVersion() >= VERSION_DDRACE &&
!GameServer()->m_apPlayers[i]->m_ShowOthers
)
)

View file

@ -103,7 +103,6 @@ void CPlayer::Reset()
GameServer()->Score()->PlayerData(m_ClientID)->Reset();
m_ClientVersion = VERSION_VANILLA;
m_ShowOthers = g_Config.m_SvShowOthersDefault;
m_ShowAll = g_Config.m_SvShowAllDefault;
m_SpecTeam = 0;
@ -297,12 +296,13 @@ void CPlayer::Snap(int SnappingClient)
if(!pPlayerInfo)
return;
int ClientVersion = GetClientVersion();
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_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;
// send 0 if times of others are not shown
@ -338,10 +338,7 @@ void CPlayer::Snap(int SnappingClient)
void CPlayer::FakeSnap()
{
// This is problematic when it's sent before we know whether it's a non-64-player-client
// Then we can't spectate players at the start
if(m_ClientVersion >= VERSION_DDNET_OLD)
if(GetClientVersion() >= VERSION_DDNET_OLD)
return;
int FakeID = VANILLA_MAX_CLIENTS - 1;
@ -422,7 +419,7 @@ void CPlayer::OnPredictedInput(CNetObj_PlayerInput *NewInput)
// Magic number when we can hope that client has successfully identified itself
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);
}
}
@ -482,6 +479,11 @@ void CPlayer::OnPredictedEarlyInput(CNetObj_PlayerInput *NewInput)
m_pCharacter->OnDirectInput(NewInput);
}
int CPlayer::GetClientVersion() const
{
return m_pGameServer->GetClientVersion(m_ClientID);
}
CCharacter *CPlayer::GetCharacter()
{
if(m_pCharacter && m_pCharacter->IsAlive())

View file

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

View file

@ -424,7 +424,7 @@ void CGameTeams::SendTeamsState(int ClientID)
if (g_Config.m_SvTeam == 3)
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;
CMsgPacker Msg(NETMSGTYPE_SV_TEAMSSTATE);
@ -626,7 +626,7 @@ void CGameTeams::OnFinish(CPlayer* Player, float Time, const char *pTimestamp)
NeedToSendNewRecord = true;
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())
{
@ -639,19 +639,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++)
{
if (GameServer()->m_apPlayers[i]
&& GameServer()->m_apPlayers[i]->m_ClientVersion >= VERSION_DDRACE)
&& GameServer()->m_apPlayers[i]->GetClientVersion() >= VERSION_DDRACE)
{
GameServer()->SendRecord(i);
}
}
}
if (Player->m_ClientVersion >= VERSION_DDRACE)
if (Player->GetClientVersion() >= VERSION_DDRACE)
{
CNetMsg_Sv_DDRaceTime Msg;
Msg.m_Time = (int)(Time * 100.0f);

View file

@ -490,6 +490,40 @@ void CTeeHistorian::EndTick()
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)
{
CPacker Buffer;

View file

@ -64,6 +64,9 @@ public:
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 RecordAuthLogin(int ClientID, int Level, const char *pAuthName);
void RecordAuthLogout(int ClientID);

View file

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

View file

@ -320,6 +320,43 @@ TEST_F(TeeHistorian, ExtraMessage)
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)
{
const unsigned char EXPECTED[] = {