From b5ea3fc741e71779cfad52d4c0cb5c6bfb4c13f3 Mon Sep 17 00:00:00 2001 From: Rafael Barreto Date: Sun, 6 Jun 2010 20:41:07 +0000 Subject: [PATCH] more vote abuse control, and a new vote switch "W": allow or not "weak" kick/ban votes: when the player is not lagging, spamming, tking, or obviously cheating... git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@5152 e016b1c5-ed68-44aa-a2f7-31cac88cffde --- docs/commandline.html | 4 +++- source/src/protocol.cpp | 2 +- source/src/protocol.h | 2 +- source/src/server.cpp | 39 ++++++++++++++++++++++++++------------ source/src/server.h | 6 ++++-- source/src/serveractions.h | 2 +- source/src/serverchecks.h | 11 +++++++++-- 7 files changed, 46 insertions(+), 20 deletions(-) diff --git a/docs/commandline.html b/docs/commandline.html index 9240cdae..2494c845 100644 --- a/docs/commandline.html +++ b/docs/commandline.html @@ -553,11 +553,13 @@ vote for coopedit mode p vote for a gamemode that is not supported by the map (default: no one can) + w + vote to kick/ban for "weak" reasons, i.e, the other player is not obviously lagging, nor teamkilling, nor spamming, nor cheating (as far as the server can detect it) For example: -PbmA enables ban & mastermode to be voted by normal players but only admins can change autoteam. The '-P' parameter can be used several times on the commandline. For example, '-Pb -Pm -PA' is equivalent to '-PbmA'. - The default settings are: "fkBMasRCDE". + The default settings are: "fKBMasRCDEW". diff --git a/source/src/protocol.cpp b/source/src/protocol.cpp index e9b38511..388b6dc3 100644 --- a/source/src/protocol.cpp +++ b/source/src/protocol.cpp @@ -307,7 +307,7 @@ const char *modeacronymnames[] = "OSOK", "TOSOK", "BOSOK", "HTF", "TKTF", "KTF" }; -const char *voteerrors[] = { "voting is currently disabled", "there is already a vote pending", "already voted", "can't vote that often", "this vote is not allowed in the current environment (singleplayer/multiplayer)", "no permission", "invalid vote" }; +const char *voteerrors[] = { "voting is currently disabled", "there is already a vote pending", "already voted", "can't vote that often", "this vote is not allowed in the current environment (singleplayer/multiplayer)", "no permission", "invalid vote", "server denied your call" }; const char *mmfullnames[] = { "open", "private", "match" }; const char *fullmodestr(int n) { return (n>=-1 && size_t(n+1) < sizeof(modefullnames)/sizeof(modefullnames[0])) ? modefullnames[n+1] : "unknown"; } diff --git a/source/src/protocol.h b/source/src/protocol.h index f9cc685d..32665ca4 100644 --- a/source/src/protocol.h +++ b/source/src/protocol.h @@ -53,7 +53,7 @@ extern const char *messagenames[SV_NUM]; enum { SA_KICK = 0, SA_BAN, SA_REMBANS, SA_MASTERMODE, SA_AUTOTEAM, SA_FORCETEAM, SA_GIVEADMIN, SA_MAP, SA_RECORDDEMO, SA_STOPDEMO, SA_CLEARDEMOS, SA_SERVERDESC, SA_SHUFFLETEAMS, SA_NUM}; enum { VOTE_NEUTRAL = 0, VOTE_YES, VOTE_NO, VOTE_NUM }; -enum { VOTEE_DISABLED = 0, VOTEE_CUR, VOTEE_MUL, VOTEE_MAX, VOTEE_AREA, VOTEE_PERMISSION, VOTEE_INVALID, VOTEE_NUM }; +enum { VOTEE_DISABLED = 0, VOTEE_CUR, VOTEE_MUL, VOTEE_MAX, VOTEE_AREA, VOTEE_PERMISSION, VOTEE_INVALID, VOTEE_WEAK, VOTEE_NUM }; enum { MM_OPEN = 0, MM_PRIVATE, MM_MATCH, MM_NUM }; enum { MM_MASK = 0x03 }; enum { AT_DISABLED = 0, AT_ENABLED = 1, AT_SHUFFLE = 2, AT_NUM }; enum { FA_PICKUP = 0, FA_STEAL, FA_DROP, FA_LOST, FA_RETURN, FA_SCORE, FA_NUM, FA_RESET }; diff --git a/source/src/server.cpp b/source/src/server.cpp index 293a9cb8..e3a43dbd 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -1846,10 +1846,11 @@ void sendserveropinfo(int receiver) struct voteinfo { + bool boot; int owner, callmillis, result; serveraction *action; - voteinfo() : owner(0), callmillis(0), result(VOTE_NEUTRAL), action(NULL) {} + voteinfo() : boot(false), owner(0), callmillis(0), result(VOTE_NEUTRAL), action(NULL) {} ~voteinfo() { delete action; } void end(int result) @@ -1866,7 +1867,7 @@ struct voteinfo } bool isvalid() { return valid_client(owner) && action != NULL && action->isvalid(); } - bool isalive() { return servmillis - callmillis < 40*1000; } + bool isalive() { return servmillis - callmillis < 30*1000; } void evaluate(bool forceend = false) { @@ -1921,7 +1922,7 @@ void scallvotesuc(voteinfo *v) DELETEP(curvote); curvote = v; clients[v->owner]->lastvotecall = servmillis; - + clients[v->owner]->nvotes--; // successful votes do not count as abuse sendf(v->owner, 1, "ri", SV_CALLVOTESUC); logline(ACLOG_INFO, "[%s] client %s called a vote: %s", clients[v->owner]->hostname, clients[v->owner]->name, v->action->desc ? v->action->desc : "[unknown]"); } @@ -1937,14 +1938,25 @@ bool scallvote(voteinfo *v, ENetPacket *msg) // true if a regular vote was calle { int area = isdedicated ? EE_DED_SERV : EE_LOCAL_SERV; int error = -1; + client *c = clients[v->owner], *b = v->boot ? clients[cn2boot] : NULL; - if(!v || !v->isvalid()) error = VOTEE_INVALID; - else if(v->action->role > clients[v->owner]->role) error = VOTEE_PERMISSION; - else if(!(area & v->action->area)) error = VOTEE_AREA; - else if(curvote && curvote->result==VOTE_NEUTRAL) error = VOTEE_CUR; - else if(clients[v->owner]->role == CR_DEFAULT && v->action->isdisabled()) error = VOTEE_DISABLED; - else if(clients[v->owner]->lastvotecall && servmillis - clients[v->owner]->lastvotecall < 60*1000 && clients[v->owner]->role != CR_ADMIN && numclients()>1) - error = VOTEE_MAX; + int time = servmillis - c->lastvotecall; + if ( c->nvotes > 0 && time > 4*60*1000 ) c->nvotes -= time/(4*60*1000); + if ( c->nvotes < 0 ) c->nvotes = 0; + c->nvotes++; + + if( !v || !v->isvalid() || (v->boot && !b) ) error = VOTEE_INVALID; + else if( v->action->role > c->role ) error = VOTEE_PERMISSION; + else if( !(area & v->action->area) ) error = VOTEE_AREA; + else if( curvote && curvote->result==VOTE_NEUTRAL ) error = VOTEE_CUR; + else if( c->role == CR_DEFAULT && v->action->isdisabled() ) error = VOTEE_DISABLED; + else if( (c->lastvotecall && servmillis - c->lastvotecall < 60*1000 && c->role != CR_ADMIN && numclients()>1) || c->nvotes > 3 ) error = VOTEE_MAX; + else if( c->role < roleconf('W') && v->boot == true && !is_lagging(b) && !b->mute && b->spamcount < 2 ) { + /** not same team, with low ratio, not lagging, and not spamming... so, why to kick? */ + if ( !isteam(c->team, b->team) && b->state.frags < ( b->state.deaths ? b->state.deaths : 1 ) * 5 ) error = VOTEE_WEAK; + /** same team, with low tk, not lagging, and not spamming... so, why to kick? */ + else if ( isteam(c->team, b->team) && b->state.teamkills <= c->state.teamkills ) error = VOTEE_WEAK; + } if(error>=0) { @@ -2756,7 +2768,7 @@ void process(ENetPacket *packet, int sender, int chan) while(curmsgposition.add(p.buf[curmsg++]); } if(maplayout && !m_demo && !m_coop) checkclientpos(cl); - checkmove(cn, val); + checkmove(cl, val); break; } @@ -2801,7 +2813,7 @@ void process(ENetPacket *packet, int sender, int chan) while(curmsgposition.add(p.buf[curmsg++]); } if(maplayout && !m_demo && !m_coop) checkclientpos(cl); - checkmove(cn, val); + checkmove(cl, val); break; } @@ -2931,6 +2943,7 @@ void process(ENetPacket *packet, int sender, int chan) case SV_CALLVOTE: { voteinfo *vi = new voteinfo; + vi->boot = false; int type = getint(p); switch(type) { @@ -2949,6 +2962,7 @@ void process(ENetPacket *packet, int sender, int chan) getstring(text, p); filtertext(text, text); vi->action = new kickaction(cn2boot, newstring(text)); + vi->boot = true; break; } case SA_BAN: @@ -2957,6 +2971,7 @@ void process(ENetPacket *packet, int sender, int chan) getstring(text, p); filtertext(text, text); vi->action = new banaction(cn2boot, newstring(text)); + vi->boot = true; break; } case SA_REMBANS: diff --git a/source/src/server.h b/source/src/server.h index e978cbf7..52f87eea 100644 --- a/source/src/server.h +++ b/source/src/server.h @@ -226,7 +226,7 @@ struct client // server side version of "dynent" type int skin[2]; int vote; int role; - int connectmillis; + int connectmillis, lmillis, ldt, spj; int mute, spam, lastvc; // server side voice comm spam control int acversion, acbuildtype; bool isauthed; // for passworded servers @@ -253,6 +253,7 @@ struct client // server side version of "dynent" type medals md; bool upspawnp; vec spawnp; + int nvotes; gameevent &addevent() { @@ -281,6 +282,7 @@ struct client // server side version of "dynent" type md.reset(); upspawnp = false; spawnp = vec(-1e10f, -1e10f, -1e10f); + lmillis = ldt = spj = 0; } void reset() @@ -301,7 +303,7 @@ struct client // server side version of "dynent" type spectcn = FPCN_VOID; mapchange(); freshgame = false; // don't spawn into running games - mute = spam = lastvc = badspeech = badmillis = 0; + mute = spam = lastvc = badspeech = badmillis = nvotes = 0; } void zap() diff --git a/source/src/serveractions.h b/source/src/serveractions.h index 07a37cd6..4343c2d6 100644 --- a/source/src/serveractions.h +++ b/source/src/serveractions.h @@ -3,7 +3,7 @@ enum { EE_LOCAL_SERV = 1, EE_DED_SERV = 1<<1 }; // execution environment int roleconf(int key) -{ // current defaults: "fGkBMasRCDE" +{ // current defaults: "fGkBMasRCDEW" if(strchr(scl.voteperm, tolower(key))) return CR_DEFAULT; if(strchr(scl.voteperm, toupper(key))) return CR_ADMIN; return (key) == tolower(key) ? CR_DEFAULT : CR_ADMIN; diff --git a/source/src/serverchecks.h b/source/src/serverchecks.h index cb00f28f..a20ad2af 100644 --- a/source/src/serverchecks.h +++ b/source/src/serverchecks.h @@ -452,6 +452,10 @@ void checkfrag (client *target, client *actor, int gun, bool gib) } } +inline bool is_lagging(client *cl) +{ + return ( cl->spj > 80 || gamemillis - cl->lmillis > 400 ); +} /** If you read README.txt you must know that AC does not have cheat protection implemented. @@ -469,9 +473,12 @@ This part is here for compatibility purposes. If you know nothing about these detections, please, just ignore it. */ -inline void checkmove (int cn, int *v) +inline void checkmove (client *cl, int *v) { - client *cl = clients[cn]; + cl->ldt = gamemillis - cl->lmillis; + cl->lmillis = gamemillis; + if ( cl->ldt < 30 ) cl->ldt = 30; + cl->spj = (( 7 * cl->spj + cl->ldt ) >> 3); if ( !cl->upspawnp ) { cl->spawnp = cl->state.o; cl->upspawnp = true;