vote code restructured, wip

git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@2134 e016b1c5-ed68-44aa-a2f7-31cac88cffde
This commit is contained in:
driAn
2008-06-01 17:23:34 +00:00
parent a5c49a70e3
commit db32bc2211
5 changed files with 100 additions and 89 deletions
+2 -2
View File
@@ -717,7 +717,7 @@ void callvote(int type, char *arg1, char *arg2)
votedisplayinfo *v = newvotedisplayinfo(player1, type, arg1, arg2);
if(v)
{
if(multiplayer(false)) calledvote = v;
calledvote = v;
ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE);
ucharbuf p(packet->data, packet->dataLength);
putint(p, SV_CALLVOTE);
@@ -790,7 +790,7 @@ void voteresult(int v)
curvote->result = v;
curvote->millis = lastmillis + 5000;
conoutf("vote %s", v == VOTE_YES ? "passed" : "failed");
playsound(v == VOTE_YES ? S_VOTEPASS : S_VOTEFAIL, SP_HIGH);
if(multiplayer(false)) playsound(v == VOTE_YES ? S_VOTEPASS : S_VOTEFAIL, SP_HIGH);
}
}
+1 -1
View File
@@ -106,7 +106,7 @@ const char *modeacronymnames[] =
"OSOK", "TOSOK", "BOSOK"
};
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)" };
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 *fullmodestr(int n) { return (n>=0 && (size_t)n < sizeof(modefullnames)/sizeof(modefullnames[0])) ? modefullnames[n] : "unknown"; }
const char *acronymmodestr(int n) { return (n>=0 && (size_t)n < sizeof(modeacronymnames)/sizeof(modeacronymnames[0])) ? modeacronymnames[n] : "n/a"; }
+1 -1
View File
@@ -35,7 +35,7 @@ enum
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_NUM};
enum { VOTE_NEUTRAL = 0, VOTE_YES, VOTE_NO, VOTE_NUM };
enum { VOTEE_DISABLED = 0, VOTEE_CUR, VOTEE_MUL, VOTEE_MAX, VOTEE_AREA, VOTEE_NUM };
enum { VOTEE_DISABLED = 0, VOTEE_CUR, VOTEE_MUL, VOTEE_MAX, VOTEE_AREA, VOTEE_PERMISSION, VOTEE_INVALID, VOTEE_NUM };
enum { MM_OPEN, MM_PRIVATE, MM_NUM };
#define DMF 16.0f
+1 -1
View File
@@ -444,7 +444,7 @@ void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwat
draw_textf("evt %d", left, top+320, xtraverts);
}
if(!hidevote)
if(!hidevote && multiplayer(false))
{
extern votedisplayinfo *curvote;
+95 -84
View File
@@ -14,6 +14,7 @@
#include "servercontroller.h"
void resetmap(const char *newname, int newmode, int newtime = -1, bool notify = true);
void disconnect_client(int n, int reason = -1);
servercontroller *svcctrl = NULL;
struct log *logger = NULL;
@@ -466,7 +467,6 @@ bool isdedicated;
ENetHost *serverhost = NULL;
void process(ENetPacket *packet, int sender, int chan);
void checkvotes(bool forceend=false);
void welcomepacket(ucharbuf &p, int n);
void sendf(int cn, int chan, const char *format, ...)
@@ -971,28 +971,6 @@ void sendvoicecomteam(int sound, int sender)
if(packet->referenceCount==0) enet_packet_destroy(packet);
}
const char *disc_reason(int reason)
{
static const char *disc_reasons[] = { "normal", "end of packet", "client num", "kicked by server operator", "banned by server operator", "tag type", "connection refused due to ban", "wrong password", "failed admin login", "server FULL - maxclients", "server mastermode is \"private\"", "auto kick - did your score drop below the threshold?" };
return reason >= 0 && (size_t)reason < sizeof(disc_reasons)/sizeof(disc_reasons[0]) ? disc_reasons[reason] : "unknown";
}
void disconnect_client(int n, int reason = -1)
{
if(!clients.inrange(n) || clients[n]->type!=ST_TCPIP) return;
if(m_ctf) loopi(2) if(sflaginfos[i].state==CTFF_STOLEN && sflaginfos[i].actor_cn==n) flagaction(i, SV_FLAGDROP, n);
client &c = *clients[n];
savedscore *sc = findscore(c, true);
if(sc) sc->save(c.state);
if(reason>=0) logger->writeline(log::info, "[%s] disconnecting client %s (%s)", c.hostname, c.name, disc_reason(reason));
else logger->writeline(log::info, "[%s] disconnected client %s", c.hostname, c.name);
c.peer->data = (void *)-1;
if(reason>=0) enet_peer_disconnect(c.peer, reason);
clients[n]->zap();
sendf(-1, 1, "rii", SV_CDIS, n);
checkvotes();
}
void resetitems() { sents.setsize(0); notgotitems = true; }
int spawntime(int type)
@@ -1281,45 +1259,48 @@ void changeclientrole(int client, int role, char *pwd = NULL, bool force=false)
struct voteinfo
{
int owner, callmillis;
int owner, callmillis, result;
serveraction *action;
void pass()
voteinfo() : owner(0), callmillis(0), result(VOTE_NEUTRAL), action(NULL) {}
void end(int result)
{
if(action)
resetvotes();
sendf(-1, 1, "ri2", SV_VOTERESULT, result);
if(result == VOTE_YES && action)
{
if(demorecord) enddemorecord();
action->perform();
}
this->result = result;
}
bool isvalid() { return valid_client(owner) && action != NULL && action->isvalid(); }
bool isalive() { return servmillis < callmillis+40*1000; }
voteinfo() : owner(0), callmillis(0), action(NULL) {}
void evaluate(bool forceend = false)
{
int stats[VOTE_NUM] = {0};
loopv(clients)
if(clients[i]->type!=ST_EMPTY && clients[i]->connectmillis < callmillis)
{
stats[clients[i]->vote]++;
};
bool admin = clients[owner]->role==CR_ADMIN || (!isdedicated && clients[owner]->type==ST_LOCAL);
int total = stats[VOTE_NO]+stats[VOTE_YES]+stats[VOTE_NEUTRAL];
const float requiredcount = 0.51f;
if(stats[VOTE_YES]/(float)total > requiredcount || admin)
end(VOTE_YES);
else if(forceend || stats[VOTE_NO]/(float)total > requiredcount || stats[VOTE_NO] >= stats[VOTE_YES]+stats[VOTE_NEUTRAL])
end(VOTE_NO);
else return;
}
};
static voteinfo *curvote = NULL;
void checkvotes(bool forceend)
{
if(!curvote) return;
int stats[VOTE_NUM] = {0};
loopv(clients) if(clients[i]->type!=ST_EMPTY && clients[i]->connectmillis < curvote->callmillis) { stats[clients[i]->vote]++; };
int total = stats[VOTE_NO]+stats[VOTE_YES]+stats[VOTE_NEUTRAL];
const float requiredcount = 0.51f;
if(stats[VOTE_YES]/(float)total > requiredcount || (curvote->isvalid() && clients[curvote->owner]->role == CR_ADMIN))
{
sendf(-1, 1, "ri2", SV_VOTERESULT, VOTE_YES);
curvote->pass();
}
else if(forceend || stats[VOTE_NO]/(float)total > requiredcount || stats[VOTE_NO] >= stats[VOTE_YES]+stats[VOTE_NEUTRAL])
{
sendf(-1, 1, "ri2", SV_VOTERESULT, VOTE_NO);
}
else return;
resetvotes();
DELETEP(curvote);
}
bool vote(int sender, int vote) // true if the vote was placed successfully
{
if(!curvote || !valid_client(sender) || vote < VOTE_YES || vote > VOTE_NO) return false;
@@ -1331,52 +1312,76 @@ bool vote(int sender, int vote) // true if the vote was placed successfully
else
{
clients[sender]->vote = vote;
checkvotes();
curvote->evaluate();
return true;
}
}
void callvotesuc(voteinfo *v)
{
if(!v->isvalid()) return;
curvote = v;
clients[v->owner]->lastvotecall = servmillis;
sendf(v->owner, 1, "ri", SV_CALLVOTESUC);
logger->writeline(log::info, "[%s] client %s called a vote: %s", clients[v->owner]->hostname, clients[v->owner]->name, v->action->desc ? v->action->desc : "[unknown]");
}
void callvoteerr(voteinfo *v, int error)
{
if(!v->isvalid()) return;
sendf(v->owner, 1, "ri2", SV_CALLVOTEERR, error);
logger->writeline(log::info, "[%s] client %s failed to call a vote: %s (%s)", clients[v->owner]->hostname, clients[v->owner]->name, v->action->desc ? v->action->desc : "[unknown]", voteerrorstr(error));
}
bool callvote(voteinfo *v) // true if a regular vote was called
{
if(!v || !v->isvalid() || v->action->role > clients[v->owner]->role) return false;
int area = isdedicated ? EE_DED_SERV : EE_LOCAL_SERV;
if(!(area & v->action->area)) sendf(v->owner, 1, "ri2", SV_CALLVOTEERR, VOTEE_AREA); // action now allowed in current area
if(!isdedicated)
{
if(clients[v->owner]->type == ST_LOCAL) // allow op commands locally
{
v->action->perform();
}
return false;
int error = -1;
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) error = VOTEE_CUR;
else if(configsets.length() && curcfgset < configsets.length() && !configsets[curcfgset].vote && clients[v->owner]->role == CR_DEFAULT)
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;
if(error >= 0)
{
callvoteerr(v, error);
return false;
}
else
{
// regular vote
int voteerror = -1;
if(curvote)
voteerror = VOTEE_CUR;
else if(configsets.length() && curcfgset < configsets.length() && !configsets[curcfgset].vote && clients[v->owner]->role == CR_DEFAULT)
voteerror = VOTEE_DISABLED;
else if(clients[v->owner]->lastvotecall && servmillis - clients[v->owner]->lastvotecall < 60*1000 && clients[v->owner]->role != CR_ADMIN && numclients()>1)
voteerror = VOTEE_MAX;
if(voteerror >= 0)
{
sendf(v->owner, 1, "ri2", SV_CALLVOTEERR, voteerror);
logger->writeline(log::info, "[%s] client %s failed to call a vote: %s (%s)", clients[v->owner]->hostname, clients[v->owner]->name, v->action->desc ? v->action->desc : "[unknown]", voteerrorstr(voteerror));
return false;
}
else
{
curvote = v;
clients[v->owner]->lastvotecall = servmillis;
logger->writeline(log::info, "[%s] client %s called a vote: %s", clients[v->owner]->hostname, clients[v->owner]->name, v->action->desc ? v->action->desc : "[unknown]");
return true;
}
callvotesuc(v);
return true;
}
}
const char *disc_reason(int reason)
{
static const char *disc_reasons[] = { "normal", "end of packet", "client num", "kicked by server operator", "banned by server operator", "tag type", "connection refused due to ban", "wrong password", "failed admin login", "server FULL - maxclients", "server mastermode is \"private\"", "auto kick - did your score drop below the threshold?" };
return reason >= 0 && (size_t)reason < sizeof(disc_reasons)/sizeof(disc_reasons[0]) ? disc_reasons[reason] : "unknown";
}
void disconnect_client(int n, int reason)
{
if(!clients.inrange(n) || clients[n]->type!=ST_TCPIP) return;
if(m_ctf) loopi(2) if(sflaginfos[i].state==CTFF_STOLEN && sflaginfos[i].actor_cn==n) flagaction(i, SV_FLAGDROP, n);
client &c = *clients[n];
savedscore *sc = findscore(c, true);
if(sc) sc->save(c.state);
if(reason>=0) logger->writeline(log::info, "[%s] disconnecting client %s (%s)", c.hostname, c.name, disc_reason(reason));
else logger->writeline(log::info, "[%s] disconnected client %s", c.hostname, c.name);
c.peer->data = (void *)-1;
if(reason>=0) enet_peer_disconnect(c.peer, reason);
clients[n]->zap();
sendf(-1, 1, "rii", SV_CDIS, n);
if(curvote) curvote->evaluate();
}
void sendwhois(int sender, int cn)
{
if(!valid_client(sender) || !valid_client(cn)) return;
@@ -1919,7 +1924,9 @@ void process(ENetPacket *packet, int sender, int chan) // sender may be -1
}
vi->owner = sender;
vi->callmillis = servmillis;
if(callvote(vi)) { QUEUE_MSG; sendf(sender, 1, "ri", SV_CALLVOTESUC); }
//if(callvote(vi)) { QUEUE_MSG; sendf(sender, 1, "ri", SV_CALLVOTESUC); }
//else delete vi;
if(callvote(vi)) { QUEUE_MSG; }
else delete vi;
break;
}
@@ -2033,7 +2040,11 @@ void serverslice(uint timeout) // main server update, called from cube main lo
if(m_arena) arenacheck();
}
if(curvote && !curvote->isalive()) checkvotes(true);
if(curvote)
{
if(!curvote->isalive()) curvote->evaluate(true);
if(curvote->result!=VOTE_NEUTRAL) DELETEP(curvote);
}
int nonlocalclients = numnonlocalclients();