diff --git a/source/src/client.cpp b/source/src/client.cpp index ac7ae87b..9fcedd82 100644 --- a/source/src/client.cpp +++ b/source/src/client.cpp @@ -73,7 +73,7 @@ void connects(char *servername, char *serverport, char *password) ENetAddress address; int p = 0; - if(serverport) p = atoi(serverport); + if(serverport && serverport[0]) p = atoi(serverport); address.port = p > 0 ? p : CUBE_DEFAULT_SERVER_PORT; if(servername) diff --git a/source/src/clients2c.cpp b/source/src/clients2c.cpp index 1e7de1bf..2f87de49 100644 --- a/source/src/clients2c.cpp +++ b/source/src/clients2c.cpp @@ -665,6 +665,28 @@ void parsemessages(int cn, playerent *d, ucharbuf &p) break; } + case SV_HEALTHINFO: + { + int cn = getint(p); + playerent *pl = cn == getclientnum() ? player1 : getclient(cn); + if(!pl) return; + pl->health = getuint(p); + pl->armour = getuint(p); + break; + } + + case SV_AMMOINFO: + { + int cn = getint(p); + playerent *pl = cn == getclientnum() ? player1 : getclient(cn); + if(!pl) return; + int weapon = pl->gunselect; + if(weapon<0 || weapon>=NUMGUNS) return; + pl->mag[weapon] = getuint(p); + pl->ammo[weapon] = getuint(p); + break; + } + default: neterr("type"); return; diff --git a/source/src/physics.cpp b/source/src/physics.cpp index 60d7c3b8..90f5642b 100644 --- a/source/src/physics.cpp +++ b/source/src/physics.cpp @@ -476,7 +476,7 @@ void moveplayer(physent *pl, int moveres, bool local, int curtime) // End add } -VARP(minframetime, 5, 10, 20); +const int minframetime = 5; int physicsfraction = 0, physicsrepeat = 0; diff --git a/source/src/protocol.cpp b/source/src/protocol.cpp index 2192da77..c954df5b 100644 --- a/source/src/protocol.cpp +++ b/source/src/protocol.cpp @@ -131,6 +131,7 @@ char msgsizesl[] = // size inclusive message token, 0 for variable SV_CALLVOTE, 0, SV_CALLVOTESUC, 1, SV_CALLVOTEERR, 2, SV_VOTE, 2, SV_VOTERESULT, 2, SV_FORCETEAM, 2, SV_AUTOTEAM, 2, SV_CHANGETEAM, 1, SV_WHOIS, 2, SV_WHOISINFO, 3, + SV_HEALTHINFO, 4, SV_AMMOINFO, 4, SV_LISTDEMOS, 1, SV_SENDDEMOLIST, 0, SV_GETDEMO, 2, SV_SENDDEMO, 0, SV_DEMOPLAYBACK, 2, SV_CONNECT, 0, SV_CLIENT, 0, diff --git a/source/src/protocol.h b/source/src/protocol.h index 055f9764..29f37b7d 100644 --- a/source/src/protocol.h +++ b/source/src/protocol.h @@ -28,6 +28,7 @@ enum SV_CALLVOTE, SV_CALLVOTESUC, SV_CALLVOTEERR, SV_VOTE, SV_VOTERESULT, SV_FORCETEAM, SV_AUTOTEAM, SV_CHANGETEAM, SV_WHOIS, SV_WHOISINFO, + SV_HEALTHINFO, SV_AMMOINFO, SV_LISTDEMOS, SV_SENDDEMOLIST, SV_GETDEMO, SV_SENDDEMO, SV_DEMOPLAYBACK, SV_CONNECT, SV_CLIENT diff --git a/source/src/server.cpp b/source/src/server.cpp index 1eb704ff..aeb4ab8b 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -13,7 +13,8 @@ #include "cube.h" #include "servercontroller.h" -extern void resetmap(const char *newname, int newmode, int newtime = -1, bool notify = true); +void resetmap(const char *newname, int newmode, int newtime = -1, bool notify = true); +void recordclientinfo(int cn); servercontroller *svcctrl = NULL; struct log *logger = NULL; @@ -204,6 +205,7 @@ struct client // server side version of "dynent" type bool isauthed; // for passworded servers bool timesync; int gameoffset, lastevent, lastvotecall; + int demoflags; clientstate state; vector events; vector position, messages; @@ -226,7 +228,7 @@ struct client // server side version of "dynent" type void reset() { - name[0] = team[0] = 0; + name[0] = team[0] = demoflags = 0; position.setsizenodelete(0); messages.setsizenodelete(0); isauthed = false; @@ -334,6 +336,7 @@ bool buildworldstate() int psize = ws.positions.length(), msize = ws.messages.length(); if(psize) recordpacket(0, ws.positions.getbuf(), psize); if(msize) recordpacket(1, ws.messages.getbuf(), msize); + loopv(clients) recordclientinfo(i); 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; @@ -564,6 +567,41 @@ void recordpacket(int chan, void *data, int len) if(recordpackets) writedemo(chan, data, len); } +enum +{ + DF_NONE = 0, + DF_HEALTHCHANGED = 1<<0, + DF_AMMOCHANGED = 1<<1 +}; + +void recordclientinfo(int cn) +{ + if(!demorecord || !valid_client(cn)) return; + client *c = clients[cn]; + if(c->demoflags==DF_NONE) return; + + uchar buf[MAXTRANS]; + ucharbuf p(buf, sizeof(buf)); + if(c->demoflags&DF_HEALTHCHANGED) + { + putint(p, SV_HEALTHINFO); + putuint(p, c->clientnum); + putuint(p, c->state.health); + putuint(p, c->state.armour); + } + if(c->demoflags&DF_AMMOCHANGED) + { + int weapon = c->state.gunselect; + putint(p, SV_AMMOINFO); + putuint(p, c->clientnum); + putuint(p, c->state.mag[weapon]); + putuint(p, c->state.ammo[weapon]); + } + writedemo(1, buf, p.len); + + c->demoflags = DF_NONE; +} + void enddemorecord() { if(!demorecord) return; @@ -1021,6 +1059,7 @@ bool serverpickup(int i, int sender) // server side item pickup, acknowl } sendf(-1, 1, "ri3", SV_ITEMACC, i, sender); cl->state.pickup(sents[i].type); + cl->demoflags |= (sents[i].type==I_HEALTH || sents[i].type==I_ARMOUR) ? DF_HEALTHCHANGED : DF_AMMOCHANGED; } e.spawned = false; e.spawntime = spawntime(e.type); @@ -1075,6 +1114,7 @@ void serverdamage(client *target, client *actor, int damage, int gun, bool gib, if(actor->state.frags < scorethreshold) disconnect_client(actor->clientnum, DISC_AUTOKICK); } + target->demoflags |= DF_HEALTHCHANGED; } #include "serverevents.h" @@ -1525,6 +1565,8 @@ void process(ENetPacket *packet, int sender, int chan) // sender may be -1 if(cl && !cl->isauthed) { + int clientrole = CR_DEFAULT; + if(chan==0) return; else if(chan!=1 || getint(p)!=SV_CONNECT) disconnect_client(sender, DISC_TAGT); else @@ -1535,7 +1577,7 @@ void process(ENetPacket *packet, int sender, int chan) // sender may be -1 if(adminpasswd && adminpasswd[0] && !strcmp(text, adminpasswd)) // pass admins always through { cl->isauthed = true; - changeclientrole(sender, CR_ADMIN, NULL, true); + clientrole = CR_ADMIN; loopv(bans) if(bans[i].address.host == cl->peer->address.host) { bans.remove(i); break; } // remove admin bans if(nonlocalclients>maxclients) loopi(nonlocalclients) if(i != sender && clients[i]->type==ST_TCPIP) { @@ -1566,6 +1608,7 @@ void process(ENetPacket *packet, int sender, int chan) // sender may be -1 enet_packet_resize(packet, p.length()); sendpacket(sender, 1, packet); if(smapname[0] && m_ctf) loopi(2) sendflaginfo(i, -1, sender); + if(clientrole != CR_DEFAULT) changeclientrole(sender, clientrole, NULL, true); } if(packet->flags&ENET_PACKET_FLAG_RELIABLE) reliablemessages = true; @@ -1655,6 +1698,7 @@ void process(ENetPacket *packet, int sender, int chan) // sender may be -1 case SV_WEAPCHANGE: { int gunselect = getint(p); + if(gunselect<0 && gunselect>=NUMGUNS) break; cl->state.gunselect = gunselect; QUEUE_MSG; break; @@ -1682,7 +1726,7 @@ void process(ENetPacket *packet, int sender, int chan) // sender may be -1 case SV_SPAWN: { int ls = getint(p), gunselect = getint(p); - if((cl->state.state!=CS_ALIVE && cl->state.state!=CS_DEAD) || ls!=cl->state.lifesequence || cl->state.lastspawn<0) break; + if((cl->state.state!=CS_ALIVE && cl->state.state!=CS_DEAD) || ls!=cl->state.lifesequence || cl->state.lastspawn<0 || gunselect<0 || gunselect>=NUMGUNS) break; cl->state.lastspawn = -1; cl->state.state = CS_ALIVE; cl->state.gunselect = gunselect; diff --git a/source/src/serverevents.h b/source/src/serverevents.h index b2452e8b..6f0697d9 100644 --- a/source/src/serverevents.h +++ b/source/src/serverevents.h @@ -41,6 +41,7 @@ void processevent(client *c, shotevent &e) loopi(NUMGUNS) if(gs.gunwait[i]) gs.gunwait[i] = max(gs.gunwait[i] - (e.millis-gs.lastshot), 0); gs.lastshot = e.millis; gs.gunwait[e.gun] = attackdelay(e.gun); + c->demoflags |= DF_AMMOCHANGED; if(e.gun==GUN_PISTOL && gs.akimbomillis>gamemillis) gs.gunwait[e.gun] /= 2; sendf(-1, 1, "ri9x", SV_SHOTFX, c->clientnum, e.gun, int(e.from[0]*DMF), int(e.from[1]*DMF), int(e.from[2]*DMF), @@ -87,6 +88,7 @@ void processevent(client *c, suicideevent &e) gs.state = CS_DEAD; gs.respawn(); logger->writeline(log::info, "[%s] %s suicided", c->hostname, c->name); + c->demoflags |= DF_HEALTHCHANGED; } void processevent(client *c, pickupevent &e) @@ -120,6 +122,7 @@ void processevent(client *c, reloadevent &e) gs.lastshot = e.millis; gs.gunwait[e.gun] += reloadtime(e.gun); } + c->demoflags |= DF_AMMOCHANGED; } void processevent(client *c, akimboevent &e) @@ -128,6 +131,7 @@ void processevent(client *c, akimboevent &e) if(!gs.isalive(gamemillis) || gs.akimbos<=0) return; gs.akimbos--; gs.akimbomillis = e.millis+30000; + c->demoflags |= DF_AMMOCHANGED; } void clearevent(client *c)