int CNetServer::BanmasterCheck(NETADDR *pAddr, unsigned char *SequenceNumber) { int64 Timeout = time_freq(); int64 Now = time_get(); for(int i = 0; i < m_NumBanmasters; i++) { if(net_addr_comp(&m_aBanmasters[i], pAddr) == 0 && (mem_comp(m_aSequenceNumbers[i], SequenceNumber, NET_BANMASTER_NR_SIZE) == 0) && (m_aTimeouts[i] && m_aTimeouts[i]+Timeout > Now)) { return i; } } return -1; }
void CLuaFile::TickDefered() { if (!g_Config.m_SvLua) return; ErrorFunc(m_pLua); if (!FunctionExist("TickDefered")) return; FunctionPrepare("TickDefered"); PushInteger((int)(time_get() * 1000 / time_freq())); PushInteger(m_pServer->Server()->Tick()); FunctionExec(); ErrorFunc(m_pLua); }
void CGameContext::SendVoteSet(int ClientID) { CNetMsg_Sv_VoteSet Msg; if(m_VoteCloseTime) { Msg.m_Timeout = (m_VoteCloseTime-time_get())/time_freq(); Msg.m_pDescription = m_aVoteDescription; Msg.m_pCommand = ""; } else { Msg.m_Timeout = 0; Msg.m_pDescription = ""; Msg.m_pCommand = ""; } Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, ClientID); }
int CNetServer::Update() { int64 Now = time_get(); for(int i = 0; i < MaxClients(); i++) { m_aSlots[i].m_Connection.Update(); if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ERROR) { if(Now - m_aSlots[i].m_Connection.ConnectTime() < time_freq() && NetBan()) NetBan()->BanAddr(ClientAddr(i), 60, "Stressing network"); else Drop(i, m_aSlots[i].m_Connection.ErrorString()); } } return 0; }
void HUD::render_teambalancewarning() { // render prompt about team-balance bool flash = time_get()/(time_freq()/2)%2 == 0; if (gameclient.snap.gameobj && (gameclient.snap.gameobj->flags&GAMEFLAG_TEAMS) != 0) { if (config.cl_warning_teambalance && !config.cl_clear_all && abs(gameclient.snap.team_size[0]-gameclient.snap.team_size[1]) >= 2) { const char *text = "Please balance teams!"; if(flash) gfx_text_color(1,1,0.5f,1); else gfx_text_color(0.7f,0.7f,0.2f,1.0f); gfx_text(0x0, 5, 50, 6, text, -1); gfx_text_color(1,1,1,1); } } }
void CPlayer::AfkVoteTimer(CNetObj_PlayerInput *NewTarget) { if(g_Config.m_SvMaxAfkVoteTime == 0) return; if(mem_comp(NewTarget, &m_LastTarget, sizeof(CNetObj_PlayerInput)) != 0) { m_LastPlaytime = time_get(); mem_copy(&m_LastTarget, NewTarget, sizeof(CNetObj_PlayerInput)); } else if(m_LastPlaytime < time_get()-time_freq()*g_Config.m_SvMaxAfkVoteTime) { m_Afk = true; return; } m_Afk = false; }
void CNetTokenCache::AddToken(const NETADDR *pAddr, TOKEN Token) { if(Token == NET_TOKEN_NONE) return; CAddressInfo Info; Info.m_Addr = *pAddr; Info.m_Token = Token; Info.m_Expiry = time_get() + time_freq() * NET_TOKENCACHE_ADDRESSEXPIRY; (*m_TokenCache.Allocate(sizeof(Info))) = Info; // search the list of packets to be sent // for this address CConnlessPacketInfo *pPrevInfo = 0; CConnlessPacketInfo *pInfo = m_pConnlessPacketList; while(pInfo) { static NETADDR NullAddr = { 0 }; NullAddr.type = 7; // cover broadcasts NullAddr.port = pAddr->port; if(net_addr_comp(&pInfo->m_Addr, pAddr) == 0 || net_addr_comp(&pInfo->m_Addr, &NullAddr) == 0) { CNetBase::SendPacketConnless(m_Socket, pAddr, Token, m_pTokenManager->GenerateToken(pAddr), pInfo->m_aData, pInfo->m_DataSize); CConnlessPacketInfo *pNext = pInfo->m_pNext; if(pPrevInfo) pPrevInfo->m_pNext = pNext; if(pInfo == m_pConnlessPacketList) m_pConnlessPacketList = pNext; delete pInfo; pInfo = pNext; } else { if(pPrevInfo) pPrevInfo = pPrevInfo->m_pNext; else pPrevInfo = pInfo; pInfo = pInfo->m_pNext; } } }
static void perf_dump_imp(PERFORMACE_INFO *info, int indent) { char buf[512] = {0}; int64 freq = time_freq(); int i; for(i = 0; i < indent; i++) buf[i] = ' '; str_format(&buf[indent], sizeof(buf)-indent, "%-20s %8.2f %8.2f", info->name, info->total*1000/(float)freq, info->biggest*1000/(float)freq); dbg_msg("perf", "%s", buf); info = info->first_child; while(info) { perf_dump_imp(info, indent+2); info = info->next_child; } }
void CHud::RenderTeambalanceWarning() { // render prompt about team-balance bool Flash = time_get()/(time_freq()/2)%2 == 0; if(m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_TEAMS) { int TeamDiff = m_pClient->m_Snap.m_aTeamSize[TEAM_RED]-m_pClient->m_Snap.m_aTeamSize[TEAM_BLUE]; if (g_Config.m_ClWarningTeambalance && (TeamDiff >= 2 || TeamDiff <= -2)) { const char *pText = Localize("Please balance teams!"); if(Flash) TextRender()->TextColor(1,1,0.5f,1); else TextRender()->TextColor(0.7f,0.7f,0.2f,1.0f); TextRender()->Text(0x0, 5, 50, 6, pText, -1); TextRender()->TextColor(1,1,1,1); } } }
void snap_free_id(int id) { dbg_assert(snap_ids[id].state == 1, "id is not alloced"); snap_id_inusage--; snap_ids[id].state = 2; snap_ids[id].timeout = time_get()+time_freq()*5; snap_ids[id].next = -1; if(snap_last_timed_id != -1) { snap_ids[snap_last_timed_id].next = id; snap_last_timed_id = id; } else { snap_first_timed_id = id; snap_last_timed_id = id; } }
void CSnapIDPool::FreeID(int Id) { dbg_assert(m_aIDs[Id].m_State == 1, "id is not alloced"); m_InUsage--; m_aIDs[Id].m_State = 2; m_aIDs[Id].m_Timeout = time_get()+time_freq()*5; m_aIDs[Id].m_Next = -1; if(m_LastTimed != -1) { m_aIDs[m_LastTimed].m_Next = Id; m_LastTimed = Id; } else { m_FirstTimed = Id; m_LastTimed = Id; } }
void CGameContext::SendVoteSet(int Type, int ToClientID) { CNetMsg_Sv_VoteSet Msg; if(m_VoteCloseTime) { Msg.m_ClientID = m_VoteCreator; Msg.m_Type = Type; Msg.m_Timeout = (m_VoteCloseTime-time_get())/time_freq(); Msg.m_pDescription = m_aVoteDescription; Msg.m_pReason = m_aVoteReason; } else { Msg.m_Type = Type; Msg.m_Timeout = 0; Msg.m_ClientID = m_VoteCreator; Msg.m_pDescription = ""; Msg.m_pReason = ""; } Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, ToClientID); }
static int Run() { int64 NextHeartBeat = 0; NETADDR BindAddr = {NETTYPE_IPV4, {0},0}; if(!pNet->Open(BindAddr, 0, 0, 0, 0)) return 0; while(1) { CNetChunk p; pNet->Update(); while(pNet->Recv(&p)) { if(p.m_ClientID == -1) { if(p.m_DataSize == sizeof(SERVERBROWSE_GETINFO) && mem_comp(p.m_pData, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO)) == 0) { SendServerInfo(&p.m_Address); } else if(p.m_DataSize == sizeof(SERVERBROWSE_FWCHECK) && mem_comp(p.m_pData, SERVERBROWSE_FWCHECK, sizeof(SERVERBROWSE_FWCHECK)) == 0) { SendFWCheckResponse(&p.m_Address); } } } /* send heartbeats if needed */ if(NextHeartBeat < time_get()) { NextHeartBeat = time_get()+time_freq()*(15+(rand()%15)); SendHeartBeats(); } thread_sleep(100); } }
void CHud::RenderGameTimer() { // MineTee CServerInfo Info; Client()->GetServerInfo(&Info); if (str_find_nocase(Info.m_aGameType, "minetee")) return; // float Half = 300.0f*Graphics()->ScreenAspect()/2.0f; if(!(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_SUDDENDEATH)) { char Buf[32]; int Time = 0; if(m_pClient->m_Snap.m_pGameInfoObj->m_TimeLimit && !m_pClient->m_Snap.m_pGameInfoObj->m_WarmupTimer) { Time = m_pClient->m_Snap.m_pGameInfoObj->m_TimeLimit*60 - ((Client()->GameTick()-m_pClient->m_Snap.m_pGameInfoObj->m_RoundStartTick)/Client()->GameTickSpeed()); if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER) Time = 0; } else Time = (Client()->GameTick()-m_pClient->m_Snap.m_pGameInfoObj->m_RoundStartTick)/Client()->GameTickSpeed(); str_format(Buf, sizeof(Buf), "%d:%02d", Time/60, Time%60); float FontSize = 10.0f; float w = TextRender()->TextWidth(0, FontSize, Buf, -1); // last 60 sec red, last 10 sec blink if(m_pClient->m_Snap.m_pGameInfoObj->m_TimeLimit && Time <= 60 && !m_pClient->m_Snap.m_pGameInfoObj->m_WarmupTimer) { float Alpha = Time <= 10 && (2*time_get()/time_freq()) % 2 ? 0.5f : 1.0f; TextRender()->TextColor(1.0f, 0.25f, 0.25f, Alpha); } TextRender()->Text(0, Half-w/2, 2, FontSize, Buf, -1); TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f); } }
void CBroadcast::OnMessage(int MsgType, void *pRawMsg) { CALLSTACK_ADD(); if(MsgType == NETMSGTYPE_SV_BROADCAST) { CNetMsg_Sv_Broadcast *pMsg = (CNetMsg_Sv_Broadcast *)pRawMsg; str_copy(m_aBroadcastText, pMsg->m_pMessage, sizeof(m_aBroadcastText)); CTextCursor Cursor; TextRender()->SetCursor(&Cursor, 0, 0, 12.0f, TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = 300*Graphics()->ScreenAspect(); TextRender()->TextEx(&Cursor, m_aBroadcastText, -1); m_BroadcastRenderOffset = 150*Graphics()->ScreenAspect()-Cursor.m_X/2; m_BroadcastTime = time_get()+time_freq()*10; if (g_Config.m_ClPrintBroadcasts) { char aBuf[1024]; int i, ii; for (i = 0, ii = 0; i < str_length(m_aBroadcastText); i++) { if (m_aBroadcastText[i] == '\n') { aBuf[ii] = '\0'; ii = 0; m_pClient->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "broadcast", aBuf, true); } else { aBuf[ii] = m_aBroadcastText[i]; ii++; } } aBuf[ii] = '\0'; m_pClient->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "broadcast", aBuf, true); } } }
void CNetTokenCache::SendPacketConnless(const NETADDR *pAddr, const void *pData, int DataSize, CSendCBData *pCallbackData) { TOKEN Token = GetToken(pAddr); if(Token != NET_TOKEN_NONE) { CNetBase::SendPacketConnless(m_Socket, pAddr, Token, m_pTokenManager->GenerateToken(pAddr), pData, DataSize); } else { FetchToken(pAddr); // store the packet for future sending CConnlessPacketInfo **ppInfo = &m_pConnlessPacketList; while(*ppInfo) ppInfo = &(*ppInfo)->m_pNext; *ppInfo = new CConnlessPacketInfo(); mem_copy((*ppInfo)->m_aData, pData, DataSize); (*ppInfo)->m_Addr = *pAddr; (*ppInfo)->m_DataSize = DataSize; int64 Now = time_get(); (*ppInfo)->m_Expiry = Now + time_freq() * NET_TOKENCACHE_PACKETEXPIRY; (*ppInfo)->m_LastTokenRequest = Now; (*ppInfo)->m_pNext = 0; if(pCallbackData) { (*ppInfo)->m_pfnCallback = pCallbackData->m_pfnCallback; (*ppInfo)->m_pCallbackUser = pCallbackData->m_pCallbackUser; pCallbackData->m_TrackID = (*ppInfo)->m_TrackID; } else { (*ppInfo)->m_pfnCallback = 0; (*ppInfo)->m_pCallbackUser = 0; } } }
void CNetTokenCache::SendPacketConnless(const NETADDR *pAddr, const void *pData, int DataSize) { TOKEN Token = GetToken(pAddr); if(Token != NET_TOKEN_NONE) { CNetBase::SendPacketConnless(m_Socket, pAddr, Token, m_pTokenManager->GenerateToken(pAddr), pData, DataSize); } else { FetchToken(pAddr); // store the packet for future sending CConnlessPacketInfo **ppInfo = &m_pConnlessPacketList; while(*ppInfo) ppInfo = &(*ppInfo)->m_pNext; *ppInfo = new CConnlessPacketInfo(); mem_copy((*ppInfo)->m_aData, pData, DataSize); (*ppInfo)->m_Addr = *pAddr; (*ppInfo)->m_DataSize = DataSize; (*ppInfo)->m_Expiry = time_get() + time_freq() * NET_TOKENCACHE_PACKETEXPIRY; (*ppInfo)->m_pNext = 0; } }
void CLuaFile::Tick() { if (!g_Config.m_SvLua) return; ErrorFunc(m_pLua); MySQLTick(); //garbage collector -> clear old results that aren't fetched by lua m_pLuaShared->Tick(); if (!FunctionExist("Tick")) return; FunctionPrepare("Tick"); PushInteger((int)(time_get() * 1000 / time_freq())); PushInteger(m_pServer->Server()->Tick()); FunctionExec(); if (m_pServer->Server()->Tick() % (m_pServer->Server()->TickSpeed() * 60) == 0) dbg_msg("lua", "%i kiB", lua_gc(m_pLua, LUA_GCCOUNT, 0)); lua_gc(m_pLua, LUA_GCCOLLECT, 1000); ErrorFunc(m_pLua); }
void CGameContext::StartVote(const char *pDesc, const char *pCommand) { // check if a vote is already running if(m_VoteCloseTime) return; // reset votes m_VoteEnforce = VOTE_ENFORCE_UNKNOWN; for(int i = 0; i < MAX_CLIENTS; i++) { if(m_apPlayers[i]) { m_apPlayers[i]->m_Vote = 0; m_apPlayers[i]->m_VotePos = 0; } } // start vote m_VoteCloseTime = time_get() + time_freq()*25; str_copy(m_aVoteDescription, pDesc, sizeof(m_aVoteDescription)); str_copy(m_aVoteCommand, pCommand, sizeof(m_aVoteCommand)); SendVoteSet(-1); m_VoteUpdate = true; }
void CGameClient::OnRender() { /*Graphics()->Clear(1,0,0); menus->render_background(); return;*/ /* Graphics()->Clear(1,0,0); Graphics()->MapScreen(0,0,100,100); Graphics()->QuadsBegin(); Graphics()->SetColor(1,1,1,1); Graphics()->QuadsDraw(50, 50, 30, 30); Graphics()->QuadsEnd(); return;*/ // update the local character and spectate position UpdatePositions(); // dispatch all input to systems DispatchInput(); // render all systems for(int i = 0; i < m_All.m_Num; i++) m_All.m_paComponents[i]->OnRender(); // clear new tick flags m_NewTick = false; m_NewPredictedTick = false; // check if client info has to be resent if(m_LastSendInfo && Client()->State() == IClient::STATE_ONLINE && m_Snap.m_LocalClientID >= 0 && !m_pMenus->IsActive() && m_LastSendInfo+time_freq()*5 < time_get()) { // resend if client info differs if(str_comp(g_Config.m_PlayerName, m_aClients[m_Snap.m_LocalClientID].m_aName) || str_comp(g_Config.m_PlayerClan, m_aClients[m_Snap.m_LocalClientID].m_aClan) || g_Config.m_PlayerCountry != m_aClients[m_Snap.m_LocalClientID].m_Country || str_comp(g_Config.m_PlayerSkin, m_aClients[m_Snap.m_LocalClientID].m_aSkinName) || (m_Snap.m_pGameInfoObj && !(m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_TEAMS) && // no teamgame? (g_Config.m_PlayerUseCustomColor != m_aClients[m_Snap.m_LocalClientID].m_UseCustomColor || g_Config.m_PlayerColorBody != m_aClients[m_Snap.m_LocalClientID].m_ColorBody || g_Config.m_PlayerColorFeet != m_aClients[m_Snap.m_LocalClientID].m_ColorFeet))) { SendInfo(false); } m_LastSendInfo = 0; } }
int CControls::SnapInput(int *pData, int *pPredictionData) { static int64 LastSendTime = 0; bool Send = false; // update player state if(m_pClient->m_pChat->IsActive()) m_InputData.m_PlayerFlags = PLAYERFLAG_CHATTING; else if(m_pClient->m_pMenus->IsActive()) m_InputData.m_PlayerFlags = PLAYERFLAG_IN_MENU; else m_InputData.m_PlayerFlags = PLAYERFLAG_PLAYING; if(m_pClient->m_pScoreboard->Active() || m_pClient->m_UpdateScoreboard) m_InputData.m_PlayerFlags |= PLAYERFLAG_SCOREBOARD; m_pClient->m_UpdateScoreboard = false; if(m_LastData.m_PlayerFlags != m_InputData.m_PlayerFlags) Send = true; m_LastData.m_PlayerFlags = m_InputData.m_PlayerFlags; // we freeze the input if chat or menu is activated if(!(m_InputData.m_PlayerFlags&PLAYERFLAG_PLAYING)) { OnReset(); mem_copy(pData, &m_InputData, sizeof(m_InputData)); // send once a second just to be sure if(time_get() > LastSendTime + time_freq()) Send = true; } else { m_InputData.m_TargetX = (int)m_MousePos.x; m_InputData.m_TargetY = (int)m_MousePos.y; if(!m_InputData.m_TargetX && !m_InputData.m_TargetY) { m_InputData.m_TargetX = 1; m_MousePos.x = 1; } // set direction m_InputData.m_Direction = 0; if(m_InputDirectionLeft && !m_InputDirectionRight) m_InputData.m_Direction = -1; if(!m_InputDirectionLeft && m_InputDirectionRight) m_InputData.m_Direction = 1; // stress testing if(g_Config.m_DbgStress) { float t = Client()->LocalTime(); mem_zero(&m_InputData, sizeof(m_InputData)); m_InputData.m_Direction = ((int)t/2)&1; m_InputData.m_Jump = ((int)t); m_InputData.m_Fire = ((int)(t*10)); m_InputData.m_Hook = ((int)(t*2))&1; m_InputData.m_WantedWeapon = ((int)t)%NUM_WEAPONS; m_InputData.m_TargetX = (int)(sinf(t*3)*100.0f); m_InputData.m_TargetY = (int)(cosf(t*3)*100.0f); } m_PredictionData = m_InputData; if (m_pClient->m_pLuaBinding) //make sure that we have this class { //Lua m_pClient->m_pLuaBinding->m_ControlDirectionPre = m_InputData.m_Direction; m_pClient->m_pLuaBinding->m_ControlFirePre = m_InputData.m_Fire; m_pClient->m_pLuaBinding->m_ControlJumpPre = m_InputData.m_Jump; m_pClient->m_pLuaBinding->m_ControlHookPre = m_InputData.m_Hook; m_pClient->m_pLuaBinding->m_ControlWeaponPre = m_InputData.m_WantedWeapon; m_pClient->m_pLuaBinding->m_ControlTargetXPre = m_InputData.m_TargetX; m_pClient->m_pLuaBinding->m_ControlTargetYPre = m_InputData.m_TargetY; int EventID = m_pClient->m_pLua->m_pEventListener->CreateEventStack(); m_pClient->m_pLua->m_pEventListener->OnEvent("OnControlChange"); if (m_pClient->m_pLuaBinding->m_ControlDirectionIsSet) { m_InputData.m_Direction = m_pClient->m_pLuaBinding->m_ControlDirection; } if (m_pClient->m_pLuaBinding->m_ControlFireIsSet) { m_InputData.m_Fire = m_pClient->m_pLuaBinding->m_ControlFire; } if (m_pClient->m_pLuaBinding->m_ControlHookIsSet) { m_InputData.m_Hook = m_pClient->m_pLuaBinding->m_ControlHook; } if (m_pClient->m_pLuaBinding->m_ControlJumpIsSet) { m_InputData.m_Jump = m_pClient->m_pLuaBinding->m_ControlJump; } if (m_pClient->m_pLuaBinding->m_ControlWeaponIsSet) { m_InputData.m_WantedWeapon = m_pClient->m_pLuaBinding->m_ControlWeapon; } if (m_pClient->m_pLuaBinding->m_ControlTargetXIsSet) { m_InputData.m_TargetX = m_pClient->m_pLuaBinding->m_ControlTargetX; } if (m_pClient->m_pLuaBinding->m_ControlTargetYIsSet) { m_InputData.m_TargetY = m_pClient->m_pLuaBinding->m_ControlTargetY; } if (m_pClient->m_pLuaBinding->m_ControlDirectionPredictedIsSet) { m_PredictionData.m_Direction = m_pClient->m_pLuaBinding->m_ControlDirectionPredicted; } if (m_pClient->m_pLuaBinding->m_ControlFirePredictedIsSet) { m_PredictionData.m_Fire = m_pClient->m_pLuaBinding->m_ControlFirePredicted; } if (m_pClient->m_pLuaBinding->m_ControlHookPredictedIsSet) { m_PredictionData.m_Hook = m_pClient->m_pLuaBinding->m_ControlHookPredicted; } if (m_pClient->m_pLuaBinding->m_ControlJumpPredictedIsSet) { m_PredictionData.m_Jump = m_pClient->m_pLuaBinding->m_ControlJumpPredicted; } if (m_pClient->m_pLuaBinding->m_ControlWeaponPredictedIsSet) { m_PredictionData.m_WantedWeapon = m_pClient->m_pLuaBinding->m_ControlWeaponPredicted; } if (m_pClient->m_pLuaBinding->m_ControlTargetXPredictedIsSet) { m_PredictionData.m_TargetX = m_pClient->m_pLuaBinding->m_ControlTargetXPredicted; } if (m_pClient->m_pLuaBinding->m_ControlTargetYPredictedIsSet) { m_PredictionData.m_TargetY = m_pClient->m_pLuaBinding->m_ControlTargetYPredicted; } } // check if we need to send input if(m_InputData.m_Direction != m_LastData.m_Direction) Send = true; else if(m_InputData.m_Jump != m_LastData.m_Jump) Send = true; else if(m_InputData.m_Fire != m_LastData.m_Fire) Send = true; else if(m_InputData.m_Hook != m_LastData.m_Hook) Send = true; else if(m_InputData.m_WantedWeapon != m_LastData.m_WantedWeapon) Send = true; else if(m_InputData.m_NextWeapon != m_LastData.m_NextWeapon) Send = true; else if(m_InputData.m_PrevWeapon != m_LastData.m_PrevWeapon) Send = true; // send at at least 10hz if(time_get() > LastSendTime + time_freq()/25) Send = true; } // copy and return size m_LastData = m_InputData; if(!Send) return 0; LastSendTime = time_get(); mem_copy(pData, &m_InputData, sizeof(m_InputData)); mem_copy(pPredictionData, &m_PredictionData, sizeof(m_PredictionData)); return sizeof(m_InputData); }
void CServerBrowser::Update(bool ForceResort) { if(m_ServerdataLocked) return; int64 Timeout = time_freq(); int64 Now = time_get(); int Count; CServerEntry *pEntry, *pNext; // do server list requests if(m_NeedRefresh && !m_pMasterServer->IsRefreshing()) { NETADDR Addr; CNetChunk Packet; int i = 0; m_NeedRefresh = 0; m_MasterServerCount = -1; mem_zero(&Packet, sizeof(Packet)); Packet.m_ClientID = -1; Packet.m_Flags = NETSENDFLAG_CONNLESS; Packet.m_DataSize = sizeof(SERVERBROWSE_GETCOUNT); Packet.m_pData = SERVERBROWSE_GETCOUNT; for(i = 0; i < IMasterServer::MAX_MASTERSERVERS; i++) { if(!m_pMasterServer->IsValid(i)) continue; Addr = m_pMasterServer->GetAddr(i); m_pMasterServer->SetCount(i, -1); Packet.m_Address = Addr; m_pNetClient->Send(&Packet); if(g_Config.m_Debug) { dbg_msg("client_srvbrowse", "count-request sent to %d", i); } } } // check if all server counts arrived if(m_MasterServerCount == -1) { m_MasterServerCount = 0; for(int i = 0; i < IMasterServer::MAX_MASTERSERVERS; i++) { if(!m_pMasterServer->IsValid(i)) continue; int Count = m_pMasterServer->GetCount(i); if(Count == -1) { /* ignore Server m_MasterServerCount = -1; return; // we don't have the required server information */ } else m_MasterServerCount += Count; } // request serverlist NETADDR Addr; CNetChunk Packet; mem_zero(&Packet, sizeof(Packet)); Packet.m_ClientID = -1; Packet.m_Flags = NETSENDFLAG_CONNLESS; Packet.m_DataSize = sizeof(SERVERBROWSE_GETLIST); Packet.m_pData = SERVERBROWSE_GETLIST; for(int i = 0; i < IMasterServer::MAX_MASTERSERVERS; i++) { if(!m_pMasterServer->IsValid(i)) continue; Addr = m_pMasterServer->GetAddr(i); Packet.m_Address = Addr; m_pNetClient->Send(&Packet); } if(g_Config.m_Debug) { dbg_msg("client_srvbrowse", "servercount: %d, requesting server list", m_MasterServerCount); } m_LastPacketTick = 0; } else if(m_MasterServerCount > -1) { m_MasterServerCount = 0; for(int i = 0; i < IMasterServer::MAX_MASTERSERVERS; i++) { if(!m_pMasterServer->IsValid(i)) continue; int Count = m_pMasterServer->GetCount(i); if(Count == -1) { /* ignore Server m_MasterServerCount = -1; return; // we don't have the required server information */ } else m_MasterServerCount += Count; } //if(g_Config.m_Debug) //{ // dbg_msg("client_srvbrowse", "ServerCount2: %d", m_MasterServerCount); //} } if(m_MasterServerCount > m_NumRequests + m_LastPacketTick) { ++m_LastPacketTick; return; // wait for more packets } pEntry = m_pFirstReqServer; Count = 0; while(1) { if(!pEntry) // no more entries break; if(pEntry->m_RequestTime && pEntry->m_RequestTime+Timeout < Now) { pEntry = pEntry->m_pNextReq; continue; } // no more than 10 concurrent requests if(Count >= m_CurrentMaxRequests) break; if(pEntry->m_RequestTime == 0) { if (pEntry->m_Is64) RequestImpl64(pEntry->m_Addr, pEntry); else RequestImpl(pEntry->m_Addr, pEntry); } Count++; pEntry = pEntry->m_pNextReq; } // no more current server requests if(m_pFirstReqServer && Count == 0 && m_CurrentMaxRequests > 1) { // reset old ones pEntry = m_pFirstReqServer; while(1) { if(!pEntry) // no more entries break; pEntry->m_RequestTime = 0; pEntry = pEntry->m_pNextReq; } // update max-requests m_CurrentMaxRequests /= 2; if(m_CurrentMaxRequests <= 3) { m_CurrentMaxRequests = 1; m_NeedRefresh = false; } } else if(Count == 0 && m_CurrentMaxRequests == 1) // we reached the limit, just release all left requests. If a server sends us a packet, a new request will be added automatically, so we can delete all { pEntry = m_pFirstReqServer; while(1) { if(!pEntry) // no more entries break; pNext = pEntry->m_pNextReq; RemoveRequest(pEntry); // release request pEntry = pNext; } } // check if we need to resort if(m_Sorthash != SortHash() || ForceResort) Sort(); }
void CGameClient::OnInit() { m_pGraphics = Kernel()->RequestInterface<IGraphics>(); // propagate pointers m_UI.SetGraphics(Graphics(), TextRender()); m_RenderTools.m_pGraphics = Graphics(); m_RenderTools.m_pUI = UI(); int64 Start = time_get(); // set the language g_Localization.Load(g_Config.m_ClLanguagefile, Storage(), Console()); // TODO: this should be different // setup item sizes for(int i = 0; i < NUM_NETOBJTYPES; i++) Client()->SnapSetStaticsize(i, m_NetObjHandler.GetObjSize(i)); // load default font static CFont *pDefaultFont = 0; char aFilename[512]; IOHANDLE File = Storage()->OpenFile("fonts/DejaVuSans.ttf", IOFLAG_READ, IStorage::TYPE_ALL, aFilename, sizeof(aFilename)); if(File) { io_close(File); pDefaultFont = TextRender()->LoadFont(aFilename); TextRender()->SetDefaultFont(pDefaultFont); } if(!pDefaultFont) Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "gameclient", "failed to load font. filename='fonts/DejaVuSans.ttf'"); // init all components for(int i = m_All.m_Num-1; i >= 0; --i) m_All.m_paComponents[i]->OnInit(); // setup load amount// load textures for(int i = 0; i < g_pData->m_NumImages; i++) { g_pData->m_aImages[i].m_Id = Graphics()->LoadTexture(g_pData->m_aImages[i].m_pFilename, IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0); g_GameClient.m_pMenus->RenderLoading(); } for(int i = 0; i < m_All.m_Num; i++) m_All.m_paComponents[i]->OnReset(); int64 End = time_get(); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "initialisation finished after %.2fms", ((End-Start)*1000)/(float)time_freq()); Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "gameclient", aBuf); m_ServerMode = SERVERMODE_PURE; m_DDRaceMsgSent = false; m_ShowOthers = -1; // Set free binds to DDRace binds if it's active if(!g_Config.m_ClDDRaceBindsSet && g_Config.m_ClDDRaceBinds) gs_Binds.SetDDRaceBinds(true); }
void CServerBrowser::Set(const NETADDR &Addr, int Type, int Token, const CServerInfo *pInfo) { static int temp = 0; CServerEntry *pEntry = 0; if(Type == IServerBrowser::SET_MASTER_ADD) { if(m_ServerlistType != IServerBrowser::TYPE_INTERNET) return; m_LastPacketTick = 0; ++temp; if(!Find(Addr)) { pEntry = Add(Addr); QueueRequest(pEntry); } } else if(Type == IServerBrowser::SET_FAV_ADD) { if(m_ServerlistType != IServerBrowser::TYPE_FAVORITES) return; if(!Find(Addr)) { pEntry = Add(Addr); QueueRequest(pEntry); } } else if(Type == IServerBrowser::SET_RECENT) { if(m_ServerlistType != IServerBrowser::TYPE_RECENT) return; if(!Find(Addr)) { pEntry = Add(Addr); QueueRequest(pEntry); } } else if(Type == IServerBrowser::SET_DDNET_ADD) { if(m_ServerlistType != IServerBrowser::TYPE_DDNET) return; if(!Find(Addr)) { pEntry = Add(Addr); QueueRequest(pEntry); } } else if(Type == IServerBrowser::SET_TOKEN) { if(Token != m_CurrentToken) return; pEntry = Find(Addr); if(!pEntry) pEntry = Add(Addr); if(pEntry) { SetInfo(pEntry, *pInfo); if (m_ServerlistType == IServerBrowser::TYPE_LAN) pEntry->m_Info.m_Latency = min(static_cast<int>((time_get()-m_BroadcastTime)*1000/time_freq()), 999); else if (pEntry->m_RequestTime > 0) { pEntry->m_Info.m_Latency = min(static_cast<int>((time_get()-pEntry->m_RequestTime)*1000/time_freq()), 999); pEntry->m_RequestTime = -1; // Request has been answered } RemoveRequest(pEntry); } } Sort(); }
void CServerBrowser::LoadCacheThread(void *pUser) { CServerBrowser *pSelf = (CServerBrowser *)pUser; IStorageTW *pStorage = pSelf->Kernel()->RequestInterface<IStorageTW>(); int64 StartTime = time_get(); // clear out everything pSelf->m_ServerlistHeap.Reset(); pSelf->m_NumServers = 0; pSelf->m_NumSortedServers = 0; mem_zero(pSelf->m_aServerlistIp, sizeof(pSelf->m_aServerlistIp)); pSelf->m_pFirstReqServer = 0; pSelf->m_pLastReqServer = 0; pSelf->m_NumRequests = 0; pSelf->m_CurrentMaxRequests = g_Config.m_BrMaxRequests; pSelf->m_CurrentToken = (pSelf->m_CurrentToken+1)&0xff; pSelf->m_ServerlistType = IServerBrowser::TYPE_INTERNET; // open file IOHANDLE File = pStorage->OpenFile("tmp/cache/serverlist", IOFLAG_READ, IStorageTW::TYPE_ALL); if(!File) { dbg_msg("browser", "opening cache file failed."); pSelf->m_CacheExists = false; pSelf->m_ServerdataLocked = false; return;// false; } // get version { char v; io_read(File, &v, 1); if(g_Config.m_Debug) dbg_msg("browser", "loading serverlist from cache..."); if(v != CACHE_VERSION) dbg_msg("cache", "file version doesn't match, we may fail! (%i != %i)", v, CACHE_VERSION); } // get number of servers int NumServers = 0; io_read(File, &NumServers, sizeof(NumServers)); //dbg_msg("browser", "serverlist cache entries: %i", NumServers); mem_zero(pSelf->m_ppServerlist, pSelf->m_NumServerCapacity); // get length of array io_read(File, &pSelf->m_NumServerCapacity, sizeof(pSelf->m_NumServerCapacity)); // get rid of current serverlist and create a new one mem_free(pSelf->m_ppServerlist); pSelf->m_ppServerlist = (CServerEntry **)mem_alloc(pSelf->m_NumServerCapacity*sizeof(CServerEntry*), 1); // read the data from the file into the serverlist CServerInfo *pServerInfos = (CServerInfo*)mem_alloc(sizeof(CServerInfo)*NumServers, 0); io_read(File, pServerInfos, sizeof(CServerInfo)*NumServers); io_close(File); for(int i = 0; i < NumServers; i++) { NETADDR Addr; net_addr_from_str(&Addr, pServerInfos[i].m_aAddress); //dbg_msg("browser", "loading %i %s %s", i, Info.m_aAddress, Info.m_aName); pSelf->Set(Addr, IServerBrowser::SET_TOKEN, pSelf->m_CurrentToken, &pServerInfos[i]); } mem_free(pServerInfos); if(g_Config.m_Debug) dbg_msg("browser", "successfully loaded serverlist cache with %i entries (total %i), took %.2fms", pSelf->m_NumServers, NumServers, ((time_get()-StartTime)*1000)/(float)time_freq()); // TODO: check if saving actually succeeded //m_NeedUpgrade = true; // disabled due to sending our ip out to the whole universe pSelf->m_ServerdataLocked = false; pSelf->Sort(true); return;// true; }
int CControls::SnapInput(int *pData) { static int64 LastSendTime = 0; bool Send = false; // update player state if(m_pClient->m_pChat->IsActive()) m_InputData.m_PlayerFlags = PLAYERFLAG_CHATTING; else if(m_pClient->m_pMenus->IsActive()) m_InputData.m_PlayerFlags = PLAYERFLAG_IN_MENU; else m_InputData.m_PlayerFlags = PLAYERFLAG_PLAYING; if(m_pClient->m_pScoreboard->Active()) m_InputData.m_PlayerFlags |= PLAYERFLAG_SCOREBOARD; if(m_LastData.m_PlayerFlags != m_InputData.m_PlayerFlags) Send = true; m_LastData.m_PlayerFlags = m_InputData.m_PlayerFlags; // we freeze the input if chat or menu is activated if(!(m_InputData.m_PlayerFlags&PLAYERFLAG_PLAYING)) { OnReset(); mem_copy(pData, &m_InputData, sizeof(m_InputData)); // send once a second just to be sure if(time_get() > LastSendTime + time_freq()) Send = true; } else { m_InputData.m_TargetX = (int)m_MousePos.x; m_InputData.m_TargetY = (int)m_MousePos.y; if(!m_InputData.m_TargetX && !m_InputData.m_TargetY) { m_InputData.m_TargetX = 1; m_MousePos.x = 1; } // set direction m_InputData.m_Direction = 0; if(m_InputDirectionLeft && !m_InputDirectionRight) m_InputData.m_Direction = -1; if(!m_InputDirectionLeft && m_InputDirectionRight) m_InputData.m_Direction = 1; // stress testing if(g_Config.m_DbgStress) { float t = Client()->LocalTime(); mem_zero(&m_InputData, sizeof(m_InputData)); m_InputData.m_Direction = ((int)t/2)&1; m_InputData.m_Jump = ((int)t); m_InputData.m_Fire = ((int)(t*10)); m_InputData.m_Hook = ((int)(t*2))&1; m_InputData.m_WantedWeapon = ((int)t)%NUM_WEAPONS; m_InputData.m_TargetX = (int)(sinf(t*3)*100.0f); m_InputData.m_TargetY = (int)(cosf(t*3)*100.0f); } // check if we need to send input if(m_InputData.m_Direction != m_LastData.m_Direction) Send = true; else if(m_InputData.m_Jump != m_LastData.m_Jump) Send = true; else if(m_InputData.m_Fire != m_LastData.m_Fire) Send = true; else if(m_InputData.m_Hook != m_LastData.m_Hook) Send = true; else if(m_InputData.m_WantedWeapon != m_LastData.m_WantedWeapon) Send = true; else if(m_InputData.m_NextWeapon != m_LastData.m_NextWeapon) Send = true; else if(m_InputData.m_PrevWeapon != m_LastData.m_PrevWeapon) Send = true; // send at at least 10hz if(time_get() > LastSendTime + time_freq()/25) Send = true; } Send = m_pClient->m_pBot->HandleInput(&m_InputData); m_MousePos.x = m_InputData.m_TargetX; m_MousePos.y = m_InputData.m_TargetY; // copy and return size m_LastData = m_InputData; if(!Send) return 0; LastSendTime = time_get(); mem_copy(pData, &m_InputData, sizeof(m_InputData)); return sizeof(m_InputData); }
void CServer::ProcessClientPacket(CNetChunk *pPacket) { int ClientID = pPacket->m_ClientID; CUnpacker Unpacker; Unpacker.Reset(pPacket->m_pData, pPacket->m_DataSize); // unpack msgid and system flag int Msg = Unpacker.GetInt(); int Sys = Msg&1; Msg >>= 1; if(Unpacker.Error()) return; if(Sys) { // system message if(Msg == NETMSG_INFO) { if(m_aClients[ClientID].m_State == CClient::STATE_AUTH) { char aVersion[64]; str_copy(aVersion, Unpacker.GetString(CUnpacker::SANITIZE_CC), 64); bool CustClt = str_comp(aVersion, GameServer()->NetVersionCust()) == 0; dbg_msg("es", "%s client connected!", CustClt?"cust":"vanilla"); if(!CustClt && str_comp(aVersion, GameServer()->NetVersion()) != 0) { // wrong version char aReason[256]; str_format(aReason, sizeof(aReason), "Wrong version. Server is running '%s' and client '%s'", GameServer()->NetVersion(), aVersion); m_NetServer.Drop(ClientID, aReason); return; } const char *pPassword = Unpacker.GetString(CUnpacker::SANITIZE_CC); if(g_Config.m_Password[0] != 0 && str_comp(g_Config.m_Password, pPassword) != 0) { // wrong password m_NetServer.Drop(ClientID, "Wrong password"); return; } m_aClients[ClientID].m_State = CClient::STATE_CONNECTING; m_aClients[ClientID].m_CustClt = CustClt; SendMap(ClientID); } } else if(Msg == NETMSG_REQUEST_MAP_DATA) { int Chunk = Unpacker.GetInt(); int ChunkSize = 1024-128; int Offset = Chunk * ChunkSize; int Last = 0; // drop faulty map data requests if(Chunk < 0 || Offset > m_CurrentMapSize) return; if(Offset+ChunkSize >= m_CurrentMapSize) { ChunkSize = m_CurrentMapSize-Offset; if(ChunkSize < 0) ChunkSize = 0; Last = 1; } CMsgPacker Msg(NETMSG_MAP_DATA); Msg.AddInt(Last); Msg.AddInt(m_CurrentMapCrc); Msg.AddInt(Chunk); Msg.AddInt(ChunkSize); Msg.AddRaw(&m_pCurrentMapData[Offset], ChunkSize); SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH, ClientID, true); if(g_Config.m_Debug) { char aBuf[256]; str_format(aBuf, sizeof(aBuf), "sending chunk %d with size %d", Chunk, ChunkSize); Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "server", aBuf); } } else if(Msg == NETMSG_READY) { if(m_aClients[ClientID].m_State == CClient::STATE_CONNECTING) { char aAddrStr[NETADDR_MAXSTRSIZE]; net_addr_str(m_NetServer.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "player is ready. ClientID=%x addr=%s", ClientID, aAddrStr); Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf); m_aClients[ClientID].m_State = CClient::STATE_READY; GameServer()->OnClientConnected(ClientID); SendConnectionReady(ClientID); } } else if(Msg == NETMSG_ENTERGAME) { if(m_aClients[ClientID].m_State == CClient::STATE_READY && GameServer()->IsClientReady(ClientID)) { char aAddrStr[NETADDR_MAXSTRSIZE]; net_addr_str(m_NetServer.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "player has entered the game. ClientID=%x addr=%s", ClientID, aAddrStr); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); m_aClients[ClientID].m_State = CClient::STATE_INGAME; GameServer()->OnClientEnter(ClientID); } } else if(Msg == NETMSG_INPUT) { CClient::CInput *pInput; int64 TagTime; m_aClients[ClientID].m_LastAckedSnapshot = Unpacker.GetInt(); int IntendedTick = Unpacker.GetInt(); int Size = Unpacker.GetInt(); // check for errors if(Unpacker.Error() || Size/4 > MAX_INPUT_SIZE) return; if(m_aClients[ClientID].m_LastAckedSnapshot > 0) m_aClients[ClientID].m_SnapRate = CClient::SNAPRATE_FULL; if(m_aClients[ClientID].m_Snapshots.Get(m_aClients[ClientID].m_LastAckedSnapshot, &TagTime, 0, 0) >= 0) m_aClients[ClientID].m_Latency = (int)(((time_get()-TagTime)*1000)/time_freq()); // add message to report the input timing // skip packets that are old if(IntendedTick > m_aClients[ClientID].m_LastInputTick) { int TimeLeft = ((TickStartTime(IntendedTick)-time_get())*1000) / time_freq(); CMsgPacker Msg(NETMSG_INPUTTIMING); Msg.AddInt(IntendedTick); Msg.AddInt(TimeLeft); SendMsgEx(&Msg, 0, ClientID, true); } m_aClients[ClientID].m_LastInputTick = IntendedTick; pInput = &m_aClients[ClientID].m_aInputs[m_aClients[ClientID].m_CurrentInput]; if(IntendedTick <= Tick()) IntendedTick = Tick()+1; pInput->m_GameTick = IntendedTick; for(int i = 0; i < Size/4; i++) pInput->m_aData[i] = Unpacker.GetInt(); mem_copy(m_aClients[ClientID].m_LatestInput.m_aData, pInput->m_aData, MAX_INPUT_SIZE*sizeof(int)); m_aClients[ClientID].m_CurrentInput++; m_aClients[ClientID].m_CurrentInput %= 200; // call the mod with the fresh input data if(m_aClients[ClientID].m_State == CClient::STATE_INGAME) GameServer()->OnClientDirectInput(ClientID, m_aClients[ClientID].m_LatestInput.m_aData); } else if(Msg == NETMSG_RCON_CMD) { const char *pCmd = Unpacker.GetString(); if(Unpacker.Error() == 0 && m_aClients[ClientID].m_Authed) { char aBuf[256]; str_format(aBuf, sizeof(aBuf), "ClientID=%d rcon='%s'", ClientID, pCmd); Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf); m_RconClientID = ClientID; m_RconAuthLevel = m_aClients[ClientID].m_Authed; Console()->SetAccessLevel(m_aClients[ClientID].m_Authed == AUTHED_ADMIN ? IConsole::ACCESS_LEVEL_ADMIN : IConsole::ACCESS_LEVEL_MOD); Console()->ExecuteLineFlag(pCmd, CFGFLAG_SERVER); Console()->SetAccessLevel(IConsole::ACCESS_LEVEL_ADMIN); m_RconClientID = IServer::RCON_CID_SERV; m_RconAuthLevel = AUTHED_ADMIN; } } else if(Msg == NETMSG_RCON_AUTH) { const char *pPw; Unpacker.GetString(); // login name, not used pPw = Unpacker.GetString(CUnpacker::SANITIZE_CC); if(Unpacker.Error() == 0) { if(g_Config.m_SvRconPassword[0] == 0 && g_Config.m_SvRconModPassword[0] == 0) { SendRconLine(ClientID, "No rcon password set on server. Set sv_rcon_password and/or sv_rcon_mod_password to enable the remote console."); } else if(g_Config.m_SvRconPassword[0] && str_comp(pPw, g_Config.m_SvRconPassword) == 0) { CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS); Msg.AddInt(1); //authed Msg.AddInt(1); //cmdlist SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); m_aClients[ClientID].m_Authed = AUTHED_ADMIN; int SendRconCmds = Unpacker.GetInt(); if(Unpacker.Error() == 0 && SendRconCmds) m_aClients[ClientID].m_pRconCmdToSend = Console()->FirstCommandInfo(IConsole::ACCESS_LEVEL_ADMIN, CFGFLAG_SERVER); SendRconLine(ClientID, "Admin authentication successful. Full remote console access granted."); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (admin)", ClientID); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); } else if(g_Config.m_SvRconModPassword[0] && str_comp(pPw, g_Config.m_SvRconModPassword) == 0) { CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS); Msg.AddInt(1); //authed Msg.AddInt(1); //cmdlist SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); m_aClients[ClientID].m_Authed = AUTHED_MOD; int SendRconCmds = Unpacker.GetInt(); if(Unpacker.Error() == 0 && SendRconCmds) m_aClients[ClientID].m_pRconCmdToSend = Console()->FirstCommandInfo(IConsole::ACCESS_LEVEL_MOD, CFGFLAG_SERVER); SendRconLine(ClientID, "Moderator authentication successful. Limited remote console access granted."); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (moderator)", ClientID); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); } else if(g_Config.m_SvRconMaxTries) { m_aClients[ClientID].m_AuthTries++; char aBuf[128]; str_format(aBuf, sizeof(aBuf), "Wrong password %d/%d.", m_aClients[ClientID].m_AuthTries, g_Config.m_SvRconMaxTries); SendRconLine(ClientID, aBuf); if(m_aClients[ClientID].m_AuthTries >= g_Config.m_SvRconMaxTries) { if(!g_Config.m_SvRconBantime) m_NetServer.Drop(ClientID, "Too many remote console authentication tries"); else m_ServerBan.BanAddr(m_NetServer.ClientAddr(ClientID), g_Config.m_SvRconBantime*60, "Too many remote console authentication tries"); } } else { SendRconLine(ClientID, "Wrong password."); } } } else if(Msg == NETMSG_PING) { CMsgPacker Msg(NETMSG_PING_REPLY); SendMsgEx(&Msg, 0, ClientID, true); } else { if(g_Config.m_Debug) { char aHex[] = "0123456789ABCDEF"; char aBuf[512]; for(int b = 0; b < pPacket->m_DataSize && b < 32; b++) { aBuf[b*3] = aHex[((const unsigned char *)pPacket->m_pData)[b]>>4]; aBuf[b*3+1] = aHex[((const unsigned char *)pPacket->m_pData)[b]&0xf]; aBuf[b*3+2] = ' '; aBuf[b*3+3] = 0; } char aBufMsg[256]; str_format(aBufMsg, sizeof(aBufMsg), "strange message ClientID=%d msg=%d data_size=%d", ClientID, Msg, pPacket->m_DataSize); Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "server", aBufMsg); Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "server", aBuf); } } }
int64 CServer::TickStartTime(int Tick) { return m_GameStartTime + (time_freq()*Tick)/SERVER_TICK_SPEED; }
int CControls::SnapInput(int *pData) { static int64 LastSendTime = 0; bool Send = false; // update player state if(m_pClient->m_pChat->IsActive()) m_InputData[g_Config.m_ClDummy].m_PlayerFlags = PLAYERFLAG_CHATTING; else if(m_pClient->m_pMenus->IsActive()) m_InputData[g_Config.m_ClDummy].m_PlayerFlags = PLAYERFLAG_IN_MENU; else { if(m_InputData[g_Config.m_ClDummy].m_PlayerFlags == PLAYERFLAG_CHATTING) { CServerInfo Info; GameClient()->Client()->GetServerInfo(&Info); if(IsDDNet(&Info)) ResetInput(g_Config.m_ClDummy); } m_InputData[g_Config.m_ClDummy].m_PlayerFlags = PLAYERFLAG_PLAYING; } if(m_pClient->m_pScoreboard->Active()) m_InputData[g_Config.m_ClDummy].m_PlayerFlags |= PLAYERFLAG_SCOREBOARD; if(m_InputData[g_Config.m_ClDummy].m_PlayerFlags != PLAYERFLAG_PLAYING) m_JoystickTapTime = 0; // Do not launch hook on first tap if (m_pClient->m_pControls->m_ShowHookColl[g_Config.m_ClDummy]) m_InputData[g_Config.m_ClDummy].m_PlayerFlags |= PLAYERFLAG_AIM; if(m_LastData[g_Config.m_ClDummy].m_PlayerFlags != m_InputData[g_Config.m_ClDummy].m_PlayerFlags) Send = true; m_LastData[g_Config.m_ClDummy].m_PlayerFlags = m_InputData[g_Config.m_ClDummy].m_PlayerFlags; // we freeze the input if chat or menu is activated if(!(m_InputData[g_Config.m_ClDummy].m_PlayerFlags&PLAYERFLAG_PLAYING)) { CServerInfo Info; GameClient()->Client()->GetServerInfo(&Info); if(!IsDDNet(&Info)) ResetInput(g_Config.m_ClDummy); mem_copy(pData, &m_InputData[g_Config.m_ClDummy], sizeof(m_InputData[0])); // send once a second just to be sure if(time_get() > LastSendTime + time_freq()) Send = true; } else { m_InputData[g_Config.m_ClDummy].m_TargetX = (int)m_MousePos[g_Config.m_ClDummy].x; m_InputData[g_Config.m_ClDummy].m_TargetY = (int)m_MousePos[g_Config.m_ClDummy].y; if(!m_InputData[g_Config.m_ClDummy].m_TargetX && !m_InputData[g_Config.m_ClDummy].m_TargetY) { m_InputData[g_Config.m_ClDummy].m_TargetX = 1; m_MousePos[g_Config.m_ClDummy].x = 1; } // set direction m_InputData[g_Config.m_ClDummy].m_Direction = 0; if(m_InputDirectionLeft[g_Config.m_ClDummy] && !m_InputDirectionRight[g_Config.m_ClDummy]) m_InputData[g_Config.m_ClDummy].m_Direction = -1; if(!m_InputDirectionLeft[g_Config.m_ClDummy] && m_InputDirectionRight[g_Config.m_ClDummy]) m_InputData[g_Config.m_ClDummy].m_Direction = 1; // dummy copy moves if(g_Config.m_ClDummyCopyMoves) { CNetObj_PlayerInput *pDummyInput = &m_pClient->m_DummyInput; pDummyInput->m_Direction = m_InputData[g_Config.m_ClDummy].m_Direction; pDummyInput->m_Hook = m_InputData[g_Config.m_ClDummy].m_Hook; pDummyInput->m_Jump = m_InputData[g_Config.m_ClDummy].m_Jump; pDummyInput->m_PlayerFlags = m_InputData[g_Config.m_ClDummy].m_PlayerFlags; pDummyInput->m_TargetX = m_InputData[g_Config.m_ClDummy].m_TargetX; pDummyInput->m_TargetY = m_InputData[g_Config.m_ClDummy].m_TargetY; pDummyInput->m_WantedWeapon = m_InputData[g_Config.m_ClDummy].m_WantedWeapon; pDummyInput->m_Fire += m_InputData[g_Config.m_ClDummy].m_Fire - m_LastData[g_Config.m_ClDummy].m_Fire; pDummyInput->m_NextWeapon += m_InputData[g_Config.m_ClDummy].m_NextWeapon - m_LastData[g_Config.m_ClDummy].m_NextWeapon; pDummyInput->m_PrevWeapon += m_InputData[g_Config.m_ClDummy].m_PrevWeapon - m_LastData[g_Config.m_ClDummy].m_PrevWeapon; m_InputData[!g_Config.m_ClDummy] = *pDummyInput; } if(g_Config.m_ClDummyControl){ CNetObj_PlayerInput *pDummyInput = &m_pClient->m_DummyInput; pDummyInput->m_Jump = g_Config.m_ClDummyJump; pDummyInput->m_Fire = g_Config.m_ClDummyFire; pDummyInput->m_Hook = g_Config.m_ClDummyHook; } // stress testing #ifdef CONF_DEBUG if(g_Config.m_DbgStress) { float t = Client()->LocalTime(); mem_zero(&m_InputData[g_Config.m_ClDummy], sizeof(m_InputData[0])); m_InputData[g_Config.m_ClDummy].m_Direction = ((int)t/2)&1; m_InputData[g_Config.m_ClDummy].m_Jump = ((int)t); m_InputData[g_Config.m_ClDummy].m_Fire = ((int)(t*10)); m_InputData[g_Config.m_ClDummy].m_Hook = ((int)(t*2))&1; m_InputData[g_Config.m_ClDummy].m_WantedWeapon = ((int)t)%NUM_WEAPONS; m_InputData[g_Config.m_ClDummy].m_TargetX = (int)(sinf(t*3)*100.0f); m_InputData[g_Config.m_ClDummy].m_TargetY = (int)(cosf(t*3)*100.0f); } #endif // check if we need to send input if(m_InputData[g_Config.m_ClDummy].m_Direction != m_LastData[g_Config.m_ClDummy].m_Direction) Send = true; else if(m_InputData[g_Config.m_ClDummy].m_Jump != m_LastData[g_Config.m_ClDummy].m_Jump) Send = true; else if(m_InputData[g_Config.m_ClDummy].m_Fire != m_LastData[g_Config.m_ClDummy].m_Fire) Send = true; else if(m_InputData[g_Config.m_ClDummy].m_Hook != m_LastData[g_Config.m_ClDummy].m_Hook) Send = true; else if(m_InputData[g_Config.m_ClDummy].m_WantedWeapon != m_LastData[g_Config.m_ClDummy].m_WantedWeapon) Send = true; else if(m_InputData[g_Config.m_ClDummy].m_NextWeapon != m_LastData[g_Config.m_ClDummy].m_NextWeapon) Send = true; else if(m_InputData[g_Config.m_ClDummy].m_PrevWeapon != m_LastData[g_Config.m_ClDummy].m_PrevWeapon) Send = true; // send at at least 10hz if(time_get() > LastSendTime + time_freq()/25) Send = true; if(m_pClient->m_Snap.m_pLocalCharacter && m_pClient->m_Snap.m_pLocalCharacter->m_Weapon == WEAPON_NINJA && (m_InputData[g_Config.m_ClDummy].m_Direction || m_InputData[g_Config.m_ClDummy].m_Jump || m_InputData[g_Config.m_ClDummy].m_Hook)) Send = true; } // copy and return size m_LastData[g_Config.m_ClDummy] = m_InputData[g_Config.m_ClDummy]; if(!Send) return 0; LastSendTime = time_get(); mem_copy(pData, &m_InputData[g_Config.m_ClDummy], sizeof(m_InputData[0])); return sizeof(m_InputData[0]); }
void CControls::OnRender() { enum { JOYSTICK_RUN_DISTANCE = 65536 / 8, GAMEPAD_DEAD_ZONE = 65536 / 8, }; int64 CurTime = time_get(); bool FireWasPressed = false; if( m_Joystick ) { // Get input from left joystick int RunX = SDL_JoystickGetAxis(m_Joystick, LEFT_JOYSTICK_X); int RunY = SDL_JoystickGetAxis(m_Joystick, LEFT_JOYSTICK_Y); bool RunPressed = (RunX != 0 || RunY != 0); // Get input from right joystick int AimX = SDL_JoystickGetAxis(m_Joystick, SECOND_RIGHT_JOYSTICK_X); int AimY = SDL_JoystickGetAxis(m_Joystick, SECOND_RIGHT_JOYSTICK_Y); bool AimPressed = (AimX != 0 || AimY != 0); // Get input from another right joystick int HookX = SDL_JoystickGetAxis(m_Joystick, RIGHT_JOYSTICK_X); int HookY = SDL_JoystickGetAxis(m_Joystick, RIGHT_JOYSTICK_Y); bool HookPressed = (HookX != 0 || HookY != 0); if( m_JoystickRunPressed != RunPressed ) { if( RunPressed ) { if( m_JoystickTapTime + time_freq() > CurTime ) // Tap in less than 1 second to jump m_InputData[g_Config.m_ClDummy].m_Jump = 1; } else m_InputData[g_Config.m_ClDummy].m_Jump = 0; m_JoystickTapTime = CurTime; } m_JoystickRunPressed = RunPressed; if( RunPressed ) { m_InputDirectionLeft[g_Config.m_ClDummy] = (RunX < -JOYSTICK_RUN_DISTANCE); m_InputDirectionRight[g_Config.m_ClDummy] = (RunX > JOYSTICK_RUN_DISTANCE); } // Move 500ms in the same direction, to prevent speed bump when tapping if( !RunPressed && m_JoystickTapTime + time_freq() / 2 > CurTime ) { m_InputDirectionLeft[g_Config.m_ClDummy] = 0; m_InputDirectionRight[g_Config.m_ClDummy] = 0; } if( HookPressed ) { m_MousePos[g_Config.m_ClDummy] = vec2(HookX / 30, HookY / 30); ClampMousePos(); m_InputData[g_Config.m_ClDummy].m_Hook = 1; } else { m_InputData[g_Config.m_ClDummy].m_Hook = 0; } if( AimPressed ) { m_MousePos[g_Config.m_ClDummy] = vec2(AimX / 30, AimY / 30); ClampMousePos(); } if( AimPressed != m_JoystickFirePressed ) { // Fire when releasing joystick if( !AimPressed ) { m_InputData[g_Config.m_ClDummy].m_Fire ++; if( (bool)(m_InputData[g_Config.m_ClDummy].m_Fire % 2) != AimPressed ) m_InputData[g_Config.m_ClDummy].m_Fire ++; FireWasPressed = true; } } m_JoystickFirePressed = AimPressed; } if( m_Gamepad ) { // Get input from left joystick int RunX = SDL_JoystickGetAxis(m_Gamepad, LEFT_JOYSTICK_X); int RunY = SDL_JoystickGetAxis(m_Gamepad, LEFT_JOYSTICK_Y); if( m_UsingGamepad ) { m_InputDirectionLeft[g_Config.m_ClDummy] = (RunX < -GAMEPAD_DEAD_ZONE); m_InputDirectionRight[g_Config.m_ClDummy] = (RunX > GAMEPAD_DEAD_ZONE); } // Get input from right joystick int AimX = SDL_JoystickGetAxis(m_Gamepad, RIGHT_JOYSTICK_X); int AimY = SDL_JoystickGetAxis(m_Gamepad, RIGHT_JOYSTICK_Y); if( abs(AimX) > GAMEPAD_DEAD_ZONE || abs(AimY) > GAMEPAD_DEAD_ZONE ) { m_MousePos[g_Config.m_ClDummy] = vec2(AimX / 30, AimY / 30); ClampMousePos(); } if( !m_UsingGamepad && (abs(AimX) > GAMEPAD_DEAD_ZONE || abs(AimY) > GAMEPAD_DEAD_ZONE || abs(RunX) > GAMEPAD_DEAD_ZONE || abs(RunY) > GAMEPAD_DEAD_ZONE) ) { UI()->AndroidShowScreenKeys(false); m_UsingGamepad = true; } } CServerInfo Info; GameClient()->Client()->GetServerInfo(&Info); if( g_Config.m_ClAutoswitchWeaponsOutOfAmmo && !IsRace(&Info) && !IsDDRace(&Info) && m_pClient->m_Snap.m_pLocalCharacter ) { // Keep track of ammo count, we know weapon ammo only when we switch to that weapon, this is tracked on server and protocol does not track that m_AmmoCount[m_pClient->m_Snap.m_pLocalCharacter->m_Weapon%NUM_WEAPONS] = m_pClient->m_Snap.m_pLocalCharacter->m_AmmoCount; // Autoswitch weapon if we're out of ammo if( (m_InputData[g_Config.m_ClDummy].m_Fire % 2 != 0 || FireWasPressed) && m_pClient->m_Snap.m_pLocalCharacter->m_AmmoCount == 0 && m_pClient->m_Snap.m_pLocalCharacter->m_Weapon != WEAPON_HAMMER && m_pClient->m_Snap.m_pLocalCharacter->m_Weapon != WEAPON_NINJA ) { int w; for( w = WEAPON_RIFLE; w > WEAPON_GUN; w-- ) { if( w == m_pClient->m_Snap.m_pLocalCharacter->m_Weapon ) continue; if( m_AmmoCount[w] > 0 ) break; } if( w != m_pClient->m_Snap.m_pLocalCharacter->m_Weapon ) m_InputData[g_Config.m_ClDummy].m_WantedWeapon = w+1; } } // update target pos if(m_pClient->m_Snap.m_pGameInfoObj && !m_pClient->m_Snap.m_SpecInfo.m_Active) m_TargetPos[g_Config.m_ClDummy] = m_pClient->m_LocalCharacterPos + m_MousePos[g_Config.m_ClDummy]; else if(m_pClient->m_Snap.m_SpecInfo.m_Active && m_pClient->m_Snap.m_SpecInfo.m_UsePosition) m_TargetPos[g_Config.m_ClDummy] = m_pClient->m_Snap.m_SpecInfo.m_Position + m_MousePos[g_Config.m_ClDummy]; else m_TargetPos[g_Config.m_ClDummy] = m_MousePos[g_Config.m_ClDummy]; }