diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index ad733d49f..34f6f3dbc 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -542,7 +542,8 @@ int CServer::NewClientCallback(int ClientId, void *pUser) pThis->m_aClients[ClientId].m_aClan[0] = 0; pThis->m_aClients[ClientId].m_Authed = 0; pThis->m_aClients[ClientId].m_PwTries = 0; // init pw tries - memset(&pThis->m_aClients[ClientId].m_Addr, 0, sizeof(NETADDR)); // init that too + memset(&pThis->m_aClients[ClientId].m_Addr, 0, sizeof(NETADDR)); // init that too + pThis->m_aClients[ClientId].m_CommandTriesTimer= 0; pThis->m_aClients[ClientId].m_CmdTries = 0; //Floff init cmd tries pThis->m_aClients[ClientId].m_Resistent = 0; pThis->m_aClients[ClientId].Reset(); @@ -562,7 +563,8 @@ int CServer::DelClientCallback(int ClientId, void *pUser) pThis->m_aClients[ClientId].m_aClan[0] = 0; pThis->m_aClients[ClientId].m_Authed = 0; pThis->m_aClients[ClientId].m_PwTries = 0; // init pw tries - memset(&pThis->m_aClients[ClientId].m_Addr, 0, sizeof(NETADDR)); // init that too + memset(&pThis->m_aClients[ClientId].m_Addr, 0, sizeof(NETADDR)); // init that too + pThis->m_aClients[ClientId].m_CommandTriesTimer= 0; pThis->m_aClients[ClientId].m_CmdTries = 0; //Floff init cmd tries pThis->m_aClients[ClientId].m_Resistent = 0; pThis->m_aClients[ClientId].m_Snapshots.PurgeAll(); @@ -702,10 +704,52 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) SendMap(ClientId); } } - else - { + else { + if(m_aClients[ClientId].m_Authed == 0 && Msg != NETMSG_INPUT && Msg != NETMSG_REQUEST_MAP_DATA) + { + if(time_get() > m_aClients[ClientId].m_CommandTriesTimer + time_freq()) + { + m_aClients[ClientId].m_CmdTries = 0; + m_aClients[ClientId].m_CommandTriesTimer = time_get(); + } + m_aClients[ClientId].m_CmdTries++; + //dbg_msg("server","client_counter: %d", clients[cid].command_tries); + + if(m_aClients[ClientId].m_CmdTries > g_Config.m_SvNetmsgLimit && g_Config.m_SvNetmsgLimit != 0) + { + dbg_msg("server", "client sending too many messages to server (DDoS?), banned. cid=%x ip=%d.%d.%d.%d", + ClientId, + m_aClients[ClientId].m_Addr.ip[0], m_aClients[ClientId].m_Addr.ip[1], m_aClients[ClientId].m_Addr.ip[2], m_aClients[ClientId].m_Addr.ip[3] + ); + + BanAdd(m_aClients[ClientId].m_Addr, g_Config.m_SvNetmsgBanTime, "exceeding netmsg_limit, Bye"); // bye + return; + } + } + } if(Sys) { + if(Msg != NETMSG_INPUT && Msg != NETMSG_REQUEST_MAP_DATA) + { + m_aClients[ClientId].m_CmdTries++; + if(time_get() < m_aClients[ClientId].m_LastCommand + time_freq()/* * 1*/) + { + if(m_aClients[ClientId].m_CmdTries > g_Config.m_SvRconCmdTries) + { + dbg_msg("server", "client trying to flood the server (%d tries), ban. cid=%x ip=%d.%d.%d.%d", m_aClients[ClientId].m_CmdTries, + ClientId, + m_aClients[ClientId].m_Addr.ip[0], m_aClients[ClientId].m_Addr.ip[1], m_aClients[ClientId].m_Addr.ip[2], m_aClients[ClientId].m_Addr.ip[3] + ); + BanAdd(m_aClients[ClientId].m_Addr, g_Config.m_SvRconBanTime); // bye + return; + } + } + else + { + m_aClients[ClientId].m_CmdTries = 0; + } + m_aClients[ClientId].m_LastCommand = time_get(); + } // system message if(Msg == NETMSG_REQUEST_MAP_DATA) { @@ -740,10 +784,14 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) { if(m_aClients[ClientId].m_State == CClient::STATE_CONNECTING) { - Addr = m_NetServer.ClientAddr(ClientId); + //Addr = m_NetServer.ClientAddr(ClientId); dbg_msg("server", "player is ready. ClientId=%x ip=%d.%d.%d.%d", - ClientId, Addr.ip[0], Addr.ip[1], Addr.ip[2], Addr.ip[3]); + ClientId, + m_aClients[ClientId].m_Addr.ip[0], + m_aClients[ClientId].m_Addr.ip[1], + m_aClients[ClientId].m_Addr.ip[2], + m_aClients[ClientId].m_Addr.ip[3]); m_aClients[ClientId].m_State = CClient::STATE_READY; GameServer()->OnClientConnected(ClientId); GameServer()->OnSetAuthed(ClientId, (void*)m_aClients[ClientId].m_Authed); @@ -754,10 +802,14 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) { if(m_aClients[ClientId].m_State == CClient::STATE_READY) { - Addr = m_NetServer.ClientAddr(ClientId); + //Addr = m_NetServer.ClientAddr(ClientId); dbg_msg("server", "player has entered the game. ClientId=%x ip=%d.%d.%d.%d", - ClientId, Addr.ip[0], Addr.ip[1], Addr.ip[2], Addr.ip[3]); + ClientId, + m_aClients[ClientId].m_Addr.ip[0], + m_aClients[ClientId].m_Addr.ip[1], + m_aClients[ClientId].m_Addr.ip[2], + m_aClients[ClientId].m_Addr.ip[3]); m_aClients[ClientId].m_State = CClient::STATE_INGAME; GameServer()->OnClientEnter(ClientId); } @@ -820,20 +872,22 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) if(Unpacker.Error() == 0/* && m_aClients[ClientId].m_Authed*/) { - dbg_msg("server", "ClientId=%d Level=%d rcon='%s'", ClientId, m_aClients[ClientId].m_Authed, pCmd); - Addr = m_NetServer.ClientAddr(ClientId); - if(m_aClients[ClientId].m_Authed == 0) + dbg_msg("server", "ClientId=%d Level=%d Rcon='%s'", ClientId, m_aClients[ClientId].m_Authed, pCmd); + //Addr = m_NetServer.ClientAddr(ClientId); + if(m_aClients[ClientId].m_Authed > 0) { - if(++m_aClients[ClientId].m_CmdTries > g_Config.m_SvRconTries) - { - dbg_msg("server", "client tried rcon command without permissions, ban. cid=%x ip=%d.%d.%d.%d", - ClientId, - m_aClients[ClientId].m_Addr.ip[0], m_aClients[ClientId].m_Addr.ip[1], m_aClients[ClientId].m_Addr.ip[2], m_aClients[ClientId].m_Addr.ip[3]); - BanAdd(m_aClients[ClientId].m_Addr, g_Config.m_SvRconTriesBantime); // bye - } - } - else Console()->ExecuteLine(pCmd, m_aClients[ClientId].m_Authed, ClientId); + } else { + dbg_msg("server", "client tried rcon command without permissions. Cid=%x ip=%d.%d.%d.%d", + ClientId, + m_aClients[ClientId].m_Addr.ip[0], + m_aClients[ClientId].m_Addr.ip[1], + m_aClients[ClientId].m_Addr.ip[2], + m_aClients[ClientId].m_Addr.ip[3]); + //BanAdd(m_aClients[ClientId].m_Addr, g_Config.m_SvRconTriesBantime); // bye + } + + } } else if(Msg == NETMSG_RCON_AUTH) @@ -1021,9 +1075,9 @@ void CServer::UpdateServerInfo() } } -int CServer::BanAdd(NETADDR Addr, int Seconds) +int CServer::BanAdd(NETADDR Addr, int Seconds, const char *Reason) { - return m_NetServer.BanAdd(Addr, Seconds); + return m_NetServer.BanAdd(Addr, Seconds, Reason); } int CServer::BanRemove(NETADDR Addr) @@ -1185,6 +1239,11 @@ int CServer::Run() // load map if(LoadMap(g_Config.m_SvMap)) { + Console()->ExecuteLine("tune_reset", 4, -1); + Console()->ExecuteLine("sv_hit 1",4,-1); + Console()->ExecuteLine("sv_npc 0",4,-1); + Console()->ExecuteLine("sv_phook 1",4,-1); + Console()->ExecuteLine("sv_endless_drag 0",4,-1); //TODO: Such string executed where autoexec executed. No need?? // new map loaded GameServer()->OnShutdown(); @@ -1305,15 +1364,28 @@ void CServer::ConKick(IConsole::IResult *pResult, void *pUser, int ClientId) void CServer::ConBan(IConsole::IResult *pResult, void *pUser, int ClientId1) { NETADDR Addr; - char aAddrStr[128]; + char aAddrStr[128], Bufz[100]; const char *pStr = pResult->GetString(0); - int Minutes = 30; + int Minutes = 30, jkl;//???? + str_format(Bufz, sizeof(Bufz), ""); if(pResult->NumArguments() > 1) Minutes = pResult->GetInteger(1); + if(pResult->NumArguments() > 2) + { + for (jkl = 2;jkl <= pResult->NumArguments();jkl++) + { + strcat(Bufz, pResult->GetString(jkl)); + strcat(Bufz," "); + } + } + else + str_format(Bufz, sizeof(Bufz), "no reason given"); + + if(net_addr_from_str(&Addr, pStr) == 0) - ((CServer *)pUser)->BanAdd(Addr, Minutes*60); + ((CServer *)pUser)->BanAdd(Addr, Minutes*60, Bufz); else if(StrAllnum(pStr)) { int ClientId = str_toint(pStr); @@ -1327,7 +1399,7 @@ void CServer::ConBan(IConsole::IResult *pResult, void *pUser, int ClientId1) } NETADDR Addr = ((CServer *)pUser)->m_NetServer.ClientAddr(ClientId); - ((CServer *)pUser)->BanAdd(Addr, Minutes*60); + ((CServer *)pUser)->BanAdd(Addr, Minutes*60, Bufz); } Addr.port = 0; @@ -1457,7 +1529,8 @@ void CServer::RegisterCommands() m_pConsole = Kernel()->RequestInterface(); Console()->Register("kick", "i", CFGFLAG_SERVER, ConKick, this, "", 2); - Console()->Register("ban", "s?i", CFGFLAG_SERVER, ConBan, this, "", 2); + Console()->Register("ban", "s?i?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s", CFGFLAG_SERVER, ConBan, 0, "",2); //horrible long string + Console()->Register("unban", "s", CFGFLAG_SERVER, ConUnban, this, "", 3); Console()->Register("bans", "", CFGFLAG_SERVER, ConBans, this, "", 2); Console()->Register("status", "", CFGFLAG_SERVER, ConStatus, this, "", 1); @@ -1555,6 +1628,12 @@ int main(int argc, const char **argv) // ignore_convention pServer->RegisterCommands(); pGameServer->OnConsoleInit(); + pConsole->ExecuteLine("tune_reset", 4, -1); + pConsole->ExecuteLine("sv_hit 1", 4, -1); + pConsole->ExecuteLine("sv_npc 0", 4, -1); + pConsole->ExecuteLine("sv_phook 1", 4, -1); + pConsole->ExecuteLine("sv_endless_drag 0",4,-1); + //TODO it is in 2 places (and in one file O_o) // execute autoexec file pConsole->ExecuteFile("autoexec.cfg"); diff --git a/src/engine/server/server.h b/src/engine/server/server.h index 09d1c0683..e0c138bc0 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -103,6 +103,7 @@ public: NETADDR m_Addr; // for storing address int m_PwTries; // a players rcon pw tries int m_CmdTries; //Floff players rcon command tries, to prevent command flood server crash + int64 m_CommandTriesTimer; // time void Reset(); }; @@ -178,7 +179,7 @@ public: void SendServerInfo(NETADDR *pAddr, int Token); void UpdateServerInfo(); - int BanAdd(NETADDR Addr, int Seconds); + int BanAdd(NETADDR Addr, int Seconds, const char *Reason); int BanRemove(NETADDR Addr); diff --git a/src/engine/shared/network.cpp b/src/engine/shared/network.cpp index 0305ffffa..ec04a4171 100644 --- a/src/engine/shared/network.cpp +++ b/src/engine/shared/network.cpp @@ -101,11 +101,11 @@ void CNetBase::SendPacketConnless(NETSOCKET Socket, NETADDR *pAddr, const void * net_udp_send(Socket, pAddr, aBuffer, 6+DataSize); } -void CNetBase::SendPacket(NETSOCKET Socket, NETADDR *pAddr, CNetPacketConstruct *pPacket) +int32_t CNetBase::SendPacket(NETSOCKET Socket, NETADDR *pAddr, CNetPacketConstruct *pPacket) { unsigned char aBuffer[NET_MAX_PACKETSIZE]; - int CompressedSize = -1; - int FinalSize = -1; + int32_t CompressedSize = -1; + int32_t FinalSize = -1; // log the data if(ms_DataLogSent) @@ -141,7 +141,8 @@ void CNetBase::SendPacket(NETSOCKET Socket, NETADDR *pAddr, CNetPacketConstruct aBuffer[0] = ((pPacket->m_Flags<<4)&0xf0)|((pPacket->m_Ack>>8)&0xf); aBuffer[1] = pPacket->m_Ack&0xff; aBuffer[2] = pPacket->m_NumChunks; - net_udp_send(Socket, pAddr, aBuffer, FinalSize); + int32_t ResultVal; + ResultVal = net_udp_send(Socket, pAddr, aBuffer, FinalSize); // log raw socket data if(ms_DataLogSent) @@ -152,7 +153,9 @@ void CNetBase::SendPacket(NETSOCKET Socket, NETADDR *pAddr, CNetPacketConstruct io_write(ms_DataLogSent, aBuffer, FinalSize); io_flush(ms_DataLogSent); } + return ResultVal; } + return 0; } // TODO: rename this function diff --git a/src/engine/shared/network.h b/src/engine/shared/network.h index c48e570c7..76eb3ba6a 100644 --- a/src/engine/shared/network.h +++ b/src/engine/shared/network.h @@ -172,7 +172,7 @@ public: void Disconnect(const char *pReason); int Update(); - int Flush(); + int32_t Flush(); int Feed(CNetPacketConstruct *pPacket, NETADDR *pAddr); int QueueChunk(int Flags, int DataSize, const void *pData); @@ -217,6 +217,7 @@ public: { NETADDR m_Addr; int m_Expires; + char m_Reason[100]; }; private: @@ -275,7 +276,8 @@ public: int Drop(int ClientID, const char *Reason); // banning - int BanAdd(NETADDR Addr, int Seconds); + int BanAdd(NETADDR Addr, int Seconds, const char *Reason); + int BanAddNoDrop(NETADDR Addr, int Seconds, const char *Reason); int BanRemove(NETADDR Addr); int BanNum(); // caution, slow int BanGet(int Index, CBanInfo *pInfo); // caution, slow @@ -339,7 +341,7 @@ public: static void SendControlMsg(NETSOCKET Socket, NETADDR *pAddr, int Ack, int ControlMsg, const void *pExtra, int ExtraSize); static void SendPacketConnless(NETSOCKET Socket, NETADDR *pAddr, const void *pData, int DataSize); - static void SendPacket(NETSOCKET Socket, NETADDR *pAddr, CNetPacketConstruct *pPacket); + static int32_t SendPacket(NETSOCKET Socket, NETADDR *pAddr, CNetPacketConstruct *pPacket); static int UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct *pPacket); // The backroom is ack-NET_MAX_SEQUENCE/2. Used for knowing if we acked a packet or not diff --git a/src/engine/shared/network_conn.cpp b/src/engine/shared/network_conn.cpp index 4ed157eb2..0299bfee1 100644 --- a/src/engine/shared/network_conn.cpp +++ b/src/engine/shared/network_conn.cpp @@ -64,15 +64,18 @@ void CNetConnection::SignalResend() m_Construct.m_Flags |= NET_PACKETFLAG_RESEND; } -int CNetConnection::Flush() +int32_t CNetConnection::Flush() { - int NumChunks = m_Construct.m_NumChunks; + int32_t NumChunks = m_Construct.m_NumChunks; if(!NumChunks && !m_Construct.m_Flags) return 0; // send of the packets m_Construct.m_Ack = m_Ack; - CNetBase::SendPacket(m_Socket, &m_PeerAddr, &m_Construct); + if(CNetBase::SendPacket(m_Socket, &m_PeerAddr, &m_Construct) < 0) { + m_State = NET_CONNSTATE_ERROR; + SetError("send error" ); + } // update send times m_LastSendTime = time_get(); diff --git a/src/engine/shared/network_server.cpp b/src/engine/shared/network_server.cpp index 80eda1fe7..735ceb4fb 100644 --- a/src/engine/shared/network_server.cpp +++ b/src/engine/shared/network_server.cpp @@ -1,4 +1,5 @@ #include +#include "config.h" #include "network.h" #define MACRO_LIST_LINK_FIRST(Object, First, Prev, Next) \ @@ -78,7 +79,8 @@ int CNetServer::Drop(int ClientID, const char *pReason) { // TODO: insert lots of checks here NETADDR Addr = ClientAddr(ClientID); - + char Bufz[100]; + str_format( Bufz, sizeof(Bufz),"trying to connect so soon"); dbg_msg("net_server", "client dropped. cid=%d ip=%d.%d.%d.%d reason=\"%s\"", ClientID, Addr.ip[0], Addr.ip[1], Addr.ip[2], Addr.ip[3], @@ -89,6 +91,7 @@ int CNetServer::Drop(int ClientID, const char *pReason) if(m_pfnDelClient) m_pfnDelClient(ClientID, m_UserPtr); m_aSlots[ClientID].m_Connection.Disconnect(pReason); + BanAddNoDrop(Addr, g_Config.m_SvReconnectTime, Bufz); return 0; } @@ -139,7 +142,7 @@ int CNetServer::BanRemove(NETADDR Addr) return -1; } -int CNetServer::BanAdd(NETADDR Addr, int Seconds) +int CNetServer::BanAdd(NETADDR Addr, int Seconds, const char * Reason) { int IpHash = (Addr.ip[0]+Addr.ip[1]+Addr.ip[2]+Addr.ip[3])&0xff; int Stamp = -1; @@ -157,7 +160,11 @@ int CNetServer::BanAdd(NETADDR Addr, int Seconds) if(pBan) { // adjust the ban + if (pBan->m_Info.m_Expires > Seconds) + return 0; + pBan->m_Info.m_Expires = Stamp; + strcpy(pBan->m_Info.m_Reason, m_Reason); return 0; } @@ -212,10 +219,13 @@ int CNetServer::BanAdd(NETADDR Addr, int Seconds) char Buf[128]; NETADDR BanAddr; - if(Seconds) + if(Seconds) { str_format(Buf, sizeof(Buf), "you have been banned for %d minutes", Seconds/60); - else + strcat(Buf, Reason); + } else { str_format(Buf, sizeof(Buf), "you have been banned for life"); + strcat(Buf, Reason); + } for(int i = 0; i < MaxClients(); i++) { @@ -229,6 +239,83 @@ int CNetServer::BanAdd(NETADDR Addr, int Seconds) return 0; } + + +int CNetServer::BanAddNoDrop(NETADDR Addr, int Seconds, const char *Reason) +{ + int IpHash = (Addr.ip[0]+Addr.ip[1]+Addr.ip[2]+Addr.ip[3])&0xff; + int Stamp = -1; + CBan *pBan; + + // remove the port + Addr.port = 0; + + if(Seconds) + Stamp = time_timestamp() + Seconds; + + // search to see if it already exists + pBan = m_aBans[IpHash]; + MACRO_LIST_FIND(pBan, m_pHashNext, net_addr_comp(&pBan->m_Info.m_Addr, &Addr) == 0); + if(pBan) + { + // adjust the ban + if (pBan->m_Info.m_Expires > Seconds) + return 0; + + pBan->m_Info.m_Expires = Stamp; + strcpy(pBan->m_Info.m_Reason, m_Reason); + return 0; + } + + if(!m_BanPool_FirstFree) + return -1; + + // fetch and clear the new ban + pBan = m_BanPool_FirstFree; + MACRO_LIST_UNLINK(pBan, m_BanPool_FirstFree, m_pPrev, m_pNext); + + // setup the ban info + pBan->m_Info.m_Expires = Stamp; + pBan->m_Info.m_Addr = Addr; + strcpy(pBan->m_Info.m_Reason, m_Reason); + // add it to the ban hash + MACRO_LIST_LINK_FIRST(pBan, m_aBans[IpHash], m_pHashPrev, m_pHashNext); + + // insert it into the used list + { + if(m_BanPool_FirstUsed) + { + CBan *pInsertAfter = m_BanPool_FirstUsed; + MACRO_LIST_FIND(pInsertAfter, m_pNext, Stamp < pInsertAfter->m_Info.m_Expires); + + if(pInsertAfter) + pInsertAfter = pInsertAfter->m_pPrev; + else + { + // add to last + pInsertAfter = m_BanPool_FirstUsed; + while(pInsertAfter->m_pNext) + pInsertAfter = pInsertAfter->m_pNext; + } + + if(pInsertAfter) + { + MACRO_LIST_LINK_AFTER(pBan, pInsertAfter, m_pPrev, m_pNext); + } + else + { + MACRO_LIST_LINK_FIRST(pBan, m_BanPool_FirstUsed, m_pPrev, m_pNext); + } + } + else + { + MACRO_LIST_LINK_FIRST(pBan, m_BanPool_FirstUsed, m_pPrev, m_pNext); + } + } + return 0; +} + + int CNetServer::Update() { int Now = time_timestamp(); @@ -293,14 +380,14 @@ int CNetServer::Recv(CNetChunk *pChunk) char BanStr[128]; if(pBan->m_Info.m_Expires) { - int Mins = ((pBan->m_Info.m_Expires - Now)+59)/60; - if(Mins == 1) - str_format(BanStr, sizeof(BanStr), "banned for %d minute", Mins); + int Mins = ((pBan->m_Info.m_Expires - Now))/60; + if(Mins > 1) + str_format(BanStr, sizeof(BanStr), "Banned for %d minute(s) for %s", Mins, pBan->m_Info.m_Reason); else - str_format(BanStr, sizeof(BanStr), "banned for %d minutes", Mins); + str_format(BanStr, sizeof(BanStr), "Banned for %d minute(s) for %s", (pBan->m_Info.m_Expires - Now), pBan->m_Info.m_Reason); } else - str_format(BanStr, sizeof(BanStr), "banned for life"); + str_format(BanStr, sizeof(BanStr), "banned for life. %s", pBan->m_Info.m_Reason); CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, BanStr, str_length(BanStr)+1); continue; } diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 38249fd00..85c5654aa 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -451,10 +451,23 @@ void CGameContext::OnTick() if(m_VoteEnforce == VOTE_ENFORCE_YES) { - Console()->ExecuteLine(m_aVoteCommand, 4, -1); - EndVote(); - SendChat(-1, CGameContext::CHAT_ALL, "Vote passed"); - + //Console()->ExecuteLine(m_aVoteCommand, 4, -1); + //EndVote(); + //SendChat(-1, CGameContext::CHAT_ALL, "Vote passed"); + if(vote_enforce == VOTE_ENFORCE_YES) + { + Console()->ExecuteLine(m_aVoteCommand, 3,-1); + SendChat(-1, CGameContext::CHAT_ALL, "Vote passed (enforced by Admin)"); + dbg_msg("Vote","Due to vote enforcing, vote level has been set to 3"); + EndVote(); + } + else + { + Console()->ExecuteLine(m_aVoteCommand, 4,-1); + dbg_msg("Vote","vote level is set to 4"); + EndVote(); + SendChat(-1, CGameContext::CHAT_ALL, "Vote passed"); + } if(m_apPlayers[m_VoteCreator]) m_apPlayers[m_VoteCreator]->m_Last_VoteCall = 0; } @@ -523,7 +536,19 @@ bool compare_players(CPlayer *pl1, CPlayer *pl2) } void CGameContext::OnSetAuthed(int client_id, void* status) -{ +{ + if(m_apPlayers[client_id]) + { + m_apPlayers[client_id]->m_Authed = (int)status; + char buf[11]; + str_format(buf, sizeof(buf), "ban %d %d", client_id, g_Config.m_SvVoteKickBanTime); + //dbg_msg("hooks","%d", m_aVoteCommand == buf);//??? + if ( !strcmp(m_aVoteCommand,buf)) + { + m_VoteEnforce = CGameContext::VOTE_ENFORCE_NO; + dbg_msg("hooks","Aborting vote"); + } + } if(m_apPlayers[client_id]) m_apPlayers[client_id]->m_Authed = (int)status; } @@ -747,13 +772,23 @@ void CGameContext::OnMessage(int MsgId, CUnpacker *pUnpacker, int ClientId) if(str_comp_nocase(pMsg->m_Type, "option") == 0) { CVoteOption *pOption = m_pVoteOptionFirst; + static int64 last_mapvote = 0; //floff while(pOption) { if(str_comp_nocase(pMsg->m_Value, pOption->m_aCommand) == 0) { + if(m_apPlayers[ClientId]->m_Authed == 0 && strncmp(pOption->m_aCommand, "sv_map ", 7) == 0 && time_get() < last_mapvote + (time_freq() * g_Config.m_SvVoteMapDelay)) + { + char chatmsg[512] = {0}; + str_format(chatmsg, sizeof(chatmsg), "There's a %d second delay between map-votes,Please wait %d Second(s)", g_Config.m_SvVoteMapDelay,((last_mapvote+(g_Config.m_SvVoteMapDelay * time_freq()))/time_freq())-(time_get()/time_freq())); + SendChatTarget(ClientId, chatmsg); + + return; + } str_format(aChatmsg, sizeof(aChatmsg), "%s called vote to change server option '%s'", Server()->ClientName(ClientId), pOption->m_aCommand); str_format(aDesc, sizeof(aDesc), "%s", pOption->m_aCommand); str_format(aCmd, sizeof(aCmd), "%s", pOption->m_aCommand); + last_mapvote = time_get(); break; } @@ -766,10 +801,24 @@ void CGameContext::OnMessage(int MsgId, CUnpacker *pUnpacker, int ClientId) SendChatTarget(ClientId, aChatmsg); return; } + last_mapvote = time_get(); } else if(str_comp_nocase(pMsg->m_Type, "kick") == 0) { - if(!g_Config.m_SvVoteKick) + if(m_apPlayers[ClientId]->m_Authed == 0 && time_get() < m_apPlayers[ClientId]->m_LastKickVote + (time_freq() * 5)) + return; + else if(m_apPlayers[ClientId]->m_Authed == 0 && time_get() < m_apPlayers[ClientId]->m_LastKickVote + (time_freq() * g_Config.m_SvVoteKickDelay)) + { + char chatmsg[512] = {0}; + str_format(chatmsg, sizeof(chatmsg), "There's a %d second waittime between kickvotes for each player please wait %d second(s)", + g_Config.m_SvVoteKickDelay, + ((m_apPlayers[ClientId]->m_LastKickVote + (m_apPlayers[ClientId]->m_LastKickVote*time_freq()))/time_freq())-(time_get()/time_freq()) + ); + SendChatTarget(client_id, chatmsg); + m_apPlayers[ClientId]->m_LastKickVote = time_get(); + return; + } + else if(!g_Config.m_SvVoteKick) { SendChatTarget(ClientId, "Server does not allow voting to kick players"); return; diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index c540499f9..55ab5a37e 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -21,6 +21,12 @@ CPlayer::CPlayer(CGameContext *pGameServer, int CID, int Team) m_Muted = 0; this->m_ClientID = CID; m_Team = GameServer()->m_pController->ClampTeam(Team); + + m_LastPlaytime = time_get(); + m_LastTarget_x = 0; + m_LastTarget_y = 0; + m_SentAfkWarning = 0; // afk timer's 1st warning after 50% of sv_max_afk_time + m_SentAfkWarning2 = 0; } CPlayer::~CPlayer() @@ -142,6 +148,7 @@ void CPlayer::OnDirectInput(CNetObj_PlayerInput *NewInput) if(!Character && m_Team == -1) m_ViewPos = vec2(NewInput->m_TargetX, NewInput->m_TargetY); + AfkTimer(NewInput->m_TargetX, NewInput->m_TargetY); } CCharacter *CPlayer::GetCharacter() @@ -207,3 +214,56 @@ void CPlayer::TryRespawn() GameServer()->CreatePlayerSpawn(SpawnPos); } } + + +void CPlayer::AfkTimer(int new_target_x, int new_target_y) +{ + /* + afk timer (x, y = mouse coordinates) + Since a player has to move the mouse to play, this is a better method than checking + the player's position in the game world, because it can easily be bypassed by just locking a key. + Frozen players could be kicked as well, because they can't move. + It also works for spectators. + */ + + if(m_Authed) return; // don't kick admins + if(g_Config.m_SvMaxAfkTime == 0) return; // 0 = disabled + + if(new_target_x != last_target_x || new_target_y != last_target_y) + { + m_LastPlaytime = time_get(); + m_LastTarget_x = new_target_x; + m_LastTarget_y = new_target_y; + m_SentAfkWarning = 0; // afk timer's 1st warning after 50% of sv_max_afk_time + m_SentAfkWarning2 = 0; + + } + else + { + // not playing, check how long + if(m_SentAfkWarning == 0 && m_LastPlaytime < time_get()-time_freq()*(int)(g_Config.m_SvMaxAfkTime*0.5)) + { + sprintf( + m_pAfkMsg, + "You have been afk for %d seconds now. Please note that you get kicked after not playing for %d seconds.", + (int)(g_Config.m_SvMaxAfkTime*0.5), + g_Config.m_SvMaxAfkTime + ); + m_pGameServer->SendChatTarget(client_id, m_pAfkMsg); + m_SentAfkWarning = 1; + } else if(m_SentAfkWarning2 == 0 && m_LastPlaytime < time_get()-time_freq()*(int)(g_Config.m_SvMaxAfkTime*0.9)) + { + sprintf( + m_pAfkMsg, + "You have been afk for %d seconds now. Please note that you get kicked after not playing for %d seconds.", + (int)(g_Config.m_SvMaxAfkTime*0.9), + g_Config.m_SvMaxAfkTime + ); + m_pGameServer->SendChatTarget(client_id, m_pAfkMsg); + m_SentAfkWarning = 1; + } else if(last_playtime < time_get()-time_freq()*g_Config.m_SvMaxAfkTime) + { + m_pGameServer->Server()->Kick(client_id,"Away from keyboard"); + } + } +} \ No newline at end of file diff --git a/src/game/server/player.h b/src/game/server/player.h index 49afc9802..a8a9c66c9 100644 --- a/src/game/server/player.h +++ b/src/game/server/player.h @@ -40,13 +40,15 @@ public: int m_Vote; int m_VotePos; // - int m_Last_VoteCall; - int m_Last_VoteTry; - int m_Last_Chat; - int m_Last_SetTeam; - int m_Last_ChangeInfo; - int m_Last_Emote; - int m_Last_Kill; + int64 m_Last_KickVote; + + int64 m_Last_VoteCall; + int64 m_Last_VoteTry; + int64 m_Last_Chat; + int64 m_Last_SetTeam; + int64 m_Last_ChangeInfo; + int64 m_Last_Emote; + int64 m_Last_Kill; //DDRace int m_Muted; @@ -81,6 +83,15 @@ public: int m_ScoreStartTick; bool m_ForceBalanced; + // afk timer + void AfkTimer(int new_target_x, int new_target_y); + int64 m_LastPlaytime; + int m_LastTarget_x; + int m_LastTarget_y; + int m_SentAfkWarning; // afk timer's 1st warning after 50% of sv_max_afk_time + int m_SentAfkWarning2; // afk timer's 2nd warning after 90% of sv_max_afk_time + char m_pAfkMsg[160]; + private: CCharacter *Character; CGameContext *m_pGameServer; @@ -88,6 +99,8 @@ private: CGameContext *GameServer() const { return m_pGameServer; } IServer *Server() const; + + // bool m_Spawning; int m_ClientID;