diff --git a/src/mod/remod.cpp b/src/mod/remod.cpp index 097355bf..26408f58 100644 --- a/src/mod/remod.cpp +++ b/src/mod/remod.cpp @@ -8,8 +8,8 @@ #include "commandev.h" -#include "remod.h" -#include "banlist.h" +#include "remod.h" +#include "banlist.h" EXTENSION(REMOD); @@ -62,7 +62,7 @@ struct sleepcmd vector asleepcmds; extern int identflags; -remod::banlist::banmanager *bm = new remod::banlist::banmanager; +remod::banlist::banmanager *bm = new remod::banlist::banmanager; void addasleep(int *msec, char *cmd) { @@ -130,11 +130,11 @@ namespace server { if (*c == '\"') { *c = '\''; } } - } - - bool checkpban(uint ip) - { - return bm->checkban(ip); + } + + bool checkpban(uint ip) + { + return bm->checkban(ip); } // remod implementation of addban @@ -166,14 +166,14 @@ namespace server loopv(bannedips) if(b.expire < bannedips[i].expire) { bannedips.insert(i, b); return; } bannedips.add(b); } - } - - void addpban(char *name, const char *reason) - { - enet_uint32 ip, mask; - bm->parseipstring(name, ip, mask); - bm->addban(NULL, ip, mask, 0, time(0), "server", reason); - + } + + void addpban(char *name, const char *reason) + { + enet_uint32 ip, mask; + bm->parseipstring(name, ip, mask); + bm->addban(NULL, ip, mask, 0, time(0), "server", reason); + loopvrev(clients) { clientinfo *ci = clients[i]; @@ -183,44 +183,44 @@ namespace server remod::oneventi(ONKICK, "ii", -1, ci->clientnum); disconnect_client(ci->clientnum, DISC_IPBAN); } - } - } - - /* - void addpban(char *name, const char *reason) - { - - union - { - uchar b[sizeof(enet_uint32)]; - enet_uint32 i; - } ip, mask; + } + } + + /* + void addpban(char *name, const char *reason) + { + + union + { + uchar b[sizeof(enet_uint32)]; + enet_uint32 i; + } ip, mask; ip.i = 0; - mask.i = 0; - char *next = name; - int n; - - if(*next) + mask.i = 0; + char *next = name; + int n; + + if(*next) loopi(4) { - n = strtol(next, &next, 10); - ip.b[i] = n; + n = strtol(next, &next, 10); + ip.b[i] = n; mask.b[i] = 0xFF; - if(*next && *next == '.') next++; + if(*next && *next == '.') next++; if(!*next || *next == '/') break; - } - - // CIDR - if(*next && *next == '/' && next++) - { - n = strtol(next, NULL, 10); - conoutf("next = %s, n = %i", next, n); - mask.i = ~0; - mask.i <<= (32-n); - mask.i = htonl(mask.i); - } - - // add ban and kick banned + } + + // CIDR + if(*next && *next == '/' && next++) + { + n = strtol(next, NULL, 10); + conoutf("next = %s, n = %i", next, n); + mask.i = ~0; + mask.i <<= (32-n); + mask.i = htonl(mask.i); + } + + // add ban and kick banned allowedips.removeobj(ip.i); permban b; @@ -239,12 +239,12 @@ namespace server remod::oneventi(ONKICK, "ii", -1, ci->clientnum); disconnect_client(ci->clientnum, DISC_IPBAN); } - } - - + } + + }*/ } - + namespace remod { @@ -252,30 +252,30 @@ namespace remod using namespace server; void extstate::reset() -{ - // don't reset vars on map change +{ + // don't reset vars on map change /* - muted = false; - ghost = false; - - lastmutetrigger= 0; - lastghosttrigger = 0; - */ - - suicides = 0; + muted = false; + ghost = false; + + lastmutetrigger= 0; + lastghosttrigger = 0; + */ + + suicides = 0; loopi(NUMGUNS) { guninfo[i].damage = 0; guninfo[i].shotdamage = 0; - } - - loopi(NUMFLOOD) - { - flood[i].floodlimit = 0; - flood[i].lastevent = 0; - flood[i].lastwarning = 0; - flood[i].strikes = 0; + } + + loopi(NUMFLOOD) + { + flood[i].floodlimit = 0; + flood[i].lastevent = 0; + flood[i].lastwarning = 0; + flood[i].strikes = 0; } } @@ -429,35 +429,35 @@ void writebans() ip.i = b.ip; maskedip[0] = '\0'; - // generate masked ip (ex. 234.345.45.2/32) - enet_uint32 tmsk = ntohl(b.mask); - int cidrmsk = 0; - while(tmsk) - { - tmsk <<= 1; - cidrmsk++; - } + // generate masked ip (ex. 234.345.45.2/32) + enet_uint32 tmsk = ntohl(b.mask); + int cidrmsk = 0; + while(tmsk) + { + tmsk <<= 1; + cidrmsk++; + } formatstring(maskedip, "%i.%i.%i.%i/%i", ip.b[0], ip.b[1], ip.b[2], ip.b[3], cidrmsk); f->printf("permban %s \"%s\"\n", maskedip, b.reason); - } - */ - loopv(bm->localbanlist()->bans) - { - remod::banlist::baninfo *b = bm->localbanlist()->bans[i]; - maskedip[0] = '\0'; - - // generate masked ip (ex. 234.345.45.2/32) - enet_uint32 tmsk = ntohl(b->mask); - int cidrmsk = 0; - while(tmsk) - { - tmsk <<= 1; - cidrmsk++; - } - formatstring(maskedip, "%i.%i.%i.%i/%i", b->ipoctet[0], b->ipoctet[1], b->ipoctet[2], b->ipoctet[3], cidrmsk); - f->printf("permban %s \"%s\"\n", maskedip, b->reason); - } + } + */ + loopv(bm->localbanlist()->bans) + { + remod::banlist::baninfo *b = bm->localbanlist()->bans[i]; + maskedip[0] = '\0'; + + // generate masked ip (ex. 234.345.45.2/32) + enet_uint32 tmsk = ntohl(b->mask); + int cidrmsk = 0; + while(tmsk) + { + tmsk <<= 1; + cidrmsk++; + } + formatstring(maskedip, "%i.%i.%i.%i/%i", b->ipoctet[0], b->ipoctet[1], b->ipoctet[2], b->ipoctet[3], cidrmsk); + f->printf("permban %s \"%s\"\n", maskedip, b->reason); + } f->close(); } @@ -477,9 +477,9 @@ void writebans() // (c) 2011 Thomas bool loadents(const char *fname, vector &ents, uint *crc) { - string mapname, ogzname, entsname; - copystring(mapname, fname, 100); - cutogz(mapname); + string ogzname, entsname; + char * mapname = newstring(fname); + fixmapname(mapname); formatstring(ogzname, "%s/%s.ogz", remod::mapdir, mapname); formatstring(entsname, "%s/%s.ents", remod::mapdir, mapname); path(ogzname); @@ -646,377 +646,377 @@ int getwepaccuracy(int cn, int gun) if(ci && gun>0 && gun<=NUMGUNS) acc = ci->state.ext.guninfo[gun].damage*100/max(ci->state.ext.guninfo[gun].shotdamage, 1); return(acc); -} - -// current mutemode -VAR(mutemode, 0, 0, NUMMUTEMODE-1); - -// return 1 if player can't talk, 0 if allowed -bool checkmutemode(clientinfo *ci) -{ - bool muted = false; - switch(mutemode) - { - case MUTEMODE_SPECS: - { - if(ci->state.state == CS_SPECTATOR && !ci->privilege) - { - muted = true; - } - break; - } - case MUTEMODE_PLAYERS: - { - if(!ci->privilege) - { - muted = true; - } - break; - } - case MUTEMODE_MASTERS: - { - if(ci->privilege != PRIV_ADMIN) - { - muted = true; - } - break; - } - - case MUTEMODE_NONE: - default: - break; - } - return muted; -} - -// delay in seconds before unpause game -VAR(resumedelay, 0, 0, 100); - -int resumetime; -_VAR(resumetimer, resumetimer, 0, 0, 1, IDF_READONLY); -void pausegame(bool val, clientinfo *ci) -{ - // pause game if val = 1 - if(val) - { - resumetimer = 0; - server::pausegame(val, ci); - } - else - { - if(resumedelay == 0) - { - server::pausegame(val, ci); - return; - } - - if(resumetimer || !server::gamepaused) return; - - // start resume game counter - resumetime = totalmillis + resumedelay*1000; - resumetimer = 1; - onevent(ONRESUMEGAME, "i", ci ? ci->clientnum : -1); - } -} - -void checkresume() -{ - if(!server::gamepaused || (resumetimer == 0)) return; - - // unpause game - if(resumetime <= totalmillis) - { - resumetimer = 0; - server::pausegame(false); - } -} - -int getteamscore(const char *team) -{ - int score = 0; - if(smode && smode->hidefrags()) - { - score = smode->getteamscore(team); - } - else - { - loopv(clients) - if(clients[i]->state.state != CS_SPECTATOR && clients[i]->team[0]) - { - clientinfo *ci = clients[i]; - if(ci && (strcmp(team, ci->team) == 0)) - score += ci->state.frags; - } - } - return score; -} - -bool isteamsequalscore() -{ - int goodscore = getteamscore("good"); - int evilscore = getteamscore("evil"); - return (goodscore == evilscore); -} - -void rename(int cn, const char* name) -{ - // don't rename bots - if(cn < 0 || cn >= 128) return; - - clientinfo *ci = (clientinfo *)getinfo(cn); - - // invalid cn or empty new name - if(!ci || name == NULL || name[0] == 0) return; - - char newname[MAXNAMELEN + 1]; - newname[MAXNAMELEN] = 0; - filtertext(newname, name, false, MAXNAMELEN); - - putuint(ci->messages, N_SWITCHNAME); - sendstring(newname, ci->messages); - - vector buf; - putuint(buf, N_SWITCHNAME); - sendstring(newname, buf); - - packetbuf p(MAXTRANS, ENET_PACKET_FLAG_RELIABLE); - putuint(p, N_CLIENT); - putint(p, ci->clientnum); - putint(p, buf.length()); - p.put(buf.getbuf(), buf.length()); - sendpacket(ci->clientnum, 1, p.finalize(), -1); - - string oldname; - copystring(oldname, ci->name); - copystring(ci->name, newname); - - remod::onevent(ONSWITCHNAME, "iss", ci->clientnum, ci->name, oldname); -} - -static void freegetmap(ENetPacket *packet) -{ - loopv(clients) - { - clientinfo *ci = clients[i]; - if(ci->getmap == packet) ci->getmap = NULL; - } -} - -void sendmapto(int cn) -{ - clientinfo *ci = (clientinfo *)getinfo(cn); - if(!ci || !m_edit) return; - - if(!mapdata) conoutf("no map to send to %s(%i)", ci->name, cn); - else if(ci->getmap) conoutf("already sending map to %s(%i)", ci->name, cn); - else - { - // remod - remod::onevent(ONGETMAP, "i", cn); - - sendservmsgf("[%s is getting the map]", colorname(ci)); - if((ci->getmap = sendfile(cn, 2, mapdata, "ri", N_SENDMAP))) - ci->getmap->freeCallback = freegetmap; - ci->needclipboard = totalmillis ? totalmillis : 1; - } -} - -bool iseditcommand(int type) -{ - switch(type) - { - case N_EDITF: - case N_EDITT: - case N_EDITM: - case N_FLIP: - case N_COPY: - case N_PASTE: - case N_ROTATE: - case N_REPLACE: - case N_DELCUBE: - case N_REMIP: - case N_SENDMAP: - return true; - - default: - return false; - } -} - -void ghost(int cn, bool v) -{ - clientinfo *ci = getinfo(cn); - if(!ci) return; - ci->state.ext.ghost = v; - onevent(ONGHOST, "ii", cn, v ? 1 : 0); -} - -// Red Eclipse (c) -bool filterstring(char *dst, const char *src, bool newline, bool colour, bool whitespace, bool wsstrip, size_t len) -{ - bool filtered = false; - size_t n = 0; - for(int c = uchar(*src); c && n <= len; c = uchar(*++src)) - { - if(newline && (c=='\n' || c=='\r')) c = ' '; - if(c=='\f') - { - if(!colour) dst[n++] = c; - else - { - filtered = true; - c = *++src; - if(!c) break; - else if(c=='z') - { - c = *++src; - if(c) c = *++src; - if(!c) break; - } - else if(c == '[' || c == '(' || c == '{') - { - const char *end = strchr(src, c == '[' ? ']' : (c == '(' ? ')' : '}')); - src += end ? end-src : strlen(src); - } - - } - continue; - } - if(iscubeprint(c) || (iscubespace(c) && whitespace && (!wsstrip || n))) - dst[n++] = c; - else filtered = true; - } - if(whitespace && wsstrip && n) while(iscubespace(dst[n-1])) dst[--n] = 0; - dst[n <= len ? n : len] = 0; - return filtered; -} - -// to keep irc colors work -size_t old_encodeutf8(uchar *dstbuf, size_t dstlen, const uchar *srcbuf, size_t srclen, size_t *carry) -{ - uchar *dst = dstbuf, *dstend = &dstbuf[dstlen]; - const uchar *src = srcbuf, *srcend = &srcbuf[srclen]; - if(src < srcend && dst < dstend) do - { - int uni = cube2uni(*src); - if(uni <= 0x7F) - { - if(dst >= dstend) goto done; - const uchar *end = min(srcend, &src[dstend-dst]); - do - { - *dst++ = uni; - if(++src >= end) goto done; - uni = cube2uni(*src); - } - while(uni <= 0x7F); - } - if(uni <= 0x7FF) { if(dst + 2 > dstend) goto done; *dst++ = 0xC0 | (uni>>6); goto uni2; } - else if(uni <= 0xFFFF) { if(dst + 3 > dstend) goto done; *dst++ = 0xE0 | (uni>>12); goto uni3; } - else if(uni <= 0x1FFFFF) { if(dst + 4 > dstend) goto done; *dst++ = 0xF0 | (uni>>18); goto uni4; } - else if(uni <= 0x3FFFFFF) { if(dst + 5 > dstend) goto done; *dst++ = 0xF8 | (uni>>24); goto uni5; } - else if(uni <= 0x7FFFFFFF) { if(dst + 6 > dstend) goto done; *dst++ = 0xFC | (uni>>30); goto uni6; } - else goto uni1; - uni6: *dst++ = 0x80 | ((uni>>24)&0x3F); - uni5: *dst++ = 0x80 | ((uni>>18)&0x3F); - uni4: *dst++ = 0x80 | ((uni>>12)&0x3F); - uni3: *dst++ = 0x80 | ((uni>>6)&0x3F); - uni2: *dst++ = 0x80 | (uni&0x3F); - uni1:; - } - while(++src < srcend); - -done: - if(carry) *carry += src - srcbuf; - return dst - dstbuf; -} - // networkmessage to flood message type - inline size_t floodtype(int type) - { - size_t flood = FLOOD_OTHER; - switch(type) - { - case N_SAYTEAM: - case N_TEXT: - flood = FLOOD_TEXT; - break; - - case N_SWITCHNAME: - flood = FLOOD_SWITCHNAME; - break; - - case N_SWITCHTEAM: - flood = FLOOD_SWITCHTEAM; - break; - - case N_EDITVAR: - flood = FLOOD_EDITVAR; - break; - - default: - break; - } - return flood; - } - - #define FLOODDELAY 500 - #define STRIKELIMIT 5 - #define FLOODMUTE 10000 - #define FLOODTRIGGERTIME 10000 - bool checkflood(clientinfo *ci, int type) - { - bool isflood = false; - size_t floodmsg = floodtype(type); - floodstate &fs = ci->state.ext.flood[floodmsg]; - - // if faster than limit - if((totalmillis - fs.lastevent) < FLOODDELAY) { - fs.strikes++; - } - - // strike limit is reached, ignore next events - if(fs.strikes >= STRIKELIMIT) - { - fs.floodlimit = totalmillis + FLOODMUTE; - fs.strikes = 0; - } - - // if client is flooder - if((totalmillis - fs.floodlimit) < 0) - { - isflood = true; - if((totalmillis - fs.lastwarning) > FLOODTRIGGERTIME) { - fs.lastwarning = totalmillis; - remod::onevent(ONFLOOD, "ii", ci->clientnum, floodmsg); - } - } - fs.lastevent = totalmillis; - return isflood; - } - - void debugFlood() - { +} + +// current mutemode +VAR(mutemode, 0, 0, NUMMUTEMODE-1); + +// return 1 if player can't talk, 0 if allowed +bool checkmutemode(clientinfo *ci) +{ + bool muted = false; + switch(mutemode) + { + case MUTEMODE_SPECS: + { + if(ci->state.state == CS_SPECTATOR && !ci->privilege) + { + muted = true; + } + break; + } + case MUTEMODE_PLAYERS: + { + if(!ci->privilege) + { + muted = true; + } + break; + } + case MUTEMODE_MASTERS: + { + if(ci->privilege != PRIV_ADMIN) + { + muted = true; + } + break; + } + + case MUTEMODE_NONE: + default: + break; + } + return muted; +} + +// delay in seconds before unpause game +VAR(resumedelay, 0, 0, 100); + +int resumetime; +_VAR(resumetimer, resumetimer, 0, 0, 1, IDF_READONLY); +void pausegame(bool val, clientinfo *ci) +{ + // pause game if val = 1 + if(val) + { + resumetimer = 0; + server::pausegame(val, ci); + } + else + { + if(resumedelay == 0) + { + server::pausegame(val, ci); + return; + } + + if(resumetimer || !server::gamepaused) return; + + // start resume game counter + resumetime = totalmillis + resumedelay*1000; + resumetimer = 1; + onevent(ONRESUMEGAME, "i", ci ? ci->clientnum : -1); + } +} + +void checkresume() +{ + if(!server::gamepaused || (resumetimer == 0)) return; + + // unpause game + if(resumetime <= totalmillis) + { + resumetimer = 0; + server::pausegame(false); + } +} + +int getteamscore(const char *team) +{ + int score = 0; + if(smode && smode->hidefrags()) + { + score = smode->getteamscore(team); + } + else + { + loopv(clients) + if(clients[i]->state.state != CS_SPECTATOR && clients[i]->team[0]) + { + clientinfo *ci = clients[i]; + if(ci && (strcmp(team, ci->team) == 0)) + score += ci->state.frags; + } + } + return score; +} + +bool isteamsequalscore() +{ + int goodscore = getteamscore("good"); + int evilscore = getteamscore("evil"); + return (goodscore == evilscore); +} + +void rename(int cn, const char* name) +{ + // don't rename bots + if(cn < 0 || cn >= 128) return; + + clientinfo *ci = (clientinfo *)getinfo(cn); + + // invalid cn or empty new name + if(!ci || name == NULL || name[0] == 0) return; + + char newname[MAXNAMELEN + 1]; + newname[MAXNAMELEN] = 0; + filtertext(newname, name, false, MAXNAMELEN); + + putuint(ci->messages, N_SWITCHNAME); + sendstring(newname, ci->messages); + + vector buf; + putuint(buf, N_SWITCHNAME); + sendstring(newname, buf); + + packetbuf p(MAXTRANS, ENET_PACKET_FLAG_RELIABLE); + putuint(p, N_CLIENT); + putint(p, ci->clientnum); + putint(p, buf.length()); + p.put(buf.getbuf(), buf.length()); + sendpacket(ci->clientnum, 1, p.finalize(), -1); + + string oldname; + copystring(oldname, ci->name); + copystring(ci->name, newname); + + remod::onevent(ONSWITCHNAME, "iss", ci->clientnum, ci->name, oldname); +} + +static void freegetmap(ENetPacket *packet) +{ + loopv(clients) + { + clientinfo *ci = clients[i]; + if(ci->getmap == packet) ci->getmap = NULL; + } +} + +void sendmapto(int cn) +{ + clientinfo *ci = (clientinfo *)getinfo(cn); + if(!ci || !m_edit) return; + + if(!mapdata) conoutf("no map to send to %s(%i)", ci->name, cn); + else if(ci->getmap) conoutf("already sending map to %s(%i)", ci->name, cn); + else + { + // remod + remod::onevent(ONGETMAP, "i", cn); + + sendservmsgf("[%s is getting the map]", colorname(ci)); + if((ci->getmap = sendfile(cn, 2, mapdata, "ri", N_SENDMAP))) + ci->getmap->freeCallback = freegetmap; + ci->needclipboard = totalmillis ? totalmillis : 1; + } +} + +bool iseditcommand(int type) +{ + switch(type) + { + case N_EDITF: + case N_EDITT: + case N_EDITM: + case N_FLIP: + case N_COPY: + case N_PASTE: + case N_ROTATE: + case N_REPLACE: + case N_DELCUBE: + case N_REMIP: + case N_SENDMAP: + return true; + + default: + return false; + } +} + +void ghost(int cn, bool v) +{ + clientinfo *ci = getinfo(cn); + if(!ci) return; + ci->state.ext.ghost = v; + onevent(ONGHOST, "ii", cn, v ? 1 : 0); +} + +// Red Eclipse (c) +bool filterstring(char *dst, const char *src, bool newline, bool colour, bool whitespace, bool wsstrip, size_t len) +{ + bool filtered = false; + size_t n = 0; + for(int c = uchar(*src); c && n <= len; c = uchar(*++src)) + { + if(newline && (c=='\n' || c=='\r')) c = ' '; + if(c=='\f') + { + if(!colour) dst[n++] = c; + else + { + filtered = true; + c = *++src; + if(!c) break; + else if(c=='z') + { + c = *++src; + if(c) c = *++src; + if(!c) break; + } + else if(c == '[' || c == '(' || c == '{') + { + const char *end = strchr(src, c == '[' ? ']' : (c == '(' ? ')' : '}')); + src += end ? end-src : strlen(src); + } + + } + continue; + } + if(iscubeprint(c) || (iscubespace(c) && whitespace && (!wsstrip || n))) + dst[n++] = c; + else filtered = true; + } + if(whitespace && wsstrip && n) while(iscubespace(dst[n-1])) dst[--n] = 0; + dst[n <= len ? n : len] = 0; + return filtered; +} + +// to keep irc colors work +size_t old_encodeutf8(uchar *dstbuf, size_t dstlen, const uchar *srcbuf, size_t srclen, size_t *carry) +{ + uchar *dst = dstbuf, *dstend = &dstbuf[dstlen]; + const uchar *src = srcbuf, *srcend = &srcbuf[srclen]; + if(src < srcend && dst < dstend) do + { + int uni = cube2uni(*src); + if(uni <= 0x7F) + { + if(dst >= dstend) goto done; + const uchar *end = min(srcend, &src[dstend-dst]); + do + { + *dst++ = uni; + if(++src >= end) goto done; + uni = cube2uni(*src); + } + while(uni <= 0x7F); + } + if(uni <= 0x7FF) { if(dst + 2 > dstend) goto done; *dst++ = 0xC0 | (uni>>6); goto uni2; } + else if(uni <= 0xFFFF) { if(dst + 3 > dstend) goto done; *dst++ = 0xE0 | (uni>>12); goto uni3; } + else if(uni <= 0x1FFFFF) { if(dst + 4 > dstend) goto done; *dst++ = 0xF0 | (uni>>18); goto uni4; } + else if(uni <= 0x3FFFFFF) { if(dst + 5 > dstend) goto done; *dst++ = 0xF8 | (uni>>24); goto uni5; } + else if(uni <= 0x7FFFFFFF) { if(dst + 6 > dstend) goto done; *dst++ = 0xFC | (uni>>30); goto uni6; } + else goto uni1; + uni6: *dst++ = 0x80 | ((uni>>24)&0x3F); + uni5: *dst++ = 0x80 | ((uni>>18)&0x3F); + uni4: *dst++ = 0x80 | ((uni>>12)&0x3F); + uni3: *dst++ = 0x80 | ((uni>>6)&0x3F); + uni2: *dst++ = 0x80 | (uni&0x3F); + uni1:; + } + while(++src < srcend); + +done: + if(carry) *carry += src - srcbuf; + return dst - dstbuf; +} + // networkmessage to flood message type + inline size_t floodtype(int type) + { + size_t flood = FLOOD_OTHER; + switch(type) + { + case N_SAYTEAM: + case N_TEXT: + flood = FLOOD_TEXT; + break; + + case N_SWITCHNAME: + flood = FLOOD_SWITCHNAME; + break; + + case N_SWITCHTEAM: + flood = FLOOD_SWITCHTEAM; + break; + + case N_EDITVAR: + flood = FLOOD_EDITVAR; + break; + + default: + break; + } + return flood; + } + + #define FLOODDELAY 500 + #define STRIKELIMIT 5 + #define FLOODMUTE 10000 + #define FLOODTRIGGERTIME 10000 + bool checkflood(clientinfo *ci, int type) + { + bool isflood = false; + size_t floodmsg = floodtype(type); + floodstate &fs = ci->state.ext.flood[floodmsg]; + + // if faster than limit + if((totalmillis - fs.lastevent) < FLOODDELAY) { + fs.strikes++; + } + + // strike limit is reached, ignore next events + if(fs.strikes >= STRIKELIMIT) + { + fs.floodlimit = totalmillis + FLOODMUTE; + fs.strikes = 0; + } + + // if client is flooder + if((totalmillis - fs.floodlimit) < 0) + { + isflood = true; + if((totalmillis - fs.lastwarning) > FLOODTRIGGERTIME) { + fs.lastwarning = totalmillis; + remod::onevent(ONFLOOD, "ii", ci->clientnum, floodmsg); + } + } + fs.lastevent = totalmillis; + return isflood; + } + + void debugFlood() + { loopvrev(clients) { - clientinfo *ci = clients[i]; - conoutf("Name: %s", ci->name); - conoutf("totalmillis: %d", totalmillis); - conoutf("STRIKELIMIT: %d", STRIKELIMIT); - loopi(NUMFLOOD) - { - floodstate &fs = ci->state.ext.flood[i]; - conoutf("floodstate %d:", i); - conoutf(" int lastevent %d:", fs.lastevent); - conoutf(" size_t strikes %d:", fs.strikes); - conoutf(" int lastwarning %d:", fs.lastwarning); - conoutf(" int floodlimit %d:", fs.floodlimit); + clientinfo *ci = clients[i]; + conoutf("Name: %s", ci->name); + conoutf("totalmillis: %d", totalmillis); + conoutf("STRIKELIMIT: %d", STRIKELIMIT); + loopi(NUMFLOOD) + { + floodstate &fs = ci->state.ext.flood[i]; + conoutf("floodstate %d:", i); + conoutf(" int lastevent %d:", fs.lastevent); + conoutf(" size_t strikes %d:", fs.strikes); + conoutf(" int lastwarning %d:", fs.lastwarning); + conoutf(" int floodlimit %d:", fs.floodlimit); } - } - } - - void addSuicide(clientinfo *ci) - { - if(ci) - ci->state.ext.suicides++; + } + } + + void addSuicide(clientinfo *ci) + { + if(ci) + ci->state.ext.suicides++; } }