From 32d145ed054a98b0a1aa041362575a43b5954c93 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Mon, 6 Nov 2006 00:05:10 +0000 Subject: [PATCH] *** empty log message *** git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@475 e016b1c5-ed68-44aa-a2f7-31cac88cffde --- source/src/bot/ac_bot.cpp | 12 +- source/src/bot/bot.cpp | 2 +- source/src/bot/botmanager.cpp | 14 +- source/src/client.cpp | 198 +++++------ source/src/clientextras.cpp | 4 +- source/src/clientgame.cpp | 20 +- source/src/clients2c.cpp | 169 +++++----- source/src/cube.h | 2 +- source/src/editing.cpp | 10 +- source/src/entities.cpp | 8 +- source/src/main.cpp | 9 +- source/src/physics.cpp | 2 +- source/src/protos.h | 11 +- source/src/renderextras.cpp | 1 + source/src/savegamedemo.cpp | 2 +- source/src/server.cpp | 618 ++++++++++++++++++++++------------ source/src/serverbrowser.cpp | 20 +- source/src/serverms.cpp | 10 +- source/src/serverutil.cpp | 21 +- source/src/sound.cpp | 4 +- source/src/tools.h | 17 - source/src/weapon.cpp | 12 +- source/src/world.cpp | 4 +- 23 files changed, 698 insertions(+), 472 deletions(-) diff --git a/source/src/bot/ac_bot.cpp b/source/src/bot/ac_bot.cpp index e2bb4901..f80aad13 100644 --- a/source/src/bot/ac_bot.cpp +++ b/source/src/bot/ac_bot.cpp @@ -160,8 +160,8 @@ void CACBot::BotPain(int damage, dynent *d, bool gib) frags = 1; conoutf("you fragged %s", m_pMyEnt->name); } - addmsg(1, 2, SV_FRAGS, player1->frags += frags); - addmsg(1, 4, SV_BOTDIED, BotManager.GetBotIndex(m_pMyEnt), -1, false); + addmsg(SV_FRAGS, "ri", player1->frags += frags); + addmsg(SV_BOTDIED, "ri3", BotManager.GetBotIndex(m_pMyEnt), -1, false); if(gib) addgib(m_pMyEnt); } else if (d->monsterstate) @@ -174,14 +174,14 @@ void CACBot::BotPain(int damage, dynent *d, bool gib) { conoutf("%s suicided", d->name); KillerIndex = BotManager.GetBotIndex(d); - addmsg(1, 3, SV_BOTFRAGS, KillerIndex, --d->frags); + addmsg(SV_BOTFRAGS, "rii", KillerIndex, --d->frags); } else { if (d->bIsBot) { KillerIndex = BotManager.GetBotIndex(d); - addmsg(1, 3, SV_BOTFRAGS, KillerIndex, ++d->frags); + addmsg(SV_BOTFRAGS, "rii", KillerIndex, ++d->frags); } else loopv(players){ if (players[i] == d) { KillerIndex = i; break;} } @@ -196,7 +196,7 @@ void CACBot::BotPain(int damage, dynent *d, bool gib) conoutf("%s fragged %s", d->name, m_pMyEnt->name); } } - addmsg(1, 4, SV_BOTDIED, BotManager.GetBotIndex(m_pMyEnt), KillerIndex, + addmsg(SV_BOTDIED, "ri3", BotManager.GetBotIndex(m_pMyEnt), KillerIndex, d->bIsBot); if(d->gunselect==GUN_KNIFE) addgib(m_pMyEnt); } @@ -302,7 +302,7 @@ void CACBot::AddItem(int i, int &v, int spawnsec, int t) sents[i].spawned = false; sents[i].spawnsecs = spawnsec; - addmsg(1, 3, SV_BOTITEMPICKUP, i, m_classicsp ? 100000 : spawnsec); + addmsg(SV_BOTITEMPICKUP, "rii", i, m_classicsp ? 100000 : spawnsec); // HACK: Reset ent goal if bot was looking for for this ent if (m_pTargetEnt == &ents[i]) diff --git a/source/src/bot/bot.cpp b/source/src/bot/bot.cpp index c0400e52..a52127f3 100644 --- a/source/src/bot/bot.cpp +++ b/source/src/bot/bot.cpp @@ -347,7 +347,7 @@ void CBot::SendBotInfo() enet_host_flush(clienthost); } else - localclienttoserver(packet); + localclienttoserver(0, packet); } float CBot::GetDistance(const vec &o) diff --git a/source/src/bot/botmanager.cpp b/source/src/bot/botmanager.cpp index 3228ef61..77c6b0e4 100644 --- a/source/src/bot/botmanager.cpp +++ b/source/src/bot/botmanager.cpp @@ -1029,7 +1029,7 @@ void addbot(char *arg1, char *arg2, char *arg3) sendstring(team, p); // Bot team sendstring(name, p); // Bot name enet_packet_resize(packet, p.length()); - sendpackettoserv(packet); + sendpackettoserv(1, packet); } } @@ -1077,7 +1077,7 @@ void addnbot(char *arg1, char *arg2, char *arg3) sendstring(team, p); // Bot team sendstring(name, p); // Bot name enet_packet_resize(packet, p.length()); - sendpackettoserv(packet); + sendpackettoserv(1, packet); } } @@ -1151,7 +1151,7 @@ void kickbot(const char *szName) { if (ishost()) { - addmsg(1, 2, SV_BOTDIS, iBotInd); + addmsg(SV_BOTDIS, "ri", iBotInd); conoutf("bot %s disconnected", (int)(bots[iBotInd]->name[0] ? bots[iBotInd]->name : "[incompatible client]")); @@ -1170,7 +1170,7 @@ void kickbot(const char *szName) strcpy(tmp, szName); sendstring(tmp, p); // Bot name enet_packet_resize(packet, p.length()); - sendpackettoserv(packet); + sendpackettoserv(1, packet); } } } @@ -1185,7 +1185,7 @@ void kickallbots(void) { if (ishost()) { - addmsg(1, 2, SV_BOTDIS, i); + addmsg(SV_BOTDIS, "ri", i); conoutf("bot %s disconnected",(bots[i]->name[0] ? bots[i]->name : "[incompatible client]")); @@ -1201,7 +1201,7 @@ void kickallbots(void) putint(p, int(COMMAND_KICKBOT)); // Bot command type putint(p, 0); // 0==kick all bots, 1==kick one specific bot enet_packet_resize(packet, p.length()); - sendpackettoserv(packet); + sendpackettoserv(1, packet); } } } @@ -1291,7 +1291,7 @@ void botskill(char *bot, char *skill) putint(p, int(COMMAND_BOTSKILL)); // Bot command type putint(p, SkillNr); enet_packet_resize(packet, p.length()); - sendpackettoserv(packet); + sendpackettoserv(1, packet); } } diff --git a/source/src/client.cpp b/source/src/client.cpp index e70e5821..02298cfe 100644 --- a/source/src/client.cpp +++ b/source/src/client.cpp @@ -67,21 +67,31 @@ COMMANDN(skin, newskin, ARG_1INT); void connects(char *servername) { disconnect(1); // reset state - addserver(servername); - conoutf("attempting to connect to %s", servername); - ENetAddress address = { ENET_HOST_ANY, CUBE_SERVER_PORT }; - if(enet_address_set_host(&address, servername) < 0) + ENetAddress address; + address.port = CUBE_SERVER_PORT; + + if(servername) { - conoutf("could not resolve server %s", servername); - return; + addserver(servername); + conoutf("attempting to connect to %s", servername); + if(!resolverwait(servername, &address)) + { + conoutf("could not resolve server %s", servername); + return; + }; + } + else + { + conoutf("attempting to connect over LAN"); + address.host = ENET_HOST_BROADCAST; }; clienthost = enet_host_create(NULL, 1, rate, rate); if(clienthost) { - enet_host_connect(clienthost, &address, 1); + enet_host_connect(clienthost, &address, 4); enet_host_flush(clienthost); connecting = lastmillis; connattempts = 0; @@ -99,7 +109,7 @@ void disconnect(int onlyclean, int async) { if(!connecting && !disconnecting) { - enet_peer_disconnect(clienthost->peers); + enet_peer_disconnect(clienthost->peers, DISC_NONE); enet_host_flush(clienthost); disconnecting = lastmillis; }; @@ -143,42 +153,59 @@ void trydisconnect() disconnect(0, !disconnecting); }; -string ctext; -void toserver(char *text) { conoutf("%s:\f %s", player1->name, text); s_strncpy(ctext, text, 80); }; +void toserver(char *text) { conoutf("%s:\f %s", player1->name, text); addmsg(SV_TEXT, "rs", text); }; void echo(char *text) { conoutf("%s", text); }; +void lanconnect() +{ + connects(0); +}; + COMMAND(echo, ARG_VARI); COMMANDN(say, toserver, ARG_VARI); COMMANDN(connect, connects, ARG_1STR); +COMMAND(lanconnect, ARG_NONE); COMMANDN(disconnect, trydisconnect, ARG_NONE); // collect c2s messages conveniently -vector messages; +vector messages; -void addmsg(int rel, int num, int type, ...) +void addmsg(int type, const char *fmt, ...) { if(demoplayback) return; + static uchar buf[MAXTRANS]; + ucharbuf p(buf, MAXTRANS); + putint(p, type); + int numi = 1, nums = 0; + bool reliable = false; + if(fmt) + { + va_list args; + va_start(args, fmt); + while(*fmt) switch(*fmt++) + { + case 'r': reliable = true; break; + case 'i': + { + int n = isdigit(*fmt) ? *fmt++-'0' : 1; + loopi(n) putint(p, va_arg(args, int)); + numi += n; + break; + }; + case 's': sendstring(va_arg(args, const char *), p); nums++; break; + }; + va_end(args); + }; + int num = nums?0:numi; if(num!=msgsizelookup(type)) { s_sprintfd(s)("inconsistant msg size for %d (%d != %d)", type, num, msgsizelookup(type)); fatal(s); }; - if(messages.length()==100) { conoutf("command flood protection (type %d)", type); return; }; - ivector &msg = messages.add(); - msg.add(num); - msg.add(rel); - msg.add(type); - va_list marker; - va_start(marker, type); - loopi(num-1) msg.add(va_arg(marker, int)); - va_end(marker); -}; - -void server_err() -{ - conoutf("server network error or player kick, disconnecting..."); - disconnect(); + int len = p.length(); + messages.add(len&0xFF); + messages.add((len>>8)|(reliable ? 0x80 : 0)); + loopi(len) messages.add(buf[i]); }; int lastupdate = 0, lastping = 0; -string toservermap; bool senditemstoserver = false; // after a map change, since server doesn't have map data string clientpassword; @@ -190,18 +217,15 @@ bool netmapstart() { senditemstoserver = true; return clienthost!=NULL; }; void initclientnet() { - ctext[0] = 0; - toservermap[0] = 0; clientpassword[0] = 0; - toserverpwd = NULL; newname("unnamed"); ctf_team("red"); }; -void sendpackettoserv(void *packet) +void sendpackettoserv(int chan, ENetPacket *packet) { - if(clienthost) { enet_host_broadcast(clienthost, 0, (ENetPacket *)packet); enet_host_flush(clienthost); } - else localclienttoserver((ENetPacket *)packet); + if(clienthost) { enet_host_broadcast(clienthost, chan, packet); enet_host_flush(clienthost); } + else localclienttoserver(chan, packet); } void c2skeepalive() @@ -221,50 +245,36 @@ void c2sinfo(dynent *d) // send update to the server { if(clientnum<0) return; // we haven't had a welcome message from the server yet if(lastmillis-lastupdate<40) return; // don't update faster than 25fps - ENetPacket *packet = enet_packet_create (NULL, MAXTRANS, 0); - ucharbuf p(packet->data, packet->dataLength); + ENetPacket *packet = enet_packet_create(NULL, 100, 0); + ucharbuf q(packet->data, packet->dataLength); + + putint(q, SV_POS); + putint(q, clientnum); + putuint(q, (int)(d->o.x*DMF)); // quantize coordinates to 1/16th of a cube, between 1 and 3 bytes + putuint(q, (int)(d->o.y*DMF)); + putuint(q, (int)(d->o.z*DMF)); + putuint(q, (int)(d->yaw*DAF)); + putint(q, (int)(d->pitch*DAF)); + putint(q, (int)(d->roll*DAF)); + putint(q, (int)(d->vel.x*DVF)); // quantize to 1/100, almost always 1 byte + putint(q, (int)(d->vel.y*DVF)); + putint(q, (int)(d->vel.z*DVF)); + // pack rest in 1 byte: strafe:2, move:2, onfloor:1, state:3 + putint(q, (d->strafe&3) | ((d->move&3)<<2) | (((int)d->onfloor)<<4) | ((editmode ? CS_EDITING : d->state)<<5) ); + + enet_packet_resize(packet, q.length()); + incomingdemodata(q.buf, q.length(), true); + sendpackettoserv(0, packet); + bool serveriteminitdone = false; - if(toserverpwd) - { - packet->flags = ENET_PACKET_FLAG_RELIABLE; - putint(p, SV_PWD); - sendstring(toserverpwd, p); - toserverpwd[0] = 0; - toserverpwd = NULL; - } - else if(toservermap[0]) // suggest server to change map - { // do this exclusively as map change may invalidate rest of update - packet->flags = ENET_PACKET_FLAG_RELIABLE; - putint(p, SV_MAPCHANGE); - sendstring(toservermap, p); - toservermap[0] = 0; - putint(p, nextmode); - } - else if(masterpwd[0]) - { - packet->flags = ENET_PACKET_FLAG_RELIABLE; - putint(p, SV_GETMASTER); - sendstring(masterpwd, p); - masterpwd[0] = 0; - } - else + if(gun_changed || senditemstoserver || !c2sinit || messages.length() || lastmillis-lastping>250) { - putint(p, SV_POS); - putint(p, clientnum); - putint(p, (int)(d->o.x*DMF)); // quantize coordinates to 1/16th of a cube, between 1 and 3 bytes - putint(p, (int)(d->o.y*DMF)); - putint(p, (int)(d->o.z*DMF)); - putint(p, (int)(d->yaw*DAF)); - putint(p, (int)(d->pitch*DAF)); - putint(p, (int)(d->roll*DAF)); - putint(p, (int)(d->vel.x*DVF)); // quantize to 1/100, almost always 1 byte - putint(p, (int)(d->vel.y*DVF)); - putint(p, (int)(d->vel.z*DVF)); - // pack rest in 1 byte: strafe:2, move:2, onfloor:1, state:3 - putint(p, (d->strafe&3) | ((d->move&3)<<2) | (((int)d->onfloor)<<4) | ((editmode ? CS_EDITING : d->state)<<5) ); - + packet = enet_packet_create (NULL, MAXTRANS, 0); + ucharbuf p(packet->data, packet->dataLength); + if(gun_changed) { + packet->flags = ENET_PACKET_FLAG_RELIABLE; putint(p, SV_WEAPCHANGE); putint(p, player1->gunselect); gun_changed = false; @@ -278,13 +288,6 @@ void c2sinfo(dynent *d) // send update to the server senditemstoserver = false; serveriteminitdone = true; }; - if(ctext[0]) // player chat, not flood protected for now - { - packet->flags = ENET_PACKET_FLAG_RELIABLE; - putint(p, SV_TEXT); - sendstring(ctext, p); - ctext[0] = 0; - }; if(!c2sinit) // tell other clients who I am { packet->flags = ENET_PACKET_FLAG_RELIABLE; @@ -295,24 +298,30 @@ void c2sinfo(dynent *d) // send update to the server putint(p, player1->skin); putint(p, player1->lifesequence); }; - loopv(messages) // send messages collected during the previous frames + int i = 0; + while(i < messages.length()) // send messages collected during the previous frames { - ivector &msg = messages[i]; - if(msg[1]) packet->flags = ENET_PACKET_FLAG_RELIABLE; - loopi(msg[0]) putint(p, msg[i+2]); + int len = messages[i] | ((messages[i+1]&0x7F)<<8); + if(p.remaining() < len) break; + if(messages[i+1]&0x80) packet->flags = ENET_PACKET_FLAG_RELIABLE; + p.put(&messages[i+2], len); + i += 2 + len; }; - messages.setsize(0); + messages.remove(0, i); if(lastmillis-lastping>250) { putint(p, SV_PING); putint(p, lastmillis); lastping = lastmillis; }; + if(!p.length()) enet_packet_destroy(packet); + else + { + incomingdemodata(p.buf, p.length()); + enet_packet_resize(packet, p.length()); + sendpackettoserv(1, packet); + }; }; - enet_packet_resize(packet, p.length()); - incomingdemodata(p.buf, p.length(), true); - if(clienthost) { enet_host_broadcast(clienthost, 0, packet); enet_host_flush(clienthost); } - else localclienttoserver(packet); lastupdate = lastmillis; if(serveriteminitdone) loadgamerest(); // hack }; @@ -345,14 +354,15 @@ void gets2c() // get updates from the server case ENET_EVENT_TYPE_RECEIVE: if(disconnecting) conoutf("attempting to disconnect..."); - else localservertoclient(event.packet->data, event.packet->dataLength); + else localservertoclient(event.channelID, event.packet->data, event.packet->dataLength); enet_packet_destroy(event.packet); break; case ENET_EVENT_TYPE_DISCONNECT: - if(disconnecting) disconnect(); - else - server_err(); + extern char *disc_reasons[]; + if(event.data>DISC_MAXCLIENTS) event.data = DISC_NONE; + if(!disconnecting || event.data) conoutf("\fserver network error, disconnecting (%s) ...", disc_reasons[event.data]); + disconnect(); return; } }; diff --git a/source/src/clientextras.cpp b/source/src/clientextras.cpp index 5d8403b2..32a89ade 100644 --- a/source/src/clientextras.cpp +++ b/source/src/clientextras.cpp @@ -192,7 +192,7 @@ void sendmap(char *mapname) p.put(mapdata, mapsize); delete[] mapdata; enet_packet_resize(packet, p.length()); - sendpackettoserv(packet); + sendpackettoserv(2, packet); conoutf("sending map %s to server...", mapname); s_sprintfd(msg)("[map %s uploaded to server, \"getmap\" to receive it]", mapname); toserver(msg); @@ -204,7 +204,7 @@ void getmap() ucharbuf p(packet->data, packet->dataLength); putint(p, SV_RECVMAP); enet_packet_resize(packet, p.length()); - sendpackettoserv(packet); + sendpackettoserv(2, packet); conoutf("requesting map from server..."); } diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index d8e1fda5..7224b51a 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -9,7 +9,7 @@ flaginfo flaginfos[2]; void mode(int n) { if(n==7 && clienthost) conoutf("this mode is for singleplayer only"); - else addmsg(1, 2, SV_GAMEMODE, nextmode = n); + else addmsg(SV_GAMEMODE, "ri", nextmode = n); }; COMMAND(mode, ARG_1INT); @@ -129,7 +129,7 @@ void ctf_death() // EDIT: AH flaginfo &f = flaginfos[flag]; if(f.state==CTFF_STOLEN && f.thief==player1) { - addmsg(1, 2, SV_FLAGDROP, flag); + addmsg(SV_FLAGDROP, "ri", flag); f.flag->spawned = false; f.state = CTFF_DROPPED; }; @@ -459,7 +459,7 @@ void selfdamage(int damage, int actor, dynent *act, bool gib) { actor = getclientnum(); conoutf("you suicided!"); - addmsg(1, 2, SV_FRAGS, --player1->frags); + addmsg(SV_FRAGS, "ri", --player1->frags); } else { @@ -486,8 +486,8 @@ void selfdamage(int damage, int actor, dynent *act, bool gib) if(m_ctf) ctf_death(); showscores(true); setscope(false); - if(act->bIsBot) addmsg(1, 2, SV_DIEDBYBOT, actor); - else addmsg(1, 2, gib ? SV_GIBDIED : SV_DIED, actor); + if(act->bIsBot) addmsg(SV_DIEDBYBOT, "ri", actor); + else addmsg(gib ? SV_GIBDIED : SV_DIED, "ri", actor); player1->lifesequence++; player1->attacking = false; player1->state = CS_DEAD; @@ -499,7 +499,7 @@ void selfdamage(int damage, int actor, dynent *act, bool gib) spawnstate(player1); //player1->lastaction = lastmillis; //fixme - if (act->bIsBot) addmsg(1, 3, SV_BOTFRAGS, BotManager.GetBotIndex(act), ++act->frags); + if (act->bIsBot) addmsg(SV_BOTFRAGS, "rii", BotManager.GetBotIndex(act), ++act->frags); } else { @@ -673,7 +673,7 @@ void flagaction(int flag, int action) if(f.thief==player1) { conoutf("you scored"); - addmsg(1, 2, SV_FLAGS, ++player1->flagscore); + addmsg(SV_FLAGS, "ri", ++player1->flagscore); } else conoutf("%s scored for %s team", f.thief->name, (ownflag ? "the enemy" : "your")); break; @@ -682,18 +682,16 @@ void flagaction(int flag, int action) }; }; -string masterpwd; - void getmaster(char *pwd) { if(!pwd[0]) return; if(strlen(pwd)>15) { conoutf("the master password has a maximum length of 15 characters"); return; }; - s_strcpy(masterpwd, pwd); + addmsg(SV_GETMASTER, "rs", pwd); }; void mastercommand(int cmd, int a) { - addmsg(1, 3, SV_MASTERCMD, cmd, a); + addmsg(SV_MASTERCMD, "rii", cmd, a); }; void showmastermenu(int m) // 0=kick, 1=ban diff --git a/source/src/clients2c.cpp b/source/src/clients2c.cpp index 0cc6baaa..a8a6d286 100644 --- a/source/src/clients2c.cpp +++ b/source/src/clients2c.cpp @@ -4,9 +4,7 @@ extern int clientnum; extern bool c2sinit, senditemstoserver; -extern string toservermap; extern string clientpassword; -extern char *toserverpwd; void neterr(char *s) { @@ -22,7 +20,7 @@ void changemapserv(char *name, int mode) // forced map change from the se void changemap(char *name) // request map change, server may ignore { - s_strcpy(toservermap, name); + addmsg(SV_MAPCHANGE, "rsi", name, nextmode); }; // Added by Rick @@ -76,65 +74,24 @@ void updatepos(dynent *d) extern void trydisconnect(); -#define CN_CHECK if(cn<0 || cn>=players.length()) { conoutf("invalid client (msg %i)", type); return; }; +#define CN_CHECK if(!players.inrange(cn)) { conoutf("invalid client (msg %i)", type); return; }; //#define SENDER_CHECK if(sender<0) { conoutf("invalid sender (msg %i)", type); return; }; -void localservertoclient(uchar *buf, int len) // processes any updates from the server +void parsepositions(ucharbuf &p) { - incomingdemodata(buf, len); - - ucharbuf p(buf, len); - - char text[MAXTRANS]; int cn = -1, type; dynent *d = NULL; - bool mapchanged = false; - bool c2si = false, killedbybot=false; - bool gib=false; - while(p.remaining()) switch(type = getint(p)) { - case SV_INITS2C: // welcome messsage from the server - { - cn = getint(p); - int prot = getint(p); - if(prot!=PROTOCOL_VERSION) - { - conoutf("you are using a different game protocol (you: %d, server: %d)", PROTOCOL_VERSION, prot); - disconnect(); - return; - }; - toservermap[0] = 0; - clientnum = cn; // we are now fully connectedss - bool firstplayer = !getint(p); - if(getint(p) > 0) - { - conoutf("INFO: this server is password protected"); - toserverpwd = clientpassword; - }; - int m = getint(p); - if(m==1) - { - conoutf("server is FULL, disconnecting.."); - } - else if(m==2) - { - conoutf("you are BANNED from this server"); - } - else if(firstplayer) s_strcpy(toservermap, getclientmap()); // we are the first client on this server, set map - break; - }; - case SV_POS: // position of another client { cn = getint(p); d = getclient(cn); if(!d) return; - c2si = false; - d->o.x = getint(p)/DMF; - d->o.y = getint(p)/DMF; - d->o.z = getint(p)/DMF; - d->yaw = getint(p)/DAF; + d->o.x = getuint(p)/DMF; + d->o.y = getuint(p)/DMF; + d->o.z = getuint(p)/DMF; + d->yaw = getuint(p)/DAF; d->pitch = getint(p)/DAF; d->roll = getint(p)/DAF; d->vel.x = getint(p)/DVF; @@ -142,16 +99,52 @@ void localservertoclient(uchar *buf, int len) // processes any updates from th d->vel.z = getint(p)/DVF; int f = getint(p); d->strafe = (f&3)==3 ? -1 : f&3; - f >>= 2; + f >>= 2; d->move = (f&3)==3 ? -1 : f&3; d->onfloor = (f>>2)&1; - int state = f>>3; + int state = f>>3; if(state==CS_DEAD && d->state!=CS_DEAD) d->lastaction = lastmillis; - d->state = state; + d->state = state; if(!demoplayback) updatepos(d); break; }; + default: + neterr("type"); + return; + }; +}; + +void parsemessages(int cn, dynent *d, ucharbuf &p) +{ + char text[MAXTRANS]; + int type; + bool mapchanged = false; + bool c2si = false, killedbybot=false; + bool gib=false; + + while(p.remaining()) switch(type = getint(p)) + { + case SV_INITS2C: // welcome messsage from the server + { + int mycn = getint(p), prot = getint(p); + if(prot!=PROTOCOL_VERSION) + { + conoutf("you are using a different game protocol (you: %d, server: %d)", PROTOCOL_VERSION, prot); + disconnect(); + return; + }; + clientnum = mycn; // we are now fully connectedss + bool firstplayer = !getint(p); + if(getint(p) > 0) + { + conoutf("INFO: this server is password protected"); + addmsg(SV_PWD, "rs", clientpassword); + }; + if(firstplayer) changemap(getclientmap()); // we are the first client on this server, set map + break; + }; + case SV_SOUND: playsound(getint(p), &d->o); break; @@ -213,11 +206,13 @@ void localservertoclient(uchar *buf, int len) // processes any updates from th }; case SV_CDIS: - cn = getint(p); + { + int cn = getint(p); if(!(d = getclient(cn))) break; - conoutf("player %s disconnected", (d->name[0] ? d->name : "[incompatible client]")); + if(d->name[0]) conoutf("player %s disconnected", d->name); zapdynent(players[cn]); break; + }; case SV_SHOT: { @@ -290,7 +285,7 @@ void localservertoclient(uchar *buf, int len) // processes any updates from th frags = 1; conoutf("you fragged %s", d->name); }; - addmsg(1, 2, SV_FRAGS, player1->frags += frags); + addmsg(SV_FRAGS, "ri", player1->frags += frags); if(gib) addgib(d); } else @@ -322,6 +317,18 @@ void localservertoclient(uchar *buf, int len) // processes any updates from th players[cn]->frags = getint(p); break; + case SV_RESUME: + { + int cn = getint(p), frags = getint(p); + if(cn==clientnum) player1->frags = frags; + else + { + dynent *d = getclient(cn); + if(d) d->frags = frags; + }; + break; + }; + case SV_ITEMPICKUP: case SV_BOTITEMPICKUP: setspawn(getint(p), false); @@ -380,12 +387,8 @@ void localservertoclient(uchar *buf, int len) // processes any updates from th break; }; - case SV_PING: - getint(p); - break; - case SV_PONG: - addmsg(0, 2, SV_CLIENTPING, player1->ping = (player1->ping*5+lastmillis-getint(p))/6); + addmsg(SV_CLIENTPING, "i", player1->ping = (player1->ping*5+lastmillis-getint(p))/6); break; case SV_CLIENTPING: @@ -490,14 +493,6 @@ void localservertoclient(uchar *buf, int len) // processes any updates from th break; }; - case SV_FLAGDROP: - case SV_FLAGRETURN: - case SV_FLAGSCORE: - { - getint(p); - break; - }; - // Added by Rick: Bot specific messages case SV_BOTSOUND: { @@ -605,7 +600,7 @@ void localservertoclient(uchar *buf, int len) // processes any updates from th frags = 1; conoutf("you fragged %s", bot->name); }; - addmsg(1, 2, SV_FRAGS, player1->frags += frags); + addmsg(SV_FRAGS, "ri", player1->frags += frags); if(player1->gunselect==GUN_KNIFE) addgib(bot); } @@ -678,13 +673,6 @@ void localservertoclient(uchar *buf, int len) // processes any updates from th botcommand(p, text); break; - case SV_MASTERCMD: - { - getint(p); - getint(p); - break; - }; - case SV_NOP: { getint(p); break; @@ -697,3 +685,30 @@ void localservertoclient(uchar *buf, int len) // processes any updates from th return; }; }; + +void localservertoclient(int chan, uchar *buf, int len) // processes any updates from the server +{ + incomingdemodata(buf, len); + + ucharbuf p(buf, len); + + switch(chan) + { + case 0: parsepositions(p); break; + case 1: parsemessages(-1, NULL, p); break; + case 2: + while(p.remaining()) + { + int cn = p.get(); + dynent *d = getclient(cn); + int len = p.get(); + len += p.get()<<8; + ucharbuf q(&p.buf[p.len], min(len, p.maxlen-p.len)); + if(d) parsemessages(cn, d, q); + p.len += min(len, p.maxlen-p.len); + }; + break; + case 3: parsemessages(-1, NULL, p); break; + }; +}; + diff --git a/source/src/cube.h b/source/src/cube.h index 78ead911..d11e9db8 100644 --- a/source/src/cube.h +++ b/source/src/cube.h @@ -349,7 +349,7 @@ enum { M_NONE = 0, M_SEARCH, M_HOME, M_ATTACKING, M_PAIN, M_SLEEP, M_AIMING, M_N enum { SV_INITS2C = 0, SV_INITC2S, SV_POS, SV_TEXT, SV_SOUND, SV_CDIS, - SV_GIBDIED, SV_DIED, SV_GIBDAMAGE, SV_DAMAGE, SV_SHOT, SV_FRAGS, + SV_GIBDIED, SV_DIED, SV_GIBDAMAGE, SV_DAMAGE, SV_SHOT, SV_FRAGS, SV_RESUME, SV_TIMEUP, SV_EDITENT, SV_MAPRELOAD, SV_ITEMACC, SV_MAPCHANGE, SV_ITEMSPAWN, SV_ITEMPICKUP, SV_DENIED, SV_PING, SV_PONG, SV_CLIENTPING, SV_GAMEMODE, diff --git a/source/src/editing.cpp b/source/src/editing.cpp index d85e8070..e331dfba 100644 --- a/source/src/editing.cpp +++ b/source/src/editing.cpp @@ -284,7 +284,7 @@ void editheight(int flr, int amount) EDITSEL; bool isfloor = flr==0; editheightxy(isfloor, amount, sel); - addmsg(1, 7, SV_EDITH, sel.x, sel.y, sel.xs, sel.ys, isfloor, amount); + addmsg(SV_EDITH, "ri6", sel.x, sel.y, sel.xs, sel.ys, isfloor, amount); }; COMMAND(editheight, ARG_2INT); @@ -311,7 +311,7 @@ void edittex(int type, int dir) curedittex[atype] = i = min(max(i, 0), 255); int t = lasttex = hdr.texlists[atype][i]; edittexxy(type, t, sel); - addmsg(1, 7, SV_EDITT, sel.x, sel.y, sel.xs, sel.ys, type, t); + addmsg(SV_EDITT, "ri6", sel.x, sel.y, sel.xs, sel.ys, type, t); }; void replace() @@ -344,7 +344,7 @@ void edittype(int type) || sel.x&~-sel.xs || sel.y&~-sel.ys)) { conoutf("corner selection must be power of 2 aligned"); return; }; edittypexy(type, sel); - addmsg(1, 6, SV_EDITS, sel.x, sel.y, sel.xs, sel.ys, type); + addmsg(SV_EDITS, "ri5", sel.x, sel.y, sel.xs, sel.ys, type); }; void heightfield(int t) { edittype(t==0 ? FHF : CHF); }; @@ -375,7 +375,7 @@ void equalize(int flr) bool isfloor = flr==0; EDITSEL; editequalisexy(isfloor, sel); - addmsg(1, 6, SV_EDITE, sel.x, sel.y, sel.xs, sel.ys, isfloor); + addmsg(SV_EDITE, "ri5", sel.x, sel.y, sel.xs, sel.ys, isfloor); }; COMMAND(equalize, ARG_1INT); @@ -389,7 +389,7 @@ void setvdelta(int delta) { EDITSEL; setvdeltaxy(delta, sel); - addmsg(1, 6, SV_EDITD, sel.x, sel.y, sel.xs, sel.ys, delta); + addmsg(SV_EDITD, "ri5", sel.x, sel.y, sel.xs, sel.ys, delta); }; const int MAXARCHVERT = 50; diff --git a/source/src/entities.cpp b/source/src/entities.cpp index 00179218..22c4b0b3 100644 --- a/source/src/entities.cpp +++ b/source/src/entities.cpp @@ -147,7 +147,7 @@ void additem(int i, int &v, int spawnsec, int t) { if(vteam) && f.state == CTFF_DROPPED) { - addmsg(1, 2, SV_FLAGRETURN, team); + addmsg(SV_FLAGRETURN, "ri", team); ents[n].spawned = false; } else if(team != rb_team_int(player1->team)) { - addmsg(1, 2, SV_FLAGPICKUP, team); + addmsg(SV_FLAGPICKUP, "ri", team); ents[n].spawned = false; f.thief = player1; // do this although we don't know if we picked the flag to avoid getting it after a possible respawn f.state = CTFF_STOLEN; f.pick_ack = false; } - else if(team == rb_team_int(player1->team) && f.state == CTFF_INBASE && flaginfos[rb_opposite(team)].state == CTFF_STOLEN && flaginfos[rb_opposite(team)].thief == player1) addmsg(1, 2, SV_FLAGSCORE, rb_opposite(team)); + else if(team == rb_team_int(player1->team) && f.state == CTFF_INBASE && flaginfos[rb_opposite(team)].state == CTFF_STOLEN && flaginfos[rb_opposite(team)].thief == player1) addmsg(SV_FLAGSCORE, "ri", rb_opposite(team)); break; }; }; diff --git a/source/src/main.cpp b/source/src/main.cpp index 4d297089..99acf541 100644 --- a/source/src/main.cpp +++ b/source/src/main.cpp @@ -79,6 +79,9 @@ void show_out_of_renderloop_progress(float bar1, const char *text1, float bar2, int w = scr_w, h = scr_h; glDisable(GL_DEPTH_TEST); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); @@ -110,6 +113,9 @@ void show_out_of_renderloop_progress(float bar1, const char *text1, float bar2, glDisable(GL_BLEND); glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glEnable(GL_DEPTH_TEST); SDL_GL_SwapBuffers(); }; @@ -301,8 +307,9 @@ int main(int argc, char **argv) loadweapons(); log("localconnect"); + extern string clientmap; + s_strcpy(clientmap, "maps/ac_complex"); localconnect(); - changemap("maps/ac_complex"); // if this map is changed, also change depthcorrect() log("mainloop"); int ignore = 5, grabmouse = 0; diff --git a/source/src/physics.cpp b/source/src/physics.cpp index 3056193e..71d961be 100644 --- a/source/src/physics.cpp +++ b/source/src/physics.cpp @@ -213,7 +213,7 @@ void physicsframe() // optimally schedule physics frames inside the gra void selfdamage(dynent *d, int dm) { if(d==player1) selfdamage(dm, -1, d); - else { addmsg(1, 4, SV_DAMAGE, d, dm, d->lifesequence); }; + else { addmsg(SV_DAMAGE, "ri3", d, dm, d->lifesequence); }; //playsound(S_FALL1+rnd(5), &d->o); }; // fixme sound particle_splash(3, dm, 1000, d->o); //edit out? demodamage(dm, d->o); diff --git a/source/src/protos.h b/source/src/protos.h index c3773f2b..e3663cd7 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -34,6 +34,7 @@ extern void purgemenu(int m); // serverbrowser extern void addserver(char *servername); extern char *getservername(int n); +extern bool resolverwait(const char *name, ENetAddress *address); extern void writeservercfg(); // rendergl @@ -59,14 +60,14 @@ extern void finishstrips(); extern void setarraypointers(); // client -extern void localservertoclient(uchar *buf, int len); +extern void localservertoclient(int chan, uchar *buf, int len); extern void connects(char *servername); extern void disconnect(int onlyclean = 0, int async = 0); extern void toserver(char *text); -extern void addmsg(int rel, int num, int type, ...); +extern void addmsg(int type, const char *fmt = NULL, ...); extern bool multiplayer(); extern bool allowedittoggle(); -extern void sendpackettoserv(void *packet); +extern void sendpackettoserv(int chan, struct _ENetPacket *packet); extern void gets2c(); extern void c2sinfo(dynent *d); extern void c2skeepalive(); @@ -227,11 +228,13 @@ extern void rendermd3gun(); extern void loadweapons(); // server +enum { DISC_NONE = 0, DISC_EOP, DISC_CN, DISC_MKICK, DISC_MBAN, DISC_TAGT, DISC_BANREFUSE, DISC_WRONGPW, DISC_MLOGINFAIL, DISC_MAXCLIENTS }; + extern void initserver(bool dedicated, int uprate, char *sdesc, char *ip, char *master, char *passwd, int maxcl, char *maprot, char *masterpwd); // EDIT: AH extern void cleanupserver(); extern void localconnect(); extern void localdisconnect(); -extern void localclienttoserver(struct _ENetPacket *); +extern void localclienttoserver(int chan, struct _ENetPacket *); extern void serverslice(int seconds, unsigned int timeout); extern void putint(ucharbuf &p, int n); extern int getint(ucharbuf &p); diff --git a/source/src/renderextras.cpp b/source/src/renderextras.cpp index 4af8b62a..ea3e3764 100644 --- a/source/src/renderextras.cpp +++ b/source/src/renderextras.cpp @@ -667,6 +667,7 @@ void loadingscreen() glEnable(GL_TEXTURE_2D); glDisable(GL_BLEND); + glColor3f(1, 1, 1); glBindTexture(GL_TEXTURE_2D, 8); glBegin(GL_QUADS); diff --git a/source/src/savegamedemo.cpp b/source/src/savegamedemo.cpp index fd13433a..5d2259b9 100644 --- a/source/src/savegamedemo.cpp +++ b/source/src/savegamedemo.cpp @@ -266,7 +266,7 @@ void demoplaybackstep() }; uchar buf[MAXTRANS]; gzread(f, buf, len); - localservertoclient(buf, len); // update game state + localservertoclient(0, buf, len); // update game state dynent *target = players[democlientnum]; ASSERT(target); diff --git a/source/src/server.cpp b/source/src/server.cpp index b266c0f1..58b1d893 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -6,19 +6,34 @@ #define m_ctf_s (mode==5) #define m_teammode_s (mode==0 || mode==4 || mode==5) -#define valid_client(c) (c >= 0 && c < clients.length() && clients[c].type!=ST_EMPTY) +#define valid_client(c) (clients.inrange(c) && clients[c]->type!=ST_EMPTY) #define valid_flag(f) (f >= 0 && f < 2) enum { ST_EMPTY, ST_LOCAL, ST_TCPIP }; +struct clientscore +{ + int frags; +}; + +struct savedscore : clientscore +{ + string name; + uint ip; +}; + +static vector scores; + struct client // server side version of "dynent" type { int type; + int clientnum; ENetPeer *peer; string hostname; string mapvote; string name; int modevote; + clientscore score; // Added by Rick: For bot voting #ifndef STANDALONE bool addbot, kickbot, changebotskill; @@ -30,9 +45,132 @@ struct client // server side version of "dynent" type // End add bool ismaster; bool isauthed; // for passworded servers + vector position, messages; + int positionoffset, messageoffset; + + void reset() + { + name[0] = 0; + score.frags = 0; + position.setsizenodelete(0); + messages.setsizenodelete(0); + }; }; -vector clients; +vector clients; + +struct worldstate +{ + enet_uint32 uses; + vector positions, messages; +}; + +vector worldstates; + +void cleanworldstate(ENetPacket *packet) +{ + loopv(worldstates) + { + worldstate *ws = worldstates[i]; + if(packet->data >= ws->positions.getbuf() && packet->data <= &ws->positions.last()) ws->uses--; + else if(packet->data >= ws->messages.getbuf() && packet->data <= &ws->messages.last()) ws->uses--; + else continue; + if(!ws->uses) + { + delete ws; + worldstates.remove(i); + }; + break; + }; +}; + +int bsend = 0, brec = 0, laststatus = 0, lastsec = 0; + +void sendpacket(int n, int chan, ENetPacket *packet) +{ + switch(clients[n]->type) + { + case ST_TCPIP: + { + enet_peer_send(clients[n]->peer, chan, packet); + bsend += packet->dataLength; + break; + }; + + case ST_LOCAL: + localservertoclient(chan, packet->data, (int)packet->dataLength); + break; + }; +}; + +static bool reliablemessages = false; + +bool buildworldstate() +{ + worldstate &ws = *new worldstate; + loopv(clients) + { + client &c = *clients[i]; + if(c.type!=ST_TCPIP) continue; + if(c.position.empty()) c.positionoffset = -1; + else + { + c.positionoffset = ws.positions.length(); + loopvj(c.position) ws.positions.add(c.position[j]); + }; + if(c.messages.empty()) c.messageoffset = -1; + else + { + c.messageoffset = ws.messages.length(); + ws.messages.add(c.clientnum); + ws.messages.add(c.messages.length()&0xFF); + ws.messages.add(c.messages.length()>>8); + loopvj(c.messages) ws.messages.add(c.messages[j]); + }; + }; + int psize = ws.positions.length(), msize = ws.messages.length(); + loopi(psize) { uchar c = ws.positions[i]; ws.positions.add(c); }; + loopi(msize) { uchar c = ws.messages[i]; ws.messages.add(c); }; + ws.uses = 0; + loopv(clients) + { + client &c = *clients[i]; + if(c.type!=ST_TCPIP) continue; + ENetPacket *packet; + if(psize && (c.positionoffset<0 || psize-c.position.length()>0)) + { + packet = enet_packet_create(&ws.positions[c.positionoffset<0 ? 0 : c.positionoffset+c.position.length()], + c.positionoffset<0 ? psize : psize-c.position.length(), + ENET_PACKET_FLAG_NO_ALLOCATE); + sendpacket(c.clientnum, 0, packet); + if(!packet->referenceCount) enet_packet_destroy(packet); + else { ++ws.uses; packet->freeCallback = cleanworldstate; }; + }; + c.position.setsizenodelete(0); + + if(msize && (c.messageoffset<0 || msize-3-c.messages.length()>0)) + { + packet = enet_packet_create(&ws.messages[c.messageoffset<0 ? 0 : c.messageoffset+3+c.messages.length()], + c.messageoffset<0 ? msize : msize-3-c.messages.length(), + (reliablemessages ? ENET_PACKET_FLAG_RELIABLE : 0) | ENET_PACKET_FLAG_NO_ALLOCATE); + sendpacket(c.clientnum, 2, packet); + if(!packet->referenceCount) enet_packet_destroy(packet); + else { ++ws.uses; packet->freeCallback = cleanworldstate; }; + }; + c.messages.setsizenodelete(0); + }; + reliablemessages = false; + if(!ws.uses) + { + delete &ws; + return false; + } + else + { + worldstates.add(&ws); + return true; + }; +}; int maxclients = 8; string smapname; @@ -42,15 +180,46 @@ char *masterpasswd = NULL; int numclients() { int num = 0; - loopv(clients) if(clients[i].type!=ST_EMPTY) num++; + loopv(clients) if(clients[i]->type!=ST_EMPTY) num++; return num; }; void zapclient(int c) { if(c<0 || c>=clients.length()) return; - clients[c].type = ST_EMPTY; - clients[c].ismaster = clients[c].isauthed = false; + clients[c]->type = ST_EMPTY; + clients[c]->ismaster = clients[c]->isauthed = false; +}; + +clientscore *findscore(client &c, bool insert) +{ + if(c.type!=ST_TCPIP) return NULL; + if(!insert) loopv(clients) + { + client &o = *clients[i]; + if(o.type!=ST_TCPIP) + if(o.clientnum!=c.clientnum && o.peer->address.host==c.peer->address.host && !strcmp(o.name, c.name)) return &o.score; + }; + loopv(scores) + { + savedscore &sc = scores[i]; + if(!strcmp(sc.name, c.name) && sc.ip==c.peer->address.host) return ≻ + }; + if(!insert) return NULL; + savedscore &sc = scores.add(); + s_strcpy(sc.name, c.name); + sc.ip = c.peer->address.host; + (clientscore &)sc = c.score; + return ≻ +}; + +void resetscores() +{ + loopv(clients) if(clients[i]->type==ST_TCPIP) + { + clients[i]->score.frags = 0; + }; + scores.setsize(0); }; vector sents; @@ -81,43 +250,34 @@ bool mapreload = false; char *serverpassword = ""; bool isdedicated; -ENetHost * serverhost = NULL; -int bsend = 0, brec = 0, laststatus = 0, lastsec = 0; +ENetHost *serverhost = NULL; -#define MAXOBUF 100000 +void process(ENetPacket *packet, int sender, int chan); +void multicast(ENetPacket *packet, int sender, int chan); +void disconnect_client(int n, int reason); -void process(ENetPacket *packet, int sender); -void multicast(ENetPacket *packet, int sender); -void disconnect_client(int n, char *reason); - -void send(int n, ENetPacket *packet) +void sendf(int cn, int chan, const char *format, ...) { - if(!packet) return; - switch(clients[n].type) + bool reliable = false; + if(*format=='r') { reliable = true; ++format; }; + ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, reliable ? ENET_PACKET_FLAG_RELIABLE : 0); + ucharbuf p(packet->data, packet->dataLength); + va_list args; + va_start(args, format); + while(*format) switch(*format++) { - case ST_TCPIP: + case 'i': { - enet_peer_send(clients[n].peer, 0, packet); - bsend += packet->dataLength; + int n = isdigit(*format) ? *format++-'0' : 1; + loopi(n) putint(p, va_arg(args, int)); break; }; - - case ST_LOCAL: - localservertoclient(packet->data, packet->dataLength); - break; - + case 's': sendstring(va_arg(args, const char *), p); break; }; -}; - -void send2(bool rel, int cn, int a, int b) -{ - ENetPacket *packet = enet_packet_create(NULL, 32, rel ? ENET_PACKET_FLAG_RELIABLE : 0); - ucharbuf p(packet->data, packet->dataLength); - putint(p, a); - putint(p, b); + va_end(args); enet_packet_resize(packet, p.length()); - if(cn<0) process(packet, -1); - else send(cn, packet); + if(cn<0) multicast(packet, -1, chan); + else sendpacket(cn, chan, packet); if(packet->referenceCount==0) enet_packet_destroy(packet); }; @@ -143,8 +303,8 @@ void sendflaginfo(int flag, int action, int cn = -1) if(f.state==CTFF_STOLEN || action==SV_FLAGRETURN) putint(p, f.thief_cn); else if(f.state==CTFF_DROPPED) loopi(3) putint(p, f.pos[i]); enet_packet_resize(packet, p.length()); - if(cn<0) multicast(packet, -1); - else send(cn, packet); + if(cn<0) multicast(packet, -1, 1); + else sendpacket(cn, 1, packet); if(packet->referenceCount==0) enet_packet_destroy(packet); }; @@ -162,22 +322,20 @@ void ctfreset(bool send=true) void sendservmsg(char *msg, int client=-1) { - ENetPacket *packet = enet_packet_create(NULL, _MAXDEFSTR+10, ENET_PACKET_FLAG_RELIABLE); - ucharbuf p(packet->data, packet->dataLength); - putint(p, SV_SERVMSG); - sendstring(msg, p); - enet_packet_resize(packet, p.length()); - if(client==-1) multicast(packet, -1); else send(client, packet); - if(packet->referenceCount==0) enet_packet_destroy(packet); + sendf(client, 1, "ris", SV_SERVMSG, msg); }; -void disconnect_client(int n, char *reason) +char *disc_reasons[] = { "normal", "end of packet", "client num", "kicked by master", "banned by master", "tag type", "connection refused due to ban", "wrong password", "failed master login", "server FULL (maxclients)"}; + +void disconnect_client(int n, int reason) { - if(n<0 || n>=clients.length()) return; - printf("disconnecting client (%s) [%s]\n", clients[n].hostname, reason); - enet_peer_disconnect(clients[n].peer); + if(n<0 || n>=clients.length() || clients[n]->type!=ST_TCPIP) return; + clientscore *sc = findscore(*clients[n], true); + if(sc) *sc = clients[n]->score; + printf("disconnecting client (%s) [%s]\n", clients[n]->hostname, disc_reasons[reason]); + enet_peer_disconnect(clients[n]->peer, reason); zapclient(n); - send2(true, -1, SV_CDIS, n); + sendf(-1, 1, "rii", SV_CDIS, n); }; void resetitems() { sents.setsize(0); notgotitems = true; }; @@ -189,7 +347,7 @@ void pickup(uint i, int sec, int sender) // server side item pickup, ack { sents[i].spawned = false; sents[i].spawnsecs = sec; - send2(true, sender, SV_ITEMACC, i); + sendf(sender, 1, "rii", SV_ITEMACC, i); }; }; @@ -276,32 +434,32 @@ void nextcfgset() // load next maprotation set void resetvotes() { - loopv(clients) clients[i].mapvote[0] = 0; + loopv(clients) clients[i]->mapvote[0] = 0; }; bool vote(char *map, int reqmode, int sender) { if(!valid_client(sender)) return false; - if(configsets.length() && curcfgset < configsets.length() && !configsets[curcfgset].vote && !clients[sender].ismaster) + if(configsets.length() && curcfgset < configsets.length() && !configsets[curcfgset].vote && !clients[sender]->ismaster) { - s_sprintfd(msg)("%s voted, but voting is currently disabled", clients[sender].name); + s_sprintfd(msg)("%s voted, but voting is currently disabled", clients[sender]->name); sendservmsg(msg); return false; }; - s_strcpy(clients[sender].mapvote, map); - clients[sender].modevote = reqmode; + s_strcpy(clients[sender]->mapvote, map); + clients[sender]->modevote = reqmode; int yes = 0, no = 0; - loopv(clients) if(clients[i].type!=ST_EMPTY) + loopv(clients) if(clients[i]->type!=ST_EMPTY) { - if(clients[i].mapvote[0]) { if(strcmp(clients[i].mapvote, map)==0 && clients[i].modevote==reqmode) yes++; else no++; } + if(clients[i]->mapvote[0]) { if(strcmp(clients[i]->mapvote, map)==0 && clients[i]->modevote==reqmode) yes++; else no++; } else no++; }; if(yes==1 && no==0) return true; // single player - s_sprintfd(msg)("%s suggests %s on map %s (set map to vote)", clients[sender].name, modestr(reqmode), map); + s_sprintfd(msg)("%s suggests %s on map %s (set map to vote)", clients[sender]->name, modestr(reqmode), map); sendservmsg(msg); - if(yes/(float)(yes+no) <= 0.5f && !clients[sender].ismaster) return false; + if(yes/(float)(yes+no) <= 0.5f && !clients[sender]->ismaster) return false; sendservmsg("vote passed"); resetvotes(); return true; @@ -315,60 +473,60 @@ void resetbotvotes() { loopv(clients) { - clients[i].addbot = false; - clients[i].kickbot = false; - clients[i].changebotskill = false; - clients[i].kickallbots = false; - clients[i].botcount = 0; - clients[i].botteam[0] = 0; - clients[i].botname[0] = 0; - clients[i].botskill = -1; - } + clients[i]->addbot = false; + clients[i]->kickbot = false; + clients[i]->changebotskill = false; + clients[i]->kickallbots = false; + clients[i]->botcount = 0; + clients[i]->botteam[0] = 0; + clients[i]->botname[0] = 0; + clients[i]->botskill = -1; + }; }; bool addbotvote(int count, char *team, int skill, char *name, int sender) { - clients[sender].addbot = true; - clients[sender].kickbot = false; - clients[sender].changebotskill = false; - clients[sender].botcount = (count>=0) ? count : 0; - if (team && team[0]) s_strcpy(clients[sender].botteam, team); - else clients[sender].botteam[0] = 0; - clients[sender].botskill = skill; - if (name && name[0]) s_strcpy(clients[sender].botname, name); - else clients[sender].botname[0] = 0; + clients[sender]->addbot = true; + clients[sender]->kickbot = false; + clients[sender]->changebotskill = false; + clients[sender]->botcount = (count>=0) ? count : 0; + if (team && team[0]) s_strcpy(clients[sender]->botteam, team); + else clients[sender]->botteam[0] = 0; + clients[sender]->botskill = skill; + if (name && name[0]) s_strcpy(clients[sender]->botname, name); + else clients[sender]->botname[0] = 0; int yes = 0, no = 0; - loopv(clients) if(clients[i].type!=ST_EMPTY) + loopv(clients) if(clients[i]->type!=ST_EMPTY) { - if (clients[i].addbot) + if (clients[i]->addbot) { - if (!strcmp(clients[i].botteam, team) && !strcmp(clients[i].botname, name) && - (clients[i].botskill == skill) && - (clients[i].botcount == clients[sender].botcount)) + if (!strcmp(clients[i]->botteam, team) && !strcmp(clients[i]->botname, name) && + (clients[i]->botskill == skill) && + (clients[i]->botcount == clients[sender]->botcount)) yes++; else no++; } else no++; - } + }; if(yes==1 && no==0) return true; // single player - s_sprintfd(msg)("%s suggests to add a bot", clients[sender].name); - if (team && team[0]) + s_sprintfd(msg)("%s suggests to add a bot", clients[sender]->name); + if(team && team[0]) { - strcat(msg, " on team "); - strcat(msg, team); - } + strcat(msg, " on team "); + strcat(msg, team); + }; - if (skill!=-1) + if(skill!=-1) { - strcat(msg, ", with skill "); - strcat(msg, SkillNrToSkillName(skill)); - } + strcat(msg, ", with skill "); + strcat(msg, SkillNrToSkillName(skill)); + }; - if (name && name[0]) + if(name && name[0]) { - strcat(msg, " named "); - strcat(msg, name); + strcat(msg, " named "); + strcat(msg, name); } sendservmsg(msg); @@ -382,25 +540,25 @@ bool addbotvote(int count, char *team, int skill, char *name, int sender) bool kickbotvote(int specific, char *name, int sender) { - clients[sender].addbot = false; - clients[sender].kickbot = true; - clients[sender].changebotskill = false; - clients[sender].kickallbots = !specific; - if (name && name[0]) s_strcpy(clients[sender].botname, name); - else clients[sender].botname[0] = 0; + clients[sender]->addbot = false; + clients[sender]->kickbot = true; + clients[sender]->changebotskill = false; + clients[sender]->kickallbots = !specific; + if(name && name[0]) s_strcpy(clients[sender]->botname, name); + else clients[sender]->botname[0] = 0; int yes = 0, no = 0; - loopv(clients) if(clients[i].type!=ST_EMPTY) + loopv(clients) if(clients[i]->type!=ST_EMPTY) { - if (clients[i].kickbot) + if(clients[i]->kickbot) { - if (clients[sender].kickallbots) + if(clients[sender]->kickallbots) { - if (clients[i].kickallbots) yes++; + if(clients[i]->kickallbots) yes++; else no++; } else { - if (!clients[i].kickallbots && !strcmp(clients[i].botname, name)) + if(!clients[i]->kickallbots && !strcmp(clients[i]->botname, name)) yes++; else no++; @@ -411,11 +569,11 @@ bool kickbotvote(int specific, char *name, int sender) if(yes==1 && no==0) return true; // single player char msg[256]; - if (clients[sender].kickallbots) - sprintf(msg, "%s suggests to kick all bots", clients[sender].name); + if(clients[sender]->kickallbots) + sprintf(msg, "%s suggests to kick all bots", clients[sender]->name); else - sprintf(msg, "%s suggests to kick bot %s", clients[sender].name, - clients[sender].botname); + sprintf(msg, "%s suggests to kick bot %s", clients[sender]->name, + clients[sender]->botname); sendservmsg(msg); if(yes/(float)(yes+no) <= 0.5f) return false; @@ -426,24 +584,24 @@ bool kickbotvote(int specific, char *name, int sender) bool botskillvote(int skill, int sender) { - clients[sender].addbot = false; - clients[sender].kickbot = false; - clients[sender].changebotskill = true; - clients[sender].botskill = skill; + clients[sender]->addbot = false; + clients[sender]->kickbot = false; + clients[sender]->changebotskill = true; + clients[sender]->botskill = skill; int yes = 0, no = 0; - loopv(clients) if(clients[i].type!=ST_EMPTY) + loopv(clients) if(clients[i]->type!=ST_EMPTY) { - if (clients[i].changebotskill) + if(clients[i]->changebotskill) { - if (clients[sender].botskill == clients[i].botskill) yes++; + if(clients[sender]->botskill == clients[i]->botskill) yes++; else no++; } else no++; } if(yes==1 && no==0) return true; // single player - s_sprintfd(msg)("%s suggests to change the skill of all bots to: %s", clients[sender].name, - SkillNrToSkillName(clients[sender].botskill)); + s_sprintfd(msg)("%s suggests to change the skill of all bots to: %s", clients[sender]->name, + SkillNrToSkillName(clients[sender]->botskill)); sendservmsg(msg); if(yes/(float)(yes+no) <= 0.5f) return false; sendservmsg("vote passed"); @@ -508,14 +666,7 @@ void botcommand(ucharbuf &p, char *text, int sender) // force map change, EDIT: AH void changemap() { - ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); - ucharbuf p(packet->data, packet->dataLength); - putint(p, SV_MAPCHANGE); - sendstring(smapname, p); - putint(p, mode); - enet_packet_resize(packet, p.length()); - multicast(packet, -1); - if(packet->referenceCount==0) enet_packet_destroy(packet); + sendf(-1, 1, "risi", SV_MAPCHANGE, smapname, mode); }; struct ban @@ -529,7 +680,7 @@ vector bans; bool isbanned(int cn) { if(!valid_client(cn)) return false; - client &c = clients[cn]; + client &c = *clients[cn]; loopv(bans) { ban &b = bans[i]; @@ -544,31 +695,31 @@ void getmaster(int sender, char *pwd) if(!pwd[0] || !isdedicated) return; if(masterpasswd && !strcmp(masterpasswd, pwd)) { - clients[sender].ismaster = true; + clients[sender]->ismaster = true; sendservmsg("master login successful", sender); } - else disconnect_client(sender, "failed master login"); + else disconnect_client(sender, DISC_MLOGINFAIL); }; void mastercmd(int sender, int cmd, int a) { if(!isdedicated) return; - if(clients[sender].ismaster==false) return; + if(clients[sender]->ismaster==false) return; switch(cmd) { case MCMD_KICK: { if(!valid_client(a)) return; - disconnect_client(a, "kicked by master"); + disconnect_client(a, DISC_MKICK); sendservmsg("player kicked"); break; }; case MCMD_BAN: { if(!valid_client(a)) return; - ban b = { clients[a].peer->address, lastsec+20*60 }; + ban b = { clients[a]->peer->address, lastsec+20*60 }; bans.add(b); - disconnect_client(a, "banned by master"); + disconnect_client(a, DISC_MBAN); sendservmsg("player banned"); break; }; @@ -586,7 +737,7 @@ void sendmapinfo(int c) if(!valid_client(c)) return; if(smapname[0]) { - ENetPacket * packet = enet_packet_create (NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); + ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); ucharbuf p(packet->data, packet->dataLength); putint(p, SV_MAPCHANGE); sendstring(smapname, p); @@ -595,67 +746,82 @@ void sendmapinfo(int c) loopv(sents) if(sents[i].spawned) putint(p, i); putint(p, -1); enet_packet_resize(packet, p.length()); - send(c, packet); + sendpacket(c, 1, packet); }; }; - // server side processing of updates: does very little and most state is tracked client only // could be extended to move more gameplay to server (at expense of lag) #ifdef STANDALONE -#define CN_CHECK if(!valid_client(cn)) { if(sender>=0) disconnect_client(sender, "client num"); return; }; +#define CN_CHECK if((cn>=0 && cn!=sender) || !valid_client(cn)) { if(sender>=0) disconnect_client(sender, DISC_CN); return; }; #define SENDER_CHECK if(sender<0) return; #else -#define CN_CHECK if(!valid_client(cn)) { if(sender>=0) disconnect_client(sender, "client num"); conoutf("invalid client (msg %i)", type); return; }; +#define CN_CHECK if((cn>=0 && cn!=sender) || !valid_client(cn)) { if(sender>=0) disconnect_client(sender, DISC_CN); conoutf("invalid client (msg %i)", type); return; }; #define SENDER_CHECK if(sender<0) { conoutf("invalid sender (msg %i)", type); return; }; #endif - -int tmp_pos[3]; - -void process(ENetPacket *packet, int sender) // sender may be -1 +void process(ENetPacket *packet, int sender, int chan) // sender may be -1 { ucharbuf p(packet->data, packet->dataLength); char text[MAXTRANS]; - int cn = -1, type; + client *cl = sender>=0 ? clients[sender] : NULL; + int cn = sender, type; + int tmp_pos[3]; - if(serverpassword[0] && sender>=0 && sender<=clients.length() && !clients[sender].isauthed) + if(serverpassword[0] && sender>=0 && sender<=clients.length() && !clients[sender]->isauthed) { int msg = getint(p); getstring(text, p); - if(msg != SV_PWD || !text[0] || strcmp(text, serverpassword)) disconnect_client(sender, "wrong password"); + if(msg != SV_PWD || !text[0] || strcmp(text, serverpassword)) disconnect_client(sender, DISC_WRONGPW); else { - clients[sender].isauthed = true; + clients[sender]->isauthed = true; sendmapinfo(sender); }; return; }; - while(p.remaining()) switch(type = getint(p)) + if(packet->flags&ENET_PACKET_FLAG_RELIABLE) reliablemessages = true; + + #define QUEUE_MSG { while(curmsgmessages.add(p.buf[curmsg++]); } + int curmsg; + while((curmsg = p.length()) < p.maxlen) switch(type = getint(p)) { case SV_CDIS: { int n = getint(p); if(m_ctf_s) loopi(2) if(ctfflags[i].state==CTFF_STOLEN && ctfflags[i].thief_cn==n) - send2(true, -1, SV_FLAGDROP, i); + sendf(-1, 1, "rii", SV_FLAGDROP, i); + QUEUE_MSG; break; }; case SV_TEXT: getstring(text, p); + QUEUE_MSG; break; case SV_INITC2S: + { CN_CHECK; + bool newclient = false; + if(!clients[cn]->name[0]) newclient = true; getstring(text, p); - s_strcpy(clients[cn].name, text); + if(!text[0]) s_strcpy(text, "unarmed"); + s_strcpy(clients[cn]->name, text); + if(newclient) + { + clientscore *sc = findscore(*clients[cn], false); + if(sc) sendf(-1, 1, "riii", SV_RESUME, cn, sc->frags); + }; getstring(text, p); getint(p); getint(p); + QUEUE_MSG; break; + }; case SV_MAPCHANGE: { @@ -671,9 +837,10 @@ void process(ENetPacket *packet, int sender) // sender may be -1 interm = 0; s_strcpy(smapname, text); resetitems(); - sender = -1; laststatus = lastsec-61; ctfbroadcast = true; + resetscores(); + changemap(); break; }; @@ -687,6 +854,7 @@ void process(ENetPacket *packet, int sender) // sender may be -1 sents[n].spawned = true; }; notgotitems = false; + QUEUE_MSG; break; }; @@ -695,29 +863,31 @@ void process(ENetPacket *packet, int sender) // sender may be -1 SENDER_CHECK; int n = getint(p); pickup(n, getint(p), sender); + QUEUE_MSG; break; }; case SV_BOTITEMPICKUP: { loopi(2) getint(p); + QUEUE_MSG; break; }; case SV_PING: CN_CHECK; - send2(false, cn, SV_PONG, getint(p)); + sendf(cn, 1, "ii", SV_PONG, getint(p)); break; case SV_POS: { cn = getint(p); CN_CHECK; - if(cn!=sender) { if(sender>=0) disconnect_client(sender, "client num"); return; }; - int size = msgsizelookup(type); - if(size==-1) { disconnect_client(sender, "msg size"); return; }; - loopi(3) tmp_pos[i] = getint(p); - loopi(size-5) getint(p); + loopi(3) tmp_pos[i] = getuint(p); + getuint(p); + loopi(6) getint(p); + cl->position.setsizenodelete(0); + while(curmsgposition.add(p.buf[curmsg++]); break; }; @@ -733,28 +903,28 @@ void process(ENetPacket *packet, int sender) // sender may be -1 }; sendmaps(sender, text, mapsize, &p.buf[p.len]); p.len += mapsize; - return; + break; }; case SV_RECVMAP: SENDER_CHECK; - send(sender, recvmap(sender)); - return; + sendpacket(sender, 3, recvmap(sender)); + break; // Added by Rick: Bot specifc messages #ifndef STANDALONE case SV_ADDBOT: getint(p); getstring(text, p); - //s_strcpy(clients[cn].name, text); + //s_strcpy(clients[cn]->name, text); getstring(text, p); getint(p); + QUEUE_MSG; break; case SV_BOTCOMMAND: // Client asked server for a bot command - { botcommand(p, text, sender); + QUEUE_MSG; break; - } #endif // End add by Rick @@ -772,6 +942,7 @@ void process(ENetPacket *packet, int sender) // sender may be -1 f.lastupdate = lastsec; sendflaginfo(flag, SV_FLAGPICKUP); }; + QUEUE_MSG; break; }; @@ -825,7 +996,7 @@ void process(ENetPacket *packet, int sender) // sender may be -1 SENDER_CHECK; getstring(text, p); getmaster(sender, text); - return; + break; }; case SV_MASTERCMD: @@ -840,25 +1011,33 @@ void process(ENetPacket *packet, int sender) // sender may be -1 case SV_PWD: { getstring(text, p); - return; + break; }; + case SV_FRAGS: + { + CN_CHECK; + cl->score.frags = getint(p); + QUEUE_MSG; + break; + }; + default: { int size = msgsizelookup(type); - if(size==-1) { if(sender>=0) disconnect_client(sender, "tag type"); return; }; + if(size==-1) { if(sender>=0) disconnect_client(sender, DISC_TAGT); return; }; loopi(size-1) getint(p); + QUEUE_MSG; + break; }; }; - if(p.overread()) { if(sender>=0) - disconnect_client(sender, "end of packet"); return; }; - multicast(packet, sender); + if(p.overread()) { if(sender>=0) disconnect_client(sender, DISC_EOP); return; }; }; void send_welcome(int n) { - ENetPacket *packet = enet_packet_create (NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); + ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); ucharbuf p(packet->data, packet->dataLength); putint(p, SV_INITS2C); putint(p, n); @@ -867,9 +1046,7 @@ void send_welcome(int n) putint(p, smapname[0]); putint(p, serverpassword[0] ? 1 : 0); int numcl = numclients(); - int discn = numcl>maxclients ? 1 : (isbanned(n) ? 2 : 0); - putint(p, discn); - if(smapname[0] && !discn && !serverpassword[0]) + if(smapname[0] && !serverpassword[0]) { putint(p, SV_MAPCHANGE); sendstring(smapname, p); @@ -882,29 +1059,37 @@ void send_welcome(int n) }; }; enet_packet_resize(packet, p.length()); - send(n, packet); + sendpacket(n, 1, packet); if(smapname[0] && m_ctf_s) loopi(2) sendflaginfo(i, -1, n); // EDIT: AH }; -void multicast(ENetPacket *packet, int sender) +void multicast(ENetPacket *packet, int sender, int chan) { loopv(clients) { - if(i==sender) continue; - send(i, packet); + if(i==sender) continue; + sendpacket(i, chan, packet); }; }; -void localclienttoserver(ENetPacket *packet) +void localclienttoserver(int chan, ENetPacket *packet) { - process(packet, 0); - if(!packet->referenceCount) enet_packet_destroy (packet); + process(packet, 0, chan); + if(!packet->referenceCount) enet_packet_destroy(packet); }; client &addclient() { - loopv(clients) if(clients[i].type==ST_EMPTY) return clients[i]; - return clients.add(); + client *c = NULL; + loopv(clients) if(clients[i]->type==ST_EMPTY) { c = clients[i]; break; }; + if(!c) + { + c = new client; + c->clientnum = clients.length(); + clients.add(c); + }; + c->reset(); + return *c; }; void checkintermission() @@ -914,14 +1099,14 @@ void checkintermission() interm = lastsec+10; mapend = lastsec+1000; }; - send2(true, -1, SV_TIMEUP, minremain--); + sendf(-1, 1, "rii", SV_TIMEUP, minremain--); }; /*void startintermission() { minremain = 0; checkintermission(); };*/ void resetserverifempty() { - loopv(clients) if(clients[i].type!=ST_EMPTY) return; + loopv(clients) if(clients[i]->type!=ST_EMPTY) return; //clients.setsize(0); smapname[0] = 0; resetvotes(); @@ -938,7 +1123,23 @@ void resetserverifempty() }; int nonlocalclients = 0; -int lastconnect = 0; + +int refuseconnect(int i) +{ + if(valid_client(i) && isbanned(i)) return DISC_BANREFUSE; + return DISC_NONE; +}; + +void sendworldstate() +{ + static enet_uint32 lastsend = 0; + if(clients.empty()) return; + enet_uint32 curtime = enet_time_get()-lastsend; + if(curtime<40) return; + bool flush = buildworldstate(); + lastsend += curtime - (curtime%40); + if(flush) enet_host_flush(serverhost); +}; void serverslice(int seconds, unsigned int timeout) // main server update, called from cube main loop in sp, or dedicated server loop { @@ -948,7 +1149,7 @@ void serverslice(int seconds, unsigned int timeout) // main server update, cal { sents[i].spawnsecs = 0; sents[i].spawned = true; - send2(true, -1, SV_ITEMSPAWN, i); + sendf(-1, 1, "rii", SV_ITEMSPAWN, i); }; }; @@ -963,7 +1164,7 @@ void serverslice(int seconds, unsigned int timeout) // main server update, cal sendflaginfo(i, -1); s_sprintfd(msg)("the server reset the %s flag", rb_team_string(i)); sendservmsg(msg); - send2(true, -1, SV_SOUND, S_FLAGRETURN); + sendf(-1, 1, "rii", SV_SOUND, S_FLAGRETURN); }; }; }; @@ -981,9 +1182,9 @@ void serverslice(int seconds, unsigned int timeout) // main server update, cal changemap(); ctfbroadcast = true; } - else loopv(clients) if(clients[i].type!=ST_EMPTY) + else loopv(clients) if(clients[i]->type!=ST_EMPTY) { - send2(true, i, SV_MAPRELOAD, 0); // ask a client to trigger map reload + sendf(i, 1, "rii", SV_MAPRELOAD, 0); // ask a client to trigger map reload mapreload = true; break; }; @@ -1005,7 +1206,7 @@ void serverslice(int seconds, unsigned int timeout) // main server update, cal if(seconds-laststatus>60) // display bandwidth stats, useful for server ops { nonlocalclients = 0; - loopv(clients) if(clients[i].type==ST_TCPIP) nonlocalclients++; + loopv(clients) if(clients[i]->type==ST_TCPIP) nonlocalclients++; laststatus = seconds; if(nonlocalclients || bsend || brec) { @@ -1020,13 +1221,6 @@ void serverslice(int seconds, unsigned int timeout) // main server update, cal ENetEvent event; if(enet_host_service(serverhost, &event, timeout) > 0) { - if(numplayers>maxclients) - { - disconnect_client(lastconnect, "maxclients reached"); - } - - loopv(clients) if(valid_client(i) && isbanned(i)) disconnect_client(i, "connection refused due to ban"); - switch(event.type) { case ENET_EVENT_TYPE_CONNECT: @@ -1034,33 +1228,41 @@ void serverslice(int seconds, unsigned int timeout) // main server update, cal client &c = addclient(); c.type = ST_TCPIP; c.peer = event.peer; - c.peer->data = (void *)(&c-&clients[0]); + c.peer->data = (void *)c.clientnum; c.ismaster = c.isauthed = false; char hn[1024]; - s_strcpy(c.hostname, (enet_address_get_host(&c.peer->address, hn, sizeof(hn))==0) ? hn : "localhost"); + s_strcpy(c.hostname, (enet_address_get_host(&c.peer->address, hn, sizeof(hn))==0) ? hn : "unknown"); printf("client connected (%s)\n", c.hostname); - send_welcome(lastconnect = &c-&clients[0]); + int reason = DISC_MAXCLIENTS; + if(nonlocalclientsdataLength; int cn = (int)event.peer->data; - if(!valid_client(cn)) break; - process(event.packet, cn); + if(valid_client(cn)) process(event.packet, cn, event.channelID); if(event.packet->referenceCount==0) enet_packet_destroy(event.packet); break; - } + }; case ENET_EVENT_TYPE_DISCONNECT: + { if(!valid_client((int)event.peer->data)) break; - printf("disconnected client (%s)\n", clients[(int)event.peer->data].hostname); + client &c = *clients[(int)event.peer->data]; + printf("disconnected client (%s)\n", c.hostname); + clientscore *sc = findscore(c, true); + if(sc) *sc = c.score; zapclient((int)event.peer->data); - send2(true, -1, SV_CDIS, (int)event.peer->data); + sendf(-1, 1, "rii", SV_CDIS, (int)event.peer->data); event.peer->data = (void *)-1; break; + }; }; }; + sendworldstate(); }; void cleanupserver() @@ -1070,7 +1272,7 @@ void cleanupserver() void localdisconnect() { - loopv(clients) if(clients[i].type==ST_LOCAL) zapclient(i); + loopv(clients) if(clients[i]->type==ST_LOCAL) zapclient(i); }; void localconnect() @@ -1078,7 +1280,7 @@ void localconnect() client &c = addclient(); c.type = ST_LOCAL; s_strcpy(c.hostname, "local"); - send_welcome(&c-&clients[0]); + send_welcome(c.clientnum); }; void initserver(bool dedicated, int uprate, char *sdesc, char *ip, char *master, char *passwd, int maxcl, char *maprot, char *masterpwd) // EDIT: AH @@ -1091,9 +1293,9 @@ void initserver(bool dedicated, int uprate, char *sdesc, char *ip, char *master, { ENetAddress address = { ENET_HOST_ANY, CUBE_SERVER_PORT }; if(*ip && enet_address_set_host(&address, ip)<0) printf("WARNING: server ip not resolved"); - serverhost = enet_host_create(&address, MAXCLIENTS, 0, uprate); + serverhost = enet_host_create(&address, maxclients, 0, uprate); if(!serverhost) fatal("could not create server host\n"); - loopi(MAXCLIENTS) serverhost->peers[i].data = (void *)-1; + loopi(maxclients) serverhost->peers[i].data = (void *)-1; if(!maprot || !maprot[0]) maprot = newstring("config/maprot.cfg"); readscfg(path(maprot)); // EDIT: AH if(masterpwd && masterpwd[0]) masterpasswd = masterpwd; diff --git a/source/src/serverbrowser.cpp b/source/src/serverbrowser.cpp index bfb88d28..2b48fa56 100644 --- a/source/src/serverbrowser.cpp +++ b/source/src/serverbrowser.cpp @@ -193,10 +193,12 @@ struct serverinfo string full; string map; string sdesc; - int mode, numplayers, ping, protocol, minremain; + int mode, numplayers, ping, protocol, minremain, resolved; ENetAddress address; }; +enum { UNRESOLVED = 0, RESOLVING, RESOLVED }; + vector servers; ENetSocket pingsock = ENET_SOCKET_NULL; int lastinfo = 0; @@ -216,6 +218,7 @@ void addserver(char *servername) si.minremain = 0; si.map[0] = 0; si.sdesc[0] = 0; + si.resolved = UNRESOLVED; si.address.host = ENET_HOST_ANY; si.address.port = CUBE_SERVINFO_PORT; }; @@ -239,16 +242,29 @@ void pingservers() void checkresolver() { + int resolving = 0; + loopv(servers) + { + serverinfo &si = servers[i]; + if(si.resolved == RESOLVED) continue; + if(si.address.host == ENET_HOST_ANY) + { + if(si.resolved == UNRESOLVED) { si.resolved = RESOLVING; resolverquery(si.name); }; + resolving++; + }; + }; + if(!resolving) return; + const char *name = NULL; ENetAddress addr = { ENET_HOST_ANY, CUBE_SERVINFO_PORT }; while(resolvercheck(&name, &addr)) { - if(addr.host == ENET_HOST_ANY) continue; loopv(servers) { serverinfo &si = servers[i]; if(name == si.name) { + si.resolved = RESOLVED; si.address = addr; addr.host = ENET_HOST_ANY; break; diff --git a/source/src/serverms.cpp b/source/src/serverms.cpp index fa538542..b6a4d190 100644 --- a/source/src/serverms.cpp +++ b/source/src/serverms.cpp @@ -2,6 +2,13 @@ #include "cube.h" +#ifdef STANDALONE +bool resolverwait(const char *name, ENetAddress *address) +{ + return enet_address_set_host(address, name) >= 0; +}; +#endif + ENetSocket mssock = ENET_SOCKET_NULL; void httpgetsend(ENetAddress &ad, char *hostname, char *req, char *ref, char *agent) @@ -9,8 +16,7 @@ void httpgetsend(ENetAddress &ad, char *hostname, char *req, char *ref, char *ag if(ad.host==ENET_HOST_ANY) { printf("looking up %s...\n", hostname); - enet_address_set_host(&ad, hostname); - if(ad.host==ENET_HOST_ANY) return; + if(!resolverwait(hostname, &ad)) return; }; if(mssock!=ENET_SOCKET_NULL) enet_socket_destroy(mssock); mssock = enet_socket_create(ENET_SOCKET_TYPE_STREAM, NULL); diff --git a/source/src/serverutil.cpp b/source/src/serverutil.cpp index 2269ad91..4a0a7a9e 100644 --- a/source/src/serverutil.cpp +++ b/source/src/serverutil.cpp @@ -83,25 +83,10 @@ const char *modenames[] = //const char *modestr(int n) { return (n>=-2 && n<12) ? modenames[n+2] : "unknown"; }; const char *modestr(int n) { return (n>=0 && n<=9) ? modenames[n] : "unknown"; }; -/* Modified by Rick: New messages and different sizes for existing ones char msgsizesl[] = // size inclusive message token, 0 for variable or not-checked sizes { - SV_INITS2C, 4, SV_INITC2S, 0, SV_POS, 12, SV_TEXT, 0, SV_SOUND, 2, SV_CDIS, 2, - SV_DIED, 2, SV_DAMAGE, 4, SV_SHOsT, 8, SV_FRAGS, 2, - SV_TIMEUP, 2, SV_EDITENT, 10, SV_MAPRELOAD, 2, SV_ITEMACC, 2, - SV_MAPCHANGE, 0, SV_ITEMSPAWN, 2, SV_ITEMPICKUP, 3, SV_DENIED, 2, - SV_PING, 2, SV_PONG, 2, SV_CLIENTPING, 2, SV_GAMEMODE, 2, - SV_EDITH, 7, SV_EDITT, 7, SV_EDITS, 6, SV_EDITD, 6, SV_EDITE, 6, - SV_SENDMAP, 0, SV_RECVMAP, 1, SV_SERVMSG, 0, SV_ITEMLIST, 0, - SV_EXT, 0, - -1 -}; -*/ - -char msgsizesl[] = // size inclusive message token, 0 for variable or not-checked sizes -{ - SV_INITS2C, 4, SV_INITC2S, 0, SV_POS, 12, SV_TEXT, 0, SV_SOUND, 2, SV_CDIS, 2, - SV_GIBDIED, 2, SV_DIED, 2, SV_GIBDAMAGE, 4, SV_DAMAGE, 4, SV_SHOT, 9, SV_FRAGS, 2, + SV_INITS2C, 4, SV_INITC2S, 0, SV_POS, 0, SV_TEXT, 0, SV_SOUND, 2, SV_CDIS, 2, + SV_GIBDIED, 2, SV_DIED, 2, SV_GIBDAMAGE, 4, SV_DAMAGE, 4, SV_SHOT, 9, SV_FRAGS, 2, SV_RESUME, 3, SV_TIMEUP, 2, SV_EDITENT, 10, SV_MAPRELOAD, 2, SV_ITEMACC, 2, SV_MAPCHANGE, 0, SV_ITEMSPAWN, 2, SV_ITEMPICKUP, 3, SV_DENIED, 2, SV_PING, 2, SV_PONG, 2, SV_CLIENTPING, 2, SV_GAMEMODE, 2, @@ -158,7 +143,7 @@ ENetPacket *recvmap(int n) #ifdef STANDALONE -void localservertoclient(uchar *buf, int len) {}; +void localservertoclient(int chan, uchar *buf, int len) {}; void fatal(char *s, char *o) { cleanupserver(); printf("servererror: %s\n", s); exit(1); }; int main(int argc, char* argv[]) // EDIT: AH diff --git a/source/src/sound.cpp b/source/src/sound.cpp index b3451143..059b9e47 100644 --- a/source/src/sound.cpp +++ b/source/src/sound.cpp @@ -202,12 +202,12 @@ void updatevol() }; }; -void playsoundc(int n) { addmsg(0, 2, SV_SOUND, n); playsound(n); }; +void playsoundc(int n) { addmsg(SV_SOUND, "i", n); playsound(n); }; // Added by Rick: For bots void botplaysound(int n, dynent *b) { - addmsg(0, 3, SV_BOTSOUND, n, BotManager.GetBotIndex(b)); playsound(n, &b->o); + addmsg(SV_BOTSOUND, "rii", n, BotManager.GetBotIndex(b)); playsound(n, &b->o); } // End add by Rick diff --git a/source/src/tools.h b/source/src/tools.h index 37eca6c3..98b46ed6 100644 --- a/source/src/tools.h +++ b/source/src/tools.h @@ -157,13 +157,6 @@ template struct vector return buf[ulen++]; }; - T &dup() - { - if(ulen==alen) vrealloc(); - new (&buf[ulen]) T(buf[ulen-1]); - return buf[ulen++]; - }; - bool inrange(size_t i) const { return i=0 && i struct vector buf = (T *)_realloc(buf, olen*sizeof(T), (alen *= 2)*sizeof(T)); }; - void reserve(size_t i) - { - while(size_t(alen-ulen) < i) vrealloc(); - }; - void remove(int i, int n) { for(int p = i+n; p struct vector buf[i] = e; return buf[i]; }; - - void reverse() - { - loopi(ulen/2) swap(T, buf[i], buf[ulen-1-i]); - }; }; typedef vector cvector; diff --git a/source/src/weapon.cpp b/source/src/weapon.cpp index f9365a3c..53a375b3 100644 --- a/source/src/weapon.cpp +++ b/source/src/weapon.cpp @@ -275,11 +275,11 @@ void hit(int target, int damage, dynent *d, dynent *at, bool gib=false) } int msgtype = (at->bIsBot) ? SV_BOT2BOTDMG : SV_CLIENT2BOTDMG; - addmsg(1, 4, msgtype, BotManager.GetBotIndex(d), damage, PlayerIndex); + addmsg(msgtype, "ri3", BotManager.GetBotIndex(d), damage, PlayerIndex); playsound(S_PAIN1+rnd(5), &d->o); } // End add by Rick - //else { addmsg(1, 4, SV_DAMAGE, target, damage, d->lifesequence); playsound(S_PAIN1+rnd(5), &d->o); }; Modified by Rick: Added IsBot and PlayerIndex to message + //else { addmsg(SV_DAMAGE, "ri3", target, damage, d->lifesequence); playsound(S_PAIN1+rnd(5), &d->o); }; Modified by Rick: Added IsBot and PlayerIndex to message else { // Modified by Rick: Added IsBot and PlayerIndex to message @@ -300,8 +300,8 @@ void hit(int target, int damage, dynent *d, dynent *at, bool gib=false) } } } - if(at->bIsBot) addmsg(1, 5, SV_BOT2CLIENTDMG, target, damage, d->lifesequence, PlayerIndex); - else addmsg(1, 4, gib ? SV_GIBDAMAGE : SV_DAMAGE, target, damage, d->lifesequence); + if(at->bIsBot) addmsg(SV_BOT2CLIENTDMG, "ri4", target, damage, d->lifesequence, PlayerIndex); + else addmsg(gib ? SV_GIBDAMAGE : SV_DAMAGE, "ri3", target, damage, d->lifesequence); playsound(S_PAIN1+rnd(5), &d->o); }; @@ -468,7 +468,7 @@ void throw_nade(dynent *d, vec &to, physent *p) if(d==player1) { player1->lastaction = lastmillis; - addmsg(1, 9, SV_SHOT, d->gunselect, (int)(from.x*DMF), (int)(from.y*DMF), (int)(from.z*DMF), (int)(to.x*DMF), (int)(to.y*DMF), (int)(to.z*DMF), lastmillis-p->millis); + addmsg(SV_SHOT, "ri8", d->gunselect, (int)(from.x*DMF), (int)(from.y*DMF), (int)(from.z*DMF), (int)(to.x*DMF), (int)(to.y*DMF), (int)(to.z*DMF), lastmillis-p->millis); }; }; @@ -704,7 +704,7 @@ void shoot(dynent *d, vec &targ) else d->gunwait = guns[d->gunselect].attackdelay; shootv(d->gunselect, from, to, d, 0); - addmsg(1, 9, SV_SHOT, d->gunselect, (int)(from.x*DMF), (int)(from.y*DMF), (int)(from.z*DMF), (int)(to.x*DMF), (int)(to.y*DMF), (int)(to.z*DMF), 0 ); + addmsg(SV_SHOT, "ri8", d->gunselect, (int)(from.x*DMF), (int)(from.y*DMF), (int)(from.z*DMF), (int)(to.x*DMF), (int)(to.y*DMF), (int)(to.z*DMF), 0 ); if(guns[d->gunselect].projspeed || d->gunselect==GUN_GRENADE) return; loopv(players) diff --git a/source/src/world.cpp b/source/src/world.cpp index 00fee0b3..c4e8ee5e 100644 --- a/source/src/world.cpp +++ b/source/src/world.cpp @@ -206,7 +206,7 @@ void delent() int t = ents[e].type; conoutf("%s entity deleted", entnames[t]); ents[e].type = NOTUSED; - addmsg(1, 10, SV_EDITENT, e, NOTUSED, 0, 0, 0, 0, 0, 0, 0); + addmsg(SV_EDITENT, "ri9", e, NOTUSED, 0, 0, 0, 0, 0, 0, 0); if(t==LIGHT) calclight(); }; @@ -239,7 +239,7 @@ entity *newentity(int x, int y, int z, char *what, int v1, int v2, int v3, int v e.attr1 = (int)player1->yaw; break; }; - addmsg(1, 10, SV_EDITENT, ents.length(), type, e.x, e.y, e.z, e.attr1, e.attr2, e.attr3, e.attr4); + addmsg(SV_EDITENT, "ri9", ents.length(), type, e.x, e.y, e.z, e.attr1, e.attr2, e.attr3, e.attr4); ents.add(*((entity *)&e)); // unsafe! if(type==LIGHT) calclight(); return &ents.last();