12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589 |
- // client processing of the incoming network stream
- #include "cube.h"
- #include "bot/bot.h"
- VARP(networkdebug, 0, 0, 1);
- #define DEBUGCOND (networkdebug==1)
- extern bool watchingdemo;
- extern string clientpassword;
- void *downloaddemomenu = NULL;
- static vector<mline> demo_mlines;
- packetqueue pktlogger;
- void neterr(const char *s)
- {
- conoutf("\f3illegal network message (%s)", s);
- // might indicate a client/server communication bug, create error report
- pktlogger.flushtolog("packetlog.txt");
- conoutf("\f3wrote a network error report to packetlog.txt, please post this file to the bugtracker now!");
- disconnect();
- }
- VARP(autogetmap, 0, 1, 1); // only if the client doesn't have that map
- VARP(autogetnewmaprevisions, 0, 1, 1);
- bool localwrongmap = false;
- int MA = 0, Hhits = 0; // flowtron: moved here
- bool changemapserv(char *name, int mode, int download, int revision) // forced map change from the server
- {
- MA = Hhits = 0; // reset for checkarea()
- gamemode = mode;
- if(m_demo) return true;
- if(m_coop)
- {
- if(!name[0] || load_world(name) < 0) empty_world(0, true);
- return true;
- }
- else if(player1->state==CS_EDITING) { /*conoutf("SANITY drop from EDITING");*/ toggleedit(true); } // fix stuck-in-editmode bug
- bool loaded = load_world(name) >= 0;
- if(download > 0)
- {
- bool revmatch = hdr.maprevision == revision || revision == 0;
- if(watchingdemo)
- {
- if(loaded && !revmatch) conoutf("\f3demo was recorded on map revision %d, you have map revision %d", revision, hdr.maprevision);
- }
- else
- {
- if(securemapcheck(name, false)) return true;
- bool sizematch = maploaded == download || download < 10;
- if(loaded && sizematch && revmatch) return true;
- bool getnewrev = autogetnewmaprevisions && revision > hdr.maprevision;
- if(autogetmap || getnewrev)
- {
- if(!loaded || getnewrev) getmap(); // no need to ask
- else
- {
- defformatstring(msg)("map '%s' revision: local %d, provided by server %d", name, hdr.maprevision, revision);
- alias("__getmaprevisions", msg, true);
- showmenu("getmap");
- }
- }
- else
- {
- if(!loaded || download < 10) conoutf("\"getmap\" to download the current map from the server");
- else conoutf("\"getmap\" to download a %s version of the current map from the server",
- revision == 0 ? "different" : (revision > hdr.maprevision ? "newer" : "older"));
- }
- }
- }
- else return true;
- return false;
- }
- // update the position of other clients in the game in our world
- // don't care if he's in the scenery or other players,
- // just don't overlap with our client
- void updateplayerpos(playerent *d)
- {
- const float r = player1->radius+d->radius;
- const float dx = player1->o.x-d->o.x;
- const float dy = player1->o.y-d->o.y;
- const float dz = player1->o.z-d->o.z;
- const float rz = player1->aboveeye+d->eyeheight;
- const float fx = (float)fabs(dx), fy = (float)fabs(dy), fz = (float)fabs(dz);
- if(fx<r && fy<r && fz<rz && d->state!=CS_DEAD)
- {
- if(fx<fy) d->o.y += dy<0 ? r-fy : -(r-fy); // push aside
- else d->o.x += dx<0 ? r-fx : -(r-fx);
- }
- }
- void updatelagtime(playerent *d)
- {
- int lagtime = totalmillis-d->lastupdate;
- if(lagtime)
- {
- if(d->state!=CS_SPAWNING && d->lastupdate) d->plag = (d->plag*5+lagtime)/6;
- d->lastupdate = totalmillis;
- }
- }
- extern void trydisconnect();
- void parsepositions(ucharbuf &p)
- {
- int type;
- while(p.remaining()) switch(type = getint(p))
- {
- case SV_POS: // position of another client
- case SV_POSC:
- {
- int cn, f, g;
- vec o, vel;
- float yaw, pitch = 0;
- bool scoping;//, shoot;
- if(type == SV_POSC)
- {
- bitbuf<ucharbuf> q(p);
- cn = q.getbits(5);
- int usefactor = q.getbits(2) + 7;
- o.x = q.getbits(usefactor + 4) / DMF;
- o.y = q.getbits(usefactor + 4) / DMF;
- yaw = q.getbits(9) * 360.0f / 512;
- pitch = (q.getbits(8) - 128) * 90.0f / 127;
- if(!q.getbits(1)) q.getbits(6);
- if(!q.getbits(1))
- {
- vel.x = (q.getbits(4) - 8) / DVELF;
- vel.y = (q.getbits(4) - 8) / DVELF;
- vel.z = (q.getbits(4) - 8) / DVELF;
- }
- else vel.x = vel.y = vel.z = 0.0f;
- f = q.getbits(8);
- int negz = q.getbits(1);
- int full = q.getbits(1);
- int s = q.rembits();
- if(s < 3) s += 8;
- if(full) s = 11;
- int z = q.getbits(s);
- if(negz) z = -z;
- o.z = z / DMF;
- scoping = ( q.getbits(1) ? true : false );
- q.getbits(1);//shoot = ( q.getbits(1) ? true : false );
- }
- else
- {
- cn = getint(p);
- o.x = getuint(p)/DMF;
- o.y = getuint(p)/DMF;
- o.z = getuint(p)/DMF;
- yaw = (float)getuint(p);
- pitch = (float)getint(p);
- g = getuint(p);
- if ((g>>3) & 1) getint(p);
- if (g & 1) vel.x = getint(p)/DVELF; else vel.x = 0;
- if ((g>>1) & 1) vel.y = getint(p)/DVELF; else vel.y = 0;
- if ((g>>2) & 1) vel.z = getint(p)/DVELF; else vel.z = 0;
- scoping = ( (g>>4) & 1 ? true : false );
- //shoot = ( (g>>5) & 1 ? true : false ); // we are not using this yet
- f = getuint(p);
- }
- int seqcolor = (f>>6)&1;
- playerent *d = getclient(cn);
- if(!d || seqcolor!=(d->lifesequence&1)) continue;
- vec oldpos(d->o);
- float oldyaw = d->yaw, oldpitch = d->pitch;
- loopi(3)
- {
- float dr = o.v[i] - d->o.v[i] + ( i == 2 ? d->eyeheight : 0);
- if ( !dr ) d->vel.v[i] = 0.0f;
- else if ( d->vel.v[i] ) d->vel.v[i] = dr * 0.05f + d->vel.v[i] * 0.95f;
- d->vel.v[i] += vel.v[i];
- if ( i==2 && d->onfloor && d->vel.v[i] < 0.0f ) d->vel.v[i] = 0.0f;
- }
- d->o = o;
- d->o.z += d->eyeheight;
- d->yaw = yaw;
- d->pitch = pitch;
- if(d->weaponsel->type == GUN_SNIPER)
- {
- sniperrifle *sr = (sniperrifle *)d->weaponsel;
- sr->scoped = d->scoping = scoping;
- }
- d->strafe = (f&3)==3 ? -1 : f&3;
- f >>= 2;
- d->move = (f&3)==3 ? -1 : f&3;
- f >>= 2;
- d->onfloor = f&1;
- f >>= 1;
- d->onladder = f&1;
- f >>= 2;
- d->last_pos = totalmillis;
- updatecrouch(d, f&1);
- updateplayerpos(d);
- updatelagtime(d);
- extern int smoothmove, smoothdist;
- if(d->state==CS_DEAD)
- {
- d->resetinterp();
- d->smoothmillis = 0;
- }
- else if(smoothmove && d->smoothmillis>=0 && oldpos.dist(d->o) < smoothdist)
- {
- d->newpos = d->o;
- d->newpos.z -= d->eyeheight;
- d->newyaw = d->yaw;
- d->newpitch = d->pitch;
- d->o = oldpos;
- d->yaw = oldyaw;
- d->pitch = oldpitch;
- oldpos.z -= d->eyeheight;
- (d->deltapos = oldpos).sub(d->newpos);
- d->deltayaw = oldyaw - d->newyaw;
- if(d->deltayaw > 180) d->deltayaw -= 360;
- else if(d->deltayaw < -180) d->deltayaw += 360;
- d->deltapitch = oldpitch - d->newpitch;
- d->smoothmillis = lastmillis;
- }
- else d->smoothmillis = 0;
- if(d->state==CS_LAGGED || d->state==CS_SPAWNING) d->state = CS_ALIVE;
- // when playing a demo spectate first player we know about
- if(player1->isspectating() && player1->spectatemode==SM_NONE) togglespect();
- break;
- }
- default:
- neterr("type");
- return;
- }
- }
- extern int checkarea(int maplayout_factor, char *maplayout);
- char *mlayout = NULL;
- int Mv = 0, Ma = 0, F2F = 1000 * MINFF; // moved up:, MA = 0;
- float Mh = 0;
- extern int connected;
- extern bool noflags;
- bool item_fail = false;
- int map_quality = MAP_IS_EDITABLE;
- /// TODO: many functions and variables are redundant between client and server... someone should redo the entire server code and unify client and server.
- bool good_map() // call this function only at startmap
- {
- return true;
- if (mlayout) MA = checkarea(sfactor, mlayout);
- F2F = 1000 * MINFF;
- if(m_flags)
- {
- // flaginfo &f0 = flaginfos[0];
- // flaginfo &f1 = flaginfos[1];
- #define DIST(x) (f0.pos.x - f1.pos.x)
- F2F = 1000;//(!numflagspawn[0] || !numflagspawn[1]) ? 1000 * MINFF : DIST(x)*DIST(x)+DIST(y)*DIST(y);
- #undef DIST
- }
- item_fail = false;
- loopv(ents)
- {
- entity &e1 = ents[i];
- if (e1.type < I_CLIPS || e1.type > I_AKIMBO) continue;
- float density = 0, hdensity = 0;
- loopvj(ents)
- {
- entity &e2 = ents[j];
- if (e2.type < I_CLIPS || e2.type > I_AKIMBO || i == j) continue;
- // only I_CLIPS, I_AMMO, I_GRENADE, I_HEALTH, I_HELMET, I_ARMOUR, I_AKIMBO
- #define DIST(x) (e1.x - e2.x)
- #define DIST_ATT ((e1.z + float(e1.attr1) / entscale[e1.type][0]) - (e2.z + float(e2.attr1) / entscale[e2.type][0]))
- float r2 = DIST(x)*DIST(x) + DIST(y)*DIST(y) + DIST_ATT*DIST_ATT;
- #undef DIST_ATT
- #undef DIST
- if ( r2 == 0.0f ) { conoutf("\f3MAP CHECK FAIL: Items too close %s %s (%hd,%hd)", entnames[e1.type], entnames[e2.type],e1.x,e1.y); item_fail = true; break; }
- r2 = 1/r2;
- if (r2 < 0.0025f) continue;
- if (e1.type != e2.type)
- {
- hdensity += r2;
- continue;
- }
- density += r2;
- }
- if ( hdensity > 0.5f ) { conoutf("\f3MAP CHECK FAIL: Items too close %s %.2f (%hd,%hd)", entnames[e1.type],hdensity,e1.x,e1.y); item_fail = true; break; }
- switch(e1.type)
- {
- #define LOGTHISSWITCH(X) if( density > X ) { conoutf("\f3MAP CHECK FAIL: Items too close %s %.2f (%hd,%hd)", entnames[e1.type],density,e1.x,e1.y); item_fail = true; break; }
- case I_CLIPS:
- case I_HEALTH: LOGTHISSWITCH(0.24f); break;
- case I_AMMO: LOGTHISSWITCH(0.04f); break;
- case I_HELMET: LOGTHISSWITCH(0.02f); break;
- case I_ARMOUR:
- case I_GRENADE:
- case I_AKIMBO: LOGTHISSWITCH(0.005f); break;
- default: break;
- #undef LOGTHISSWITCH
- }
- }
- map_quality = (!item_fail && F2F > MINFF && MA < MAXMAREA && Mh < MAXMHEIGHT && Hhits < MAXHHITS) ? MAP_IS_GOOD : MAP_IS_BAD;
- if ( (!connected || gamemode == GMODE_COOPEDIT) && map_quality == MAP_IS_BAD ) map_quality = MAP_IS_EDITABLE;
- return map_quality > 0;
- }
- VARP(hudextras, 0, 0, 3);
- int teamworkid = -1;
- char *strcaps(const char *s, bool on)
- {
- static string r;
- char *o = r;
- if(on) while(*s && o < &r[sizeof(r)-1]) *o++ = toupper(*s++);
- else while(*s && o < &r[sizeof(r)-1]) *o++ = tolower(*s++);
- *o = '\0';
- return r;
- }
- void showhudextras(char hudextras, char value){
- void (*outf)(const char *s, ...) = (hudextras > 1 ? hudoutf : conoutf);
- bool caps = hudextras < 3 ? false : true;
- switch(value)
- {
- case HE_COMBO:
- case HE_COMBO2:
- case HE_COMBO3:
- case HE_COMBO4:
- case HE_COMBO5:
- {
- int n = value - HE_COMBO;
- if (n > 3) outf("\f3%s",strcaps("monster combo!!!",caps)); // I expect to never see this one
- else if (!n) outf("\f5%s",strcaps("combo", caps));
- else outf("\f5%s x%d",strcaps("multi combo", caps),n+1);
- break;
- }
- case HE_TEAMWORK:
- outf("\f5%s",strcaps("teamwork done", caps)); break;
- case HE_FLAGDEFENDED:
- outf("\f5%s",strcaps("you defended the flag", caps)); break;
- case HE_FLAGCOVERED:
- outf("\f5%s",strcaps("you covered the flag", caps)); break;
- case HE_COVER:
- if (teamworkid >= 0)
- {
- playerent *p = getclient(teamworkid);
- if (!p || p == player1) teamworkid = -1;
- else outf("\f5you covered %s",p->name); break;
- }
- default:
- {
- if (value >= HE_NUM)
- {
- teamworkid = value - HE_NUM;
- playerent *p = getclient(teamworkid);
- if (!p || p == player1) teamworkid = -1;
- else outf("\f4you replied to %s",p->name);
- }
- else outf("\f3Update your client!");
- break;
- }
- }
- #undef SSPAM
- }
- int lastspawn = 0;
- void onCallVote(int type, int vcn, char *text, char *a)
- {
- exechook(HOOK_SP_MP, "onCallVote", "%d %d [%s] [%s]", type, vcn, text, a);
- }
- void onChangeVote(int mod, int id)
- {
- exechook(HOOK_SP_MP, "onChangeVote", "%d %d", mod, id);
- }
- VARP(voicecomsounds, 0, 1, 2);
- bool medals_arrived=0;
- medalsst a_medals[END_MDS];
- void parsemessages(int cn, playerent *d, ucharbuf &p, bool demo = false)
- {
- static char text[MAXTRANS];
- int type, joining = 0;
- while(p.remaining())
- {
- type = getint(p);
- if(demo && watchingdemo && demoprotocol == 1132)
- {
- if(type > SV_IPLIST) --type; // SV_WHOIS removed
- if(type >= SV_TEXTPRIVATE) ++type; // SV_TEXTPRIVATE added
- if(type == SV_SWITCHNAME) // SV_SPECTCN removed
- {
- getint(p);
- continue;
- }
- else if(type > SV_SWITCHNAME) --type;
- }
- #ifdef _DEBUG
- if(type!=SV_POS && type!=SV_CLIENTPING && type!=SV_PING && type!=SV_PONG && type!=SV_CLIENT)
- {
- DEBUGVAR(d);
- ASSERT(type>=0 && type<SV_NUM);
- DEBUGVAR(messagenames[type]);
- protocoldebug(DEBUGCOND);
- }
- else protocoldebug(false);
- #endif
- switch(type)
- {
- case SV_SERVINFO: // welcome message from the server
- {
- int mycn = getint(p), prot = getint(p);
- sessionid = getint(p);
- if(prot!=CUR_PROTOCOL_VERSION && !(watchingdemo && prot == -PROTOCOL_VERSION))
- {
- conoutf("\f3incompatible game protocol (local protocol: %d :: server protocol: %d)", CUR_PROTOCOL_VERSION, prot);
- conoutf("\f3if this occurs a lot, obtain an upgrade from \f1http://assault.cubers.net");
- if(watchingdemo) conoutf("breaking loop : \f3this demo is using a different protocol\f5 : end it now!"); // SVN-WiP-bug: causes endless retry loop else!
- else disconnect();
- return;
- }
- player1->clientnum = mycn;
- if(getint(p) > 0) conoutf("INFO: this server is password protected");
- sendintro();
- break;
- }
- case SV_WELCOME:
- joining = getint(p);
- player1->resetspec();
- resetcamera();
- break;
- case SV_CLIENT:
- {
- int cn = getint(p), len = getuint(p);
- ucharbuf q = p.subbuf(len);
- parsemessages(cn, getclient(cn), q, demo);
- break;
- }
- case SV_SOUND:
- audiomgr.playsound(getint(p), d);
- break;
- case SV_VOICECOMTEAM:
- {
- playerent *d = getclient(getint(p));
- if(d) d->lastvoicecom = lastmillis;
- int t = getint(p);
- if(!d || !(d->muted || d->ignored))
- {
- if ( voicecomsounds == 1 || (voicecomsounds == 2 && m_teammode) ) audiomgr.playsound(t, SP_HIGH);
- }
- break;
- }
- case SV_VOICECOM:
- {
- int t = getint(p);
- if(!d || !(d->muted || d->ignored))
- {
- if ( voicecomsounds == 1 ) audiomgr.playsound(t, SP_HIGH);
- }
- if(d) d->lastvoicecom = lastmillis;
- break;
- }
- case SV_TEAMTEXTME:
- case SV_TEAMTEXT:
- {
- int cn = getint(p);
- getstring(text, p);
- filtertext(text, text, FTXT__CHAT);
- playerent *d = getclient(cn);
- if(!d) break;
- if(d->ignored) clientlogf("ignored: %s%s %s", colorname(d), type == SV_TEAMTEXT ? ":" : "", text);
- else
- {
- void (*outf)(const char *s, ...) = touchenabled() ? hudoutf : conoutf;
- if(m_teammode || team_isspect(player1->team)) outf(type == SV_TEAMTEXTME ? "\f1%s %s" : "%s:\f1 %s", colorname(d), highlight(text));
- else outf(type == SV_TEAMTEXTME ? "\f0%s %s" : "%s:\f0 %s", colorname(d), highlight(text));
- if(touchenabled()) hudkeeplastline(2500);
- }
- break;
- }
- case SV_TEXTME:
- case SV_TEXT:
- if(cn == -1)
- {
- getstring(text, p);
- conoutf("MOTD:");
- conoutf("\f4%s", text);
- }
- else if(d)
- {
- getstring(text, p);
- filtertext(text, text, FTXT__CHAT);
- if(d->ignored && d->clientrole != CR_ADMIN) clientlogf("ignored: %s%s %s", colorname(d), type == SV_TEXT ? ":" : "", text);
- else{
- void (*outf)(const char *s, ...) = touchenabled() ? hudoutf : conoutf;
- outf(type == SV_TEXTME ? "\f0%s %s" : "%s:\f0 %s", colorname(d), highlight(text));
- if(touchenabled()) hudkeeplastline(2500);
- }
- }
- else return;
- break;
- case SV_TEXTPRIVATE:
- {
- int cn = getint(p);
- getstring(text, p);
- filtertext(text, text, FTXT__CHAT);
- playerent *d = getclient(cn);
- if(!d) break;
- if(d->ignored) clientlogf("ignored: pm %s %s", colorname(d), text);
- else
- {
- conoutf("%s (PM):\f9 %s", colorname(d), highlight(text));
- lastpm = d->clientnum;
- exechook(HOOK_SP_MP, "onPM", "%d [%s]", d->clientnum, text);
- }
- break;
- }
- case SV_MAPCHANGE:
- {
- extern int spawnpermission;
- spawnpermission = SP_SPECT;
- getstring(text, p);
- int mode = getint(p);
- int downloadable = getint(p);
- int revision = getint(p);
- localwrongmap = !changemapserv(text, mode, downloadable, revision);
- if(m_arena && joining > 1 && !watchingdemo) deathstate(player1);
- break;
- }
- case SV_ITEMLIST:
- {
- int n;
- resetpickups();
- while((n = getint(p))!=-1) setpickupspawn(n, true);
- break;
- }
- case SV_MAPIDENT:
- {
- loopi(2) getint(p);
- break;
- }
- case SV_SWITCHNAME:
- getstring(text, p);
- filtertext(text, text, FTXT__PLAYERNAME, MAXNAMELEN);
- if(!text[0]) copystring(text, "unarmed");
- if(d)
- {
- if(strcmp(d->name, text)) conoutf("%s is now known as %s", colorname(d), colorname(d, text));
- exechook(HOOK_SP, "onNameChange", "%d \"%s\"", d->clientnum, text);
- copystring(d->name, text, MAXNAMELEN+1);
- updateclientname(d);
- }
- break;
- case SV_SWITCHTEAM:
- getint(p);
- break;
- case SV_SWITCHSKIN:
- loopi(2)
- {
- int skin = getint(p);
- if(d) d->setskin(i, skin);
- }
- break;
- case SV_INITCLIENT: // another client either connected or changed name/team
- {
- int cn = getint(p);
- playerent *d = newclient(cn);
- if(!d)
- {
- getstring(text, p);
- loopi(2) getint(p);
- getint(p);
- if(!demo || !watchingdemo || demoprotocol > 1132) getint(p);
- break;
- }
- getstring(text, p);
- filtertext(text, text, FTXT__PLAYERNAME, MAXNAMELEN);
- if(!text[0]) copystring(text, "unarmed");
- if(d->name[0]) // already connected
- {
- if(strcmp(d->name, text))
- conoutf("%s is now known as %s", colorname(d), colorname(d, text));
- }
- else // new client
- {
- conoutf("connected: %s", colorname(d, text));
- }
- copystring(d->name, text, MAXNAMELEN+1);
- exechook(HOOK_SP_MP, "onConnect", "%d", d->clientnum);
- loopi(2) d->setskin(i, getint(p));
- d->team = getint(p);
- // d->maxroll = (float)clamp(getint(p), 0, ROLLMOVMAX); FIXME: uncomment on protocol bump + etc.
- // d->maxrolleffect = (float)clamp(getint(p), 0, ROLLEFFMAX); FIXME: uncomment on protocol bump
- if(!demo || !watchingdemo || demoprotocol > 1132) d->address = getint(p); // partial IP address
- if(m_flags) loopi(2)
- {
- flaginfo &f = flaginfos[i];
- if(!f.actor) f.actor = getclient(f.actor_cn);
- }
- updateclientname(d);
- break;
- }
- case SV_CDIS:
- {
- int cn = getint(p);
- playerent *d = getclient(cn);
- if(!d) break;
- if(d->name[0]) conoutf("player %s disconnected", colorname(d));
- zapplayer(players[cn]);
- exechook(HOOK_SP_MP, "onDisconnect", "%d", d->clientnum);
- break;
- }
- case SV_EDITMODE:
- {
- int val = getint(p);
- if(!d) break;
- if(val) d->state = CS_EDITING;
- else d->state = CS_ALIVE;
- break;
- }
- case SV_SPAWN:
- {
- playerent *s = d;
- if(!s) { static playerent dummy; s = &dummy; }
- s->respawn();
- s->lifesequence = getint(p);
- s->health = getint(p);
- s->armour = getint(p);
- int gunselect = getint(p);
- s->setprimary(gunselect);
- s->selectweapon(gunselect);
- loopi(NUMGUNS) s->ammo[i] = getint(p);
- loopi(NUMGUNS) s->mag[i] = getint(p);
- s->state = CS_SPAWNING;
- arenaintermission = 0;
- if(s->lifesequence==0) s->resetstats(); //NEW
- break;
- }
- case SV_SPAWNSTATE:
- {
- if ( map_quality == MAP_IS_BAD )
- {
- loopi(6+2*NUMGUNS) getint(p);
- conoutf("map deemed unplayable - fix it before you can spawn");
- break;
- }
- if(editmode) toggleedit(true);
- showscores(false);
- setscope(false);
- setburst(false);
- player1->respawn();
- player1->lifesequence = getint(p);
- player1->health = getint(p);
- player1->armour = getint(p);
- player1->setprimary(getint(p));
- player1->selectweapon(getint(p));
- int arenaspawn = getint(p);
- loopi(NUMGUNS) player1->ammo[i] = getint(p);
- loopi(NUMGUNS) player1->mag[i] = getint(p);
- player1->state = CS_ALIVE;
- lastspawn = lastmillis;
- findplayerstart(player1, false, arenaspawn);
- arenaintermission = 0;
- if(m_arena && !localwrongmap)
- {
- if(connected) closemenu(NULL);
- conoutf("new round starting... fight!");
- hudeditf(HUDMSG_TIMER, "FIGHT!");
- if(m_botmode) BotManager.RespawnBots();
- }
- addmsg(SV_SPAWN, "rii", player1->lifesequence, player1->weaponsel->type);
- player1->weaponswitch(player1->primweap);
- player1->weaponchanging -= weapon::weaponchangetime/2;
- if(player1->lifesequence==0) player1->resetstats(); //NEW
- break;
- }
- case SV_SHOTFX:
- {
- int scn = getint(p), gun = getint(p);
- vec from, to;
- loopk(3) to[k] = getint(p)/DMF;
- playerent *s = getclient(scn);
- if(!s || !valid_weapon(gun)) break;
- loopk(3) from[k] = s->o.v[k];
- if(gun==GUN_SHOTGUN) createrays(from, to);
- s->lastaction = lastmillis;
- s->weaponchanging = 0;
- s->mag[gun]--;
- if(s->weapons[gun])
- {
- s->lastattackweapon = s->weapons[gun];
- s->weapons[gun]->gunwait = s->weapons[gun]->info.attackdelay;
- s->weapons[gun]->attackfx(from, to, -1);
- s->weapons[gun]->reloading = 0;
- }
- s->pstatshots[gun]++; //NEW
- break;
- }
- case SV_THROWNADE:
- {
- vec from, to;
- loopk(3) from[k] = getint(p)/DMF;
- loopk(3) to[k] = getint(p)/DMF;
- int nademillis = getint(p);
- if(!d) break;
- d->lastaction = lastmillis;
- d->weaponchanging = 0;
- d->lastattackweapon = d->weapons[GUN_GRENADE];
- if(d->weapons[GUN_GRENADE])
- {
- d->weapons[GUN_GRENADE]->attackfx(from, to, nademillis);
- d->weapons[GUN_GRENADE]->reloading = 0;
- }
- if(d!=player1) d->pstatshots[GUN_GRENADE]++; //NEW
- break;
- }
- case SV_RELOAD:
- {
- int cn = getint(p), gun = getint(p);
- playerent *p = getclient(cn);
- if(p && p!=player1) p->weapons[gun]->reload(false);
- break;
- }
- // for AUTH: WIP
- case SV_AUTHREQ:
- {
- // extern int autoauth;
- getstring(text, p);
- // if(autoauth && text[0] && tryauth(text)) conoutf("server requested authkey \"%s\"", text);
- break;
- }
- case SV_AUTHCHAL:
- {
- getstring(text, p);
- // authkey *a = findauthkey(text);
- // uint id = (uint)getint(p);
- getstring(text, p);
- // if(a && a->lastauth && lastmillis - a->lastauth < 60*1000)
- {
- // vector<char> buf;
- // answerchallenge(a->key, text, buf);
- //conoutf("answering %u, challenge %s with %s", id, text, buf.getbuf());
- // addmsg(SV_AUTHANS, "rsis", a->desc, id, buf.getbuf());
- }
- break;
- }
- // :for AUTH
- case SV_GIBDAMAGE:
- case SV_DAMAGE:
- {
- int tcn = getint(p),
- acn = getint(p),
- gun = getint(p),
- damage = getint(p),
- armour = getint(p),
- health = getint(p);
- playerent *target = getclient(tcn), *actor = getclient(acn);
- if(!target || !actor) break;
- target->armour = armour;
- target->health = health;
- dodamage(damage, target, actor, -1, type==SV_GIBDAMAGE, false);
- actor->pstatdamage[gun]+=damage; //NEW
- break;
- }
- case SV_POINTS:
- {
- int count = getint(p);
- if ( count > 0 ) {
- loopi(count){
- int pcn = getint(p); int score = getint(p);
- playerent *ppl = getclient(pcn);
- if (!ppl) break;
- ppl->points += score;
- }
- } else {
- int medals = getint(p);
- if(medals > 0) {
- // medals_arrived=1;
- loopi(medals) {
- int mcn=getint(p); int mtype=getint(p); int mitem=getint(p);
- a_medals[mtype].assigned=1;
- a_medals[mtype].cn=mcn;
- a_medals[mtype].item=mitem;
- }
- }
- }
- break;
- }
- case SV_HUDEXTRAS:
- {
- char value = getint(p);
- if (hudextras) showhudextras(hudextras, value);
- break;
- }
- case SV_HITPUSH:
- {
- int gun = getint(p), damage = getint(p);
- vec dir;
- loopk(3) dir[k] = getint(p)/DNF;
- player1->hitpush(damage, dir, NULL, gun);
- break;
- }
- case SV_GIBDIED:
- case SV_DIED:
- {
- int vcn = getint(p), acn = getint(p), frags = getint(p), gun = getint(p);
- playerent *victim = getclient(vcn), *actor = getclient(acn);
- if(!actor) break;
- if ( m_mp(gamemode) ) actor->frags = frags;
- if(!victim) break;
- dokill(victim, actor, type==SV_GIBDIED, gun);
- break;
- }
- case SV_RESUME:
- {
- loopi(MAXCLIENTS)
- {
- int cn = getint(p);
- if(p.overread() || cn<0) break;
- int state = getint(p), lifesequence = getint(p), primary = getint(p), gunselect = getint(p), flagscore = getint(p), frags = getint(p), deaths = getint(p), health = getint(p), armour = getint(p), points = getint(p);
- int teamkills = 0;
- if(!demo || !watchingdemo || demoprotocol > 1132) teamkills = getint(p);
- int ammo[NUMGUNS], mag[NUMGUNS];
- loopi(NUMGUNS) ammo[i] = getint(p);
- loopi(NUMGUNS) mag[i] = getint(p);
- playerent *d = (cn == getclientnum() ? player1 : newclient(cn));
- if(!d) continue;
- if(d!=player1) d->state = state;
- d->lifesequence = lifesequence;
- d->flagscore = flagscore;
- d->frags = frags;
- d->deaths = deaths;
- d->points = points;
- d->tks = teamkills;
- if(d!=player1)
- {
- d->setprimary(primary);
- d->selectweapon(gunselect);
- d->health = health;
- d->armour = armour;
- memcpy(d->ammo, ammo, sizeof(ammo));
- memcpy(d->mag, mag, sizeof(mag));
- if(d->lifesequence==0) d->resetstats(); //NEW
- }
- }
- break;
- }
- case SV_DISCSCORES:
- {
- discscores.shrink(0);
- int team;
- while((team = getint(p)) >= 0)
- {
- discscore &ds = discscores.add();
- ds.team = team;
- getstring(text, p);
- filtertext(ds.name, text, FTXT__PLAYERNAME, MAXNAMELEN);
- ds.flags = getint(p);
- ds.frags = getint(p);
- ds.deaths = getint(p);
- ds.points = getint(p);
- }
- break;
- }
- case SV_ITEMSPAWN:
- {
- int i = getint(p);
- setpickupspawn(i, true);
- break;
- }
- case SV_ITEMACC:
- {
- int i = getint(p), cn = getint(p);
- playerent *d = getclient(cn);
- pickupeffects(i, d);
- break;
- }
- case SV_EDITXY: // coop editing messages, should be extended to include all possible editing ops
- {
- int cmd = getint(p);
- int x = getint(p);
- int y = getint(p);
- int xs = getint(p);
- int ys = getint(p);
- int a1 = getint(p);
- int a2 = getint(p);
- if(m_coop && !OUTBORD(x,y) && xs > 0 && ys > 0 && !OUTBORD(x + xs-1, y + ys - 1))
- {
- block b = { x, y, xs, ys };
- switch(cmd)
- {
- case EDITXY_HEIGHT: editheightxy(a1 != 0, a2, b); break;
- case EDITXY_TEX: edittexxy(a1, a2, b); break;
- case EDITXY_TYPE: edittypexy(a1, b); break;
- case EDITXY_VDELTA: setvdeltaxy(a1, b); break;
- case EDITXY_EQUALISE: editequalisexy(a1 != 0, b); break;
- case EDITXY_TAG: edittagxy(a1, a2, b); break;
- case EDITXY_SLOPE: slopexy(a1, a2, b); break;
- case EDITXY_STAIRS: stairsxy(a1, a2, b); break;
- case EDITXY_FLIPROT: selfliprotate(b, a1); break;
- }
- }
- break;
- }
- case SV_EDITARCH:
- {
- int av[50]; // MAXARCHVERT, hardcoded
- int x = getint(p);
- int y = getint(p);
- int xs = getint(p);
- int ys = getint(p);
- int a1 = getint(p);
- loopi(50) av[i] = getint(p);
- if(m_coop && !OUTBORD(x,y) && xs > 0 && ys > 0 && !OUTBORD(x + xs-1, y + ys - 1))
- {
- block b = { x, y, xs, ys };
- archxy(a1, av, b);
- }
- break;
- }
- case SV_EDITBLOCK:
- {
- int bx = getuint(p), by = getuint(p), bxs = getuint(p), bys = getuint(p), light = getuint(p);
- ucharbuf *pp = getgzbuf(p);
- if(m_coop) netblockpastexy(pp, bx, by, bxs, bys, light);
- freegzbuf(pp);
- break;
- }
- case SV_NEWMAP:
- {
- int size = getint(p);
- if(!m_coop) break;
- if(size < 0 && sfactor > 9) break; // don't enlarge over 10 in MP
- empty_world(size, true);
- if(d && d!=player1)
- conoutf(size>=0 ? "%s started a new map of size %d" : "%s enlarged the map to size %d", colorname(d), sfactor);
- break;
- }
- case SV_EDITENT: // coop edit of ent
- {
- if(!m_coop)
- {
- loopi(12) getint(p);
- break;
- }
- uint i = getint(p);
- while((uint)ents.length()<=i) ents.add().type = NOTUSED;
- int to = ents[i].type;
- if(ents[i].type==SOUND)
- {
- entity &e = ents[i];
- entityreference entref(&e);
- location *loc = audiomgr.locations.find(e.attr1, &entref, mapsounds);
- if(loc)
- loc->drop();
- }
- ents[i].type = getint(p);
- ents[i].x = getint(p);
- ents[i].y = getint(p);
- ents[i].z = getint(p);
- ents[i].attr1 = getint(p);
- ents[i].attr2 = getint(p);
- ents[i].attr3 = getint(p);
- ents[i].attr4 = getint(p);
- ents[i].attr5 = getint(p);
- ents[i].attr6 = getint(p);
- ents[i].attr7 = getint(p);
- ents[i].spawned = false;
- if(ents[i].type==LIGHT || to==LIGHT) calclight();
- if(ents[i].type==SOUND) audiomgr.preloadmapsound(ents[i]);
- break;
- }
- case SV_PONG:
- {
- int millis = getint(p);
- addmsg(SV_CLIENTPING, "i", player1->ping = max(0, (player1->ping*5+totalmillis-millis)/6));
- break;
- }
- case SV_CLIENTPING:
- if(!d) return;
- d->ping = getint(p);
- break;
- case SV_GAMEMODE:
- nextmode = getint(p);
- if (nextmode >= GMODE_NUM) nextmode -= GMODE_NUM;
- break;
- case SV_TIMEUP:
- {
- int curgamemillis = getint(p);
- int curgamelimit = getint(p);
- timeupdate(curgamemillis, curgamelimit);
- break;
- }
- case SV_WEAPCHANGE:
- {
- int gun = getint(p);
- if(d) d->selectweapon(gun);
- break;
- }
- case SV_SERVMSG:
- getstring(text, p);
- conoutf("%s", text);
- break;
- case SV_FLAGINFO:
- {
- int flag = getint(p);
- if(flag<0 || flag>1) return;
- flaginfo &f = flaginfos[flag];
- f.state = getint(p);
- switch(f.state)
- {
- case CTFF_STOLEN:
- flagstolen(flag, getint(p));
- break;
- case CTFF_DROPPED:
- {
- float x = getuint(p)/DMF;
- float y = getuint(p)/DMF;
- float z = getuint(p)/DMF;
- flagdropped(flag, x, y, z);
- break;
- }
- case CTFF_INBASE:
- flaginbase(flag);
- break;
- case CTFF_IDLE:
- flagidle(flag);
- break;
- }
- break;
- }
- case SV_FLAGMSG:
- {
- int flag = getint(p);
- int message = getint(p);
- int actor = getint(p);
- int flagtime = message == FM_KTFSCORE ? getint(p) : -1;
- flagmsg(flag, message, actor, flagtime);
- break;
- }
- case SV_FLAGCNT:
- {
- int fcn = getint(p);
- int flags = getint(p);
- playerent *p = getclient(fcn);
- if(p) p->flagscore = flags;
- break;
- }
- case SV_ARENAWIN:
- {
- int acn = getint(p);
- playerent *alive = getclient(acn);
- conoutf("the round is over! next round in 5 seconds...");
- if(m_botmode && acn==-2) hudoutf("the bots have won the round!");
- else if(acn==-1) hudoutf("everyone died!");
- else if(m_teammode) hudoutf("team %s has won the round!", team_string(alive->team));
- else if(alive==player1) hudoutf("you are the survivor!");
- else hudoutf("%s is the survivor!", colorname(alive));
- arenaintermission = lastmillis;
- break;
- }
- case SV_SPAWNDENY:
- {
- extern int spawnpermission;
- spawnpermission = getint(p);
- if(spawnpermission == SP_REFILLMATCH) hudoutf("\f3you can spawn now to refill your team");
- break;
- }
- case SV_FORCEDEATH:
- {
- int cn = getint(p);
- playerent *d = cn==getclientnum() ? player1 : newclient(cn);
- if(!d) break;
- deathstate(d);
- break;
- }
- case SV_SERVOPINFO:
- {
- loopv(players) { if(players[i]) players[i]->clientrole = CR_DEFAULT; }
- player1->clientrole = CR_DEFAULT;
- int cl = getint(p), r = getint(p);
- if(cl >= 0 && r >= 0)
- {
- playerent *pl = (cl == getclientnum() ? player1 : newclient(cl));
- if(pl)
- {
- pl->clientrole = r;
- if(pl->name[0])
- {
- // two messages required to allow for proper german translation - is there a better way to do it?
- if(pl==player1) conoutf("you claimed %s status", r == CR_ADMIN ? "admin" : "master");
- else conoutf("%s claimed %s status", colorname(pl), r == CR_ADMIN ? "admin" : "master");
- }
- }
- }
- break;
- }
- case SV_TEAMDENY:
- {
- int t = getint(p);
- if(m_teammode)
- {
- if(team_isvalid(t)) conoutf("you can't change to team %s", team_string(t));
- }
- else
- {
- if(team_isspect(t)) conoutf("you can't change to spectate mode");
- else if (player1->state!=CS_ALIVE) conoutf("you can't change to active mode");
- else conoutf("you can't switch teams while being alive");
- }
- break;
- }
- case SV_SETTEAM:
- {
- int fpl = getint(p), fnt = getint(p), ftr = fnt >> 4;
- fnt &= 0x0f;
- playerent *d = (fpl == getclientnum() ? player1 : newclient(fpl));
- if(d)
- {
- const char *nts = team_string(fnt);
- bool you = fpl == player1->clientnum;
- if(m_teammode || team_isspect(fnt))
- {
- if(d->team == fnt)
- {
- if(you && ftr == FTR_AUTOTEAM) hudoutf("you stay in team %s", nts);
- }
- else
- {
- if(you && !watchingdemo)
- {
- switch(ftr)
- {
- case FTR_PLAYERWISH:
- conoutf("you're now in team %s", nts);
- break;
- case FTR_AUTOTEAM:
- hudoutf("the server forced you to team %s", nts);
- break;
- }
- }
- else
- {
- const char *pls = colorname(d);
- bool et = team_base(player1->team) != team_base(fnt);
- switch(ftr)
- {
- case FTR_PLAYERWISH:
- conoutf("player %s switched to team %s", pls, nts); // new message
- break;
- case FTR_AUTOTEAM:
- if(watchingdemo || team_isspect(player1->team)) conoutf("the server forced %s to team %s", colorname(d), nts);
- else hudoutf("the server forced %s to %s team", colorname(d), et ? "the enemy" : "your");
- break;
- }
- }
- if(you && !team_isspect(d->team) && team_isspect(fnt) && d->state == CS_DEAD) spectatemode(SM_FLY);
- }
- }
- else if(d->team != fnt && ftr == FTR_PLAYERWISH && !team_isactive(d->team)) conoutf("%s changed to active play", you ? "you" : colorname(d));
- d->team = fnt;
- if(team_isspect(d->team)) d->state = CS_SPECTATE;
- }
- break;
- }
- case SV_SERVERMODE:
- {
- int sm = getint(p);
- servstate.autoteam = sm & 1;
- servstate.mastermode = (sm >> 2) & MM_MASK;
- servstate.matchteamsize = sm >> 4;
- //if(sm & AT_SHUFFLE) playsound(TEAMSHUFFLE); // TODO
- break;
- }
- case SV_CALLVOTE:
- {
- int type = getint(p);
- int vcn = -1, n_yes = 0, n_no = 0;
- if ( type == -1 )
- {
- d = getclient(vcn = getint(p));
- n_yes = getint(p);
- n_no = getint(p);
- type = getint(p);
- }
- if (type == SA_MAP && d == NULL) d = player1; // gonext uses this
- if( type < 0 || type >= SA_NUM || !d ) return;
- votedisplayinfo *v = NULL;
- string a1, a2;
- switch(type)
- {
- case SA_MAP:
- {
- getstring(text, p);
- int mode = getint(p);
- if(m_isdemo(mode)) filtertext(text, text, FTXT__DEMONAME);
- else filtertext(text, behindpath(text), FTXT__MAPNAME);
- itoa(a1, mode);
- defformatstring(t)("%d", getint(p));
- v = newvotedisplayinfo(d, type, text, a1, t);
- break;
- }
- case SA_KICK:
- case SA_BAN:
- {
- itoa(a1, getint(p));
- getstring(text, p);
- filtertext(text, text, FTXT__CHAT);
- v = newvotedisplayinfo(d, type, a1, text);
- break;
- }
- case SA_SERVERDESC:
- getstring(text, p);
- filtertext(text, text, FTXT__SERVDESC);
- v = newvotedisplayinfo(d, type, text, NULL);
- break;
- case SA_STOPDEMO:
- // compatibility
- break;
- case SA_REMBANS:
- case SA_SHUFFLETEAMS:
- v = newvotedisplayinfo(d, type, NULL, NULL);
- break;
- case SA_FORCETEAM:
- itoa(a1, getint(p));
- itoa(a2, getint(p));
- v = newvotedisplayinfo(d, type, a1, a2);
- break;
- default:
- itoa(a1, getint(p));
- v = newvotedisplayinfo(d, type, a1, NULL);
- break;
- }
- displayvote(v);
- onCallVote(type, v->owner->clientnum, text, a1);
- if (vcn >= 0)
- {
- loopi(n_yes) votecount(VOTE_YES);
- loopi(n_no) votecount(VOTE_NO);
- }
- extern int vote(int);
- if (d == player1) vote(VOTE_YES);
- break;
- }
- case SV_CALLVOTESUC:
- {
- callvotesuc();
- onChangeVote( 0, -1);
- break;
- }
- case SV_CALLVOTEERR:
- {
- int errn = getint(p);
- callvoteerr(errn);
- onChangeVote( 1, errn);
- break;
- }
- case SV_VOTE:
- {
- int vote = getint(p);
- votecount(vote);
- onChangeVote( 2, vote);
- break;
- }
- case SV_VOTERESULT:
- {
- int vres = getint(p);
- voteresult(vres);
- onChangeVote( 3, vres);
- break;
- }
- case SV_IPLIST:
- {
- int cn;
- while((cn = getint(p)) >= 0 && !p.overread())
- {
- playerent *pl = getclient(cn);
- int ip = getint(p);
- if(!pl) continue;
- else pl->address = ip;
- }
- break;
- }
- case SV_SENDDEMOLIST:
- {
- int demos = getint(p);
- menureset(downloaddemomenu);
- demo_mlines.shrink(0);
- if(!demos)
- {
- conoutf("no demos available");
- mline &m = demo_mlines.add();
- copystring(m.name, "no demos available");
- menuitemmanual(downloaddemomenu,m.name);
- }
- else
- {
- demo_mlines.reserve(demos);
- loopi(demos)
- {
- getstring(text, p);
- conoutf("%d. %s", i+1, text);
- mline &m = demo_mlines.add();
- formatstring(m.name)("%d. %s", i+1, text);
- formatstring(m.cmd)("getdemo %d", i+1);
- menuitemmanual(downloaddemomenu, m.name, m.cmd);
- }
- }
- break;
- }
- case SV_DEMOPLAYBACK:
- {
- bool demoplayback = false;
- string demofile;
- extern char *curdemofile;
- if(demo && watchingdemo && demoprotocol == 1132)
- {
- watchingdemo = demoplayback = getint(p)!=0;
- copystring(demofile, "n/a");
- }
- else
- {
- getstring(demofile, p, MAXSTRLEN);
- watchingdemo = demoplayback = demofile[0] != '\0';
- }
- DELETEA(curdemofile);
- if(demoplayback)
- {
- curdemofile = newstring(demofile);
- player1->resetspec();
- player1->state = CS_SPECTATE;
- player1->team = TEAM_SPECT;
- }
- else
- {
- // cleanups
- curdemofile = newstring("n/a");
- loopv(players) zapplayer(players[i]);
- clearvote();
- player1->state = CS_ALIVE;
- player1->resetspec();
- }
- player1->clientnum = getint(p);
- break;
- }
- default:
- neterr("type");
- return;
- }
- }
- #ifdef _DEBUG
- protocoldebug(false);
- #endif
- }
- void setDemoFilenameFormat(char *fmt)
- {
- extern string demofilenameformat;
- if(fmt && fmt[0]!='\0')
- {
- copystring(demofilenameformat, fmt);
- } else copystring(demofilenameformat, DEFDEMOFILEFMT); // reset to default if passed empty string - or should we output the current value in this case?
- }
- COMMANDN(demonameformat, setDemoFilenameFormat, "s");
- void setDemoTimestampFormat(char *fmt)
- {
- extern string demotimestampformat;
- if(fmt && fmt[0]!='\0')
- {
- copystring(demotimestampformat, fmt);
- } else copystring(demotimestampformat, DEFDEMOTIMEFMT); // reset to default if passed empty string - or should we output the current value in this case?
- }
- COMMANDN(demotimeformat, setDemoTimestampFormat, "s");
- void setDemoTimeLocal(int *truth)
- {
- extern int demotimelocal;
- demotimelocal = *truth == 0 ? 0 : 1;
- }
- COMMANDN(demotimelocal, setDemoTimeLocal, "i");
- void getdemonameformat() { extern string demofilenameformat; result(demofilenameformat); } COMMAND(getdemonameformat, "");
- void getdemotimeformat() { extern string demotimestampformat; result(demotimestampformat); } COMMAND(getdemotimeformat, "");
- void getdemotimelocal() { extern int demotimelocal; intret(demotimelocal); } COMMAND(getdemotimelocal, "");
- const char *parseDemoFilename(char *srvfinfo)
- {
- int gmode = 0; //-314;
- int mplay = 0;
- int mdrop = 0;
- int stamp = 0;
- string srvmap;
- if(srvfinfo && srvfinfo[0])
- {
- int fip = 0;
- char sep[] = ":";
- char *pch, *b;
- pch = strtok_r(srvfinfo, sep, &b);
- while (pch != NULL && fip < 4)
- {
- fip++;
- switch(fip)
- {
- case 1: gmode = atoi(pch); break;
- case 2: mplay = atoi(pch); break;
- case 3: mdrop = atoi(pch); break;
- case 4: stamp = atoi(pch); break;
- default: break;
- }
- pch = strtok_r(NULL, sep, &b);
- }
- copystring(srvmap, pch);
- }
- extern const char *getDemoFilename(int gmode, int mplay, int mdrop, int tstamp, char *srvmap);
- return getDemoFilename(gmode, mplay, mdrop, stamp, srvmap);
- }
- void receivefile(uchar *data, int len)
- {
- static char text[MAXTRANS];
- ucharbuf p(data, len);
- int type = getint(p);
- data += p.length();
- len -= p.length();
- switch(type)
- {
- case SV_SENDDEMO:
- {
- getstring(text, p);
- extern string demosubpath;
- defformatstring(demofn)("%s", parseDemoFilename(text));
- defformatstring(fname)("demos/%s%s.dmo", demosubpath, demofn);
- copystring(demosubpath, "");
- data += strlen(text);
- int demosize = getint(p);
- if(p.remaining() < demosize)
- {
- p.forceoverread();
- break;
- }
- path(fname);
- stream *demo = openfile(fname, "wb");
- if(!demo)
- {
- conoutf("failed writing to \"%s\"", fname);
- return;
- }
- conoutf("received demo \"%s\"", fname);
- demo->write(&p.buf[p.len], demosize);
- delete demo;
- break;
- }
- case SV_RECVMAP:
- {
- getstring(text, p);
- conoutf("received map \"%s\" from server, reloading..", text);
- int mapsize = getint(p);
- int cfgsize = getint(p);
- int cfgsizegz = getint(p);
- /* int revision = */ getint(p);
- int size = mapsize + cfgsizegz;
- if(MAXMAPSENDSIZE < mapsize + cfgsizegz || cfgsize > MAXCFGFILESIZE) { // sam's suggestion
- conoutf("map %s is too large to receive", text);
- } else {
- if(p.remaining() < size)
- {
- p.forceoverread();
- break;
- }
- if(securemapcheck(text))
- {
- p.len += size;
- break;
- }
- writemap(path(text), mapsize, &p.buf[p.len]);
- p.len += mapsize;
- writecfggz(path(text), cfgsize, cfgsizegz, &p.buf[p.len]);
- p.len += cfgsizegz;
- }
- break;
- }
- default:
- p.len = 0;
- parsemessages(-1, NULL, p);
- break;
- }
- }
- void servertoclient(int chan, uchar *buf, int len, bool demo) // processes any updates from the server
- {
- ucharbuf p(buf, len);
- switch(chan)
- {
- case 0: parsepositions(p); break;
- case 1: parsemessages(-1, NULL, p, demo); break;
- case 2: receivefile(p.buf, p.maxlen); break;
- }
- }
- void localservertoclient(int chan, uchar *buf, int len, bool demo) // processes any updates from the server
- {
- // pktlogger.queue(enet_packet_create (buf, len, 0)); // log local & demo packets
- servertoclient(chan, buf, len, demo);
- }
|