#define EXT_ACK -1 #define EXT_VERSION 105 #define EXT_NO_ERROR 0 #define EXT_ERROR 1 #define EXT_PLAYERSTATS_RESP_IDS -10 #define EXT_PLAYERSTATS_RESP_STATS -11 #define EXT_UPTIME 0 #define EXT_PLAYERSTATS 1 #define EXT_TEAMSCORE 2 /* Client: ----- A: 0 EXT_UPTIME B: 0 EXT_PLAYERSTATS cn #a client number or -1 for all players# C: 0 EXT_TEAMSCORE Server: -------- A: 0 EXT_UPTIME EXT_ACK EXT_VERSION uptime #in seconds# B: 0 EXT_PLAYERSTATS cn #send by client# EXT_ACK EXT_VERSION 0 or 1 #error, if cn was > -1 and client does not exist# ... EXT_PLAYERSTATS_RESP_IDS pid(s) #1 packet# EXT_PLAYERSTATS_RESP_STATS pid playerdata #1 packet for each player# C: 0 EXT_TEAMSCORE EXT_ACK EXT_VERSION 0 or 1 #error, no teammode# remaining_time gamemode loop(teamdata [numbases bases] or -1) Errors: -------------- B:C:default: 0 command EXT_ACK EXT_VERSION EXT_ERROR */ VAR(extinfoip, 0, 0, 1); void extinfoplayer(ucharbuf &p, clientinfo *ci) { ucharbuf q = p; putint(q, EXT_PLAYERSTATS_RESP_STATS); // send player stats following putint(q, ci->clientnum); //add player id putint(q, ci->ping); sendstring(ci->name, q); sendstring(teamname(m_teammode ? ci->team : 0), q); putint(q, ci->state.frags); putint(q, ci->state.flags); putint(q, ci->state.deaths); putint(q, ci->state.teamkills); putint(q, ci->state.damage*100/max(ci->state.shotdamage,1)); putint(q, ci->state.health); putint(q, 0); putint(q, ci->state.gunselect); putint(q, ci->privilege); putint(q, ci->state.state); uint ip = extinfoip ? getclientip(ci->clientnum) : 0; q.put((uchar*)&ip, 3); sendserverinforeply(q); } static inline void extinfoteamscore(ucharbuf &p, int team, int score) { sendstring(teamname(team), p); putint(p, score); if(!smode || !smode->extinfoteam(team, p)) putint(p,-1); //no bases follow } void extinfoteams(ucharbuf &p) { putint(p, m_teammode ? 0 : 1); putint(p, gamemode); putint(p, max((gamelimit - gamemillis)/1000, 0)); if(!m_teammode) return; vector scores; if(smode && smode->hidefrags()) smode->getteamscores(scores); loopv(clients) { clientinfo *ci = clients[i]; if(ci->state.state!=CS_SPECTATOR && validteam(ci->team) && scores.htfind(ci->team) < 0) { if(smode && smode->hidefrags()) scores.add(teamscore(ci->team, 0)); else { teaminfo &t = teaminfos[ci->team-1]; scores.add(teamscore(ci->team, t.frags)); } } } loopv(scores) extinfoteamscore(p, scores[i].team, scores[i].score); } void extserverinforeply(ucharbuf &req, ucharbuf &p) { int extcmd = getint(req); // extended commands //Build a new packet putint(p, EXT_ACK); //send ack putint(p, EXT_VERSION); //send version of extended info switch(extcmd) { case EXT_UPTIME: { putint(p, totalsecs); //in seconds break; } case EXT_PLAYERSTATS: { int cn = getint(req); //a special player, -1 for all clientinfo *ci = NULL; if(cn >= 0) { loopv(clients) if(clients[i]->clientnum == cn) { ci = clients[i]; break; } if(!ci) { putint(p, EXT_ERROR); //client requested by id was not found sendserverinforeply(p); return; } } putint(p, EXT_NO_ERROR); //so far no error can happen anymore ucharbuf q = p; //remember buffer position putint(q, EXT_PLAYERSTATS_RESP_IDS); //send player ids following if(ci) putint(q, ci->clientnum); else loopv(clients) putint(q, clients[i]->clientnum); sendserverinforeply(q); if(ci) extinfoplayer(p, ci); else loopv(clients) extinfoplayer(p, clients[i]); return; } case EXT_TEAMSCORE: { extinfoteams(p); break; } default: { putint(p, EXT_ERROR); break; } } sendserverinforeply(p); }