1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384 |
- /*
- Copyright (C) 1996-1997 Id Software, Inc.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- // cl_parse.c -- parse a message received from the server
- #include "quakedef.h"
- char *svc_strings[] =
- {
- "svc_bad",
- "svc_nop",
- "svc_disconnect",
- "svc_updatestat",
- "svc_version", // [long] server version
- "svc_setview", // [short] entity number
- "svc_sound", // <see code>
- "svc_time", // [float] server time
- "svc_print", // [string] null terminated string
- "svc_stufftext", // [string] stuffed into client's console buffer
- // the string should be \n terminated
- "svc_setangle", // [vec3] set the view angle to this absolute value
-
- "svc_serverdata", // [long] version ...
- "svc_lightstyle", // [byte] [string]
- "svc_updatename", // [byte] [string]
- "svc_updatefrags", // [byte] [short]
- "svc_clientdata", // <shortbits + data>
- "svc_stopsound", // <see code>
- "svc_updatecolors", // [byte] [byte]
- "svc_particle", // [vec3] <variable>
- "svc_damage", // [byte] impact [byte] blood [vec3] from
-
- "svc_spawnstatic",
- "OBSOLETE svc_spawnbinary",
- "svc_spawnbaseline",
-
- "svc_temp_entity", // <variable>
- "svc_setpause",
- "svc_signonnum",
- "svc_centerprint",
- "svc_killedmonster",
- "svc_foundsecret",
- "svc_spawnstaticsound",
- "svc_intermission",
- "svc_finale",
- "svc_cdtrack",
- "svc_sellscreen",
- "svc_smallkick",
- "svc_bigkick",
- "svc_updateping",
- "svc_updateentertime",
- "svc_updatestatlong",
- "svc_muzzleflash",
- "svc_updateuserinfo",
- "svc_download",
- "svc_playerinfo",
- "svc_nails",
- "svc_choke",
- "svc_modellist",
- "svc_soundlist",
- "svc_packetentities",
- "svc_deltapacketentities",
- "svc_maxspeed",
- "svc_entgravity",
- "svc_setinfo",
- "svc_serverinfo",
- "svc_updatepl",
- "NEW PROTOCOL",
- "NEW PROTOCOL",
- "NEW PROTOCOL",
- "NEW PROTOCOL",
- "NEW PROTOCOL",
- "NEW PROTOCOL",
- "NEW PROTOCOL",
- "NEW PROTOCOL",
- "NEW PROTOCOL",
- "NEW PROTOCOL",
- "NEW PROTOCOL",
- "NEW PROTOCOL",
- "NEW PROTOCOL"
- };
- int oldparsecountmod;
- int parsecountmod;
- double parsecounttime;
- int cl_spikeindex, cl_playerindex, cl_flagindex;
- //=============================================================================
- int packet_latency[NET_TIMINGS];
- int CL_CalcNet (void)
- {
- int a, i;
- frame_t *frame;
- int lost;
- char st[80];
- for (i=cls.netchan.outgoing_sequence-UPDATE_BACKUP+1
- ; i <= cls.netchan.outgoing_sequence
- ; i++)
- {
- frame = &cl.frames[i&UPDATE_MASK];
- if (frame->receivedtime == -1)
- packet_latency[i&NET_TIMINGSMASK] = 9999; // dropped
- else if (frame->receivedtime == -2)
- packet_latency[i&NET_TIMINGSMASK] = 10000; // choked
- else if (frame->invalid)
- packet_latency[i&NET_TIMINGSMASK] = 9998; // invalid delta
- else
- packet_latency[i&NET_TIMINGSMASK] = (frame->receivedtime - frame->senttime)*20;
- }
- lost = 0;
- for (a=0 ; a<NET_TIMINGS ; a++)
- {
- i = (cls.netchan.outgoing_sequence-a) & NET_TIMINGSMASK;
- if (packet_latency[i] == 9999)
- lost++;
- }
- return lost * 100 / NET_TIMINGS;
- }
- //=============================================================================
- /*
- ===============
- CL_CheckOrDownloadFile
- Returns true if the file exists, otherwise it attempts
- to start a download from the server.
- ===============
- */
- qboolean CL_CheckOrDownloadFile (char *filename)
- {
- FILE *f;
- if (strstr (filename, ".."))
- {
- Con_Printf ("Refusing to download a path with ..\n");
- return true;
- }
- COM_FOpenFile (filename, &f);
- if (f)
- { // it exists, no need to download
- fclose (f);
- return true;
- }
- //ZOID - can't download when recording
- if (cls.demorecording) {
- Con_Printf("Unable to download %s in record mode.\n", cls.downloadname);
- return true;
- }
- //ZOID - can't download when playback
- if (cls.demoplayback)
- return true;
- strcpy (cls.downloadname, filename);
- Con_Printf ("Downloading %s...\n", cls.downloadname);
- // download to a temp name, and only rename
- // to the real name when done, so if interrupted
- // a runt file wont be left
- COM_StripExtension (cls.downloadname, cls.downloadtempname);
- strcat (cls.downloadtempname, ".tmp");
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- MSG_WriteString (&cls.netchan.message, va("download %s", cls.downloadname));
- cls.downloadnumber++;
- return false;
- }
- /*
- =================
- Model_NextDownload
- =================
- */
- void Model_NextDownload (void)
- {
- char *s;
- int i;
- extern char gamedirfile[];
- if (cls.downloadnumber == 0)
- {
- Con_Printf ("Checking models...\n");
- cls.downloadnumber = 1;
- }
- cls.downloadtype = dl_model;
- for (
- ; cl.model_name[cls.downloadnumber][0]
- ; cls.downloadnumber++)
- {
- s = cl.model_name[cls.downloadnumber];
- if (s[0] == '*')
- continue; // inline brush model
- if (!CL_CheckOrDownloadFile(s))
- return; // started a download
- }
- for (i=1 ; i<MAX_MODELS ; i++)
- {
- if (!cl.model_name[i][0])
- break;
- cl.model_precache[i] = Mod_ForName (cl.model_name[i], false);
- if (!cl.model_precache[i])
- {
- Con_Printf ("\nThe required model file '%s' could not be found or downloaded.\n\n"
- , cl.model_name[i]);
- Con_Printf ("You may need to download or purchase a %s client "
- "pack in order to play on this server.\n\n", gamedirfile);
- CL_Disconnect ();
- return;
- }
- }
- // all done
- cl.worldmodel = cl.model_precache[1];
- R_NewMap ();
- Hunk_Check (); // make sure nothing is hurt
- // done with modellist, request first of static signon messages
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- // MSG_WriteString (&cls.netchan.message, va("prespawn %i 0 %i", cl.servercount, cl.worldmodel->checksum2));
- MSG_WriteString (&cls.netchan.message, va(prespawn_name, cl.servercount, cl.worldmodel->checksum2));
- }
- /*
- =================
- Sound_NextDownload
- =================
- */
- void Sound_NextDownload (void)
- {
- char *s;
- int i;
- if (cls.downloadnumber == 0)
- {
- Con_Printf ("Checking sounds...\n");
- cls.downloadnumber = 1;
- }
- cls.downloadtype = dl_sound;
- for (
- ; cl.sound_name[cls.downloadnumber][0]
- ; cls.downloadnumber++)
- {
- s = cl.sound_name[cls.downloadnumber];
- if (!CL_CheckOrDownloadFile(va("sound/%s",s)))
- return; // started a download
- }
- for (i=1 ; i<MAX_SOUNDS ; i++)
- {
- if (!cl.sound_name[i][0])
- break;
- cl.sound_precache[i] = S_PrecacheSound (cl.sound_name[i]);
- }
- // done with sounds, request models now
- memset (cl.model_precache, 0, sizeof(cl.model_precache));
- cl_playerindex = -1;
- cl_spikeindex = -1;
- cl_flagindex = -1;
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- // MSG_WriteString (&cls.netchan.message, va("modellist %i 0", cl.servercount));
- MSG_WriteString (&cls.netchan.message, va(modellist_name, cl.servercount, 0));
- }
- /*
- ======================
- CL_RequestNextDownload
- ======================
- */
- void CL_RequestNextDownload (void)
- {
- switch (cls.downloadtype)
- {
- case dl_single:
- break;
- case dl_skin:
- Skin_NextDownload ();
- break;
- case dl_model:
- Model_NextDownload ();
- break;
- case dl_sound:
- Sound_NextDownload ();
- break;
- case dl_none:
- default:
- Con_DPrintf("Unknown download type.\n");
- }
- }
- /*
- =====================
- CL_ParseDownload
- A download message has been received from the server
- =====================
- */
- void CL_ParseDownload (void)
- {
- int size, percent;
- byte name[1024];
- int r;
- // read the data
- size = MSG_ReadShort ();
- percent = MSG_ReadByte ();
- if (cls.demoplayback) {
- if (size > 0)
- msg_readcount += size;
- return; // not in demo playback
- }
- if (size == -1)
- {
- Con_Printf ("File not found.\n");
- if (cls.download)
- {
- Con_Printf ("cls.download shouldn't have been set\n");
- fclose (cls.download);
- cls.download = NULL;
- }
- CL_RequestNextDownload ();
- return;
- }
- // open the file if not opened yet
- if (!cls.download)
- {
- if (strncmp(cls.downloadtempname,"skins/",6))
- sprintf (name, "%s/%s", com_gamedir, cls.downloadtempname);
- else
- sprintf (name, "qw/%s", cls.downloadtempname);
- COM_CreatePath (name);
- cls.download = fopen (name, "wb");
- if (!cls.download)
- {
- msg_readcount += size;
- Con_Printf ("Failed to open %s\n", cls.downloadtempname);
- CL_RequestNextDownload ();
- return;
- }
- }
- fwrite (net_message.data + msg_readcount, 1, size, cls.download);
- msg_readcount += size;
- if (percent != 100)
- {
- // change display routines by zoid
- // request next block
- #if 0
- Con_Printf (".");
- if (10*(percent/10) != cls.downloadpercent)
- {
- cls.downloadpercent = 10*(percent/10);
- Con_Printf ("%i%%", cls.downloadpercent);
- }
- #endif
- cls.downloadpercent = percent;
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- SZ_Print (&cls.netchan.message, "nextdl");
- }
- else
- {
- char oldn[MAX_OSPATH];
- char newn[MAX_OSPATH];
- #if 0
- Con_Printf ("100%%\n");
- #endif
- fclose (cls.download);
- // rename the temp file to it's final name
- if (strcmp(cls.downloadtempname, cls.downloadname)) {
- if (strncmp(cls.downloadtempname,"skins/",6)) {
- sprintf (oldn, "%s/%s", com_gamedir, cls.downloadtempname);
- sprintf (newn, "%s/%s", com_gamedir, cls.downloadname);
- } else {
- sprintf (oldn, "qw/%s", cls.downloadtempname);
- sprintf (newn, "qw/%s", cls.downloadname);
- }
- r = rename (oldn, newn);
- if (r)
- Con_Printf ("failed to rename.\n");
- }
- cls.download = NULL;
- cls.downloadpercent = 0;
- // get another file if needed
- CL_RequestNextDownload ();
- }
- }
- static byte *upload_data;
- static int upload_pos;
- static int upload_size;
- void CL_NextUpload(void)
- {
- byte buffer[1024];
- int r;
- int percent;
- int size;
- if (!upload_data)
- return;
- r = upload_size - upload_pos;
- if (r > 768)
- r = 768;
- memcpy(buffer, upload_data + upload_pos, r);
- MSG_WriteByte (&cls.netchan.message, clc_upload);
- MSG_WriteShort (&cls.netchan.message, r);
- upload_pos += r;
- size = upload_size;
- if (!size)
- size = 1;
- percent = upload_pos*100/size;
- MSG_WriteByte (&cls.netchan.message, percent);
- SZ_Write (&cls.netchan.message, buffer, r);
- Con_DPrintf ("UPLOAD: %6d: %d written\n", upload_pos - r, r);
- if (upload_pos != upload_size)
- return;
- Con_Printf ("Upload completed\n");
- free(upload_data);
- upload_data = 0;
- upload_pos = upload_size = 0;
- }
- void CL_StartUpload (byte *data, int size)
- {
- if (cls.state < ca_onserver)
- return; // gotta be connected
- // override
- if (upload_data)
- free(upload_data);
- Con_DPrintf("Upload starting of %d...\n", size);
- upload_data = malloc(size);
- memcpy(upload_data, data, size);
- upload_size = size;
- upload_pos = 0;
- CL_NextUpload();
- }
- qboolean CL_IsUploading(void)
- {
- if (upload_data)
- return true;
- return false;
- }
- void CL_StopUpload(void)
- {
- if (upload_data)
- free(upload_data);
- upload_data = NULL;
- }
- /*
- =====================================================================
- SERVER CONNECTING MESSAGES
- =====================================================================
- */
- /*
- ==================
- CL_ParseServerData
- ==================
- */
- void CL_ParseServerData (void)
- {
- char *str;
- FILE *f;
- char fn[MAX_OSPATH];
- qboolean cflag = false;
- extern char gamedirfile[MAX_OSPATH];
- int protover;
-
- Con_DPrintf ("Serverdata packet received.\n");
- //
- // wipe the client_state_t struct
- //
- CL_ClearState ();
- // parse protocol version number
- // allow 2.2 and 2.29 demos to play
- protover = MSG_ReadLong ();
- if (protover != PROTOCOL_VERSION &&
- !(cls.demoplayback && (protover == 26 || protover == 27 || protover == 28)))
- Host_EndGame ("Server returned version %i, not %i\nYou probably need to upgrade.\nCheck http://www.quakeworld.net/", protover, PROTOCOL_VERSION);
- cl.servercount = MSG_ReadLong ();
- // game directory
- str = MSG_ReadString ();
- if (stricmp(gamedirfile, str)) {
- // save current config
- Host_WriteConfiguration ();
- cflag = true;
- }
- COM_Gamedir(str);
- //ZOID--run the autoexec.cfg in the gamedir
- //if it exists
- if (cflag) {
- sprintf(fn, "%s/%s", com_gamedir, "config.cfg");
- if ((f = fopen(fn, "r")) != NULL) {
- fclose(f);
- Cbuf_AddText ("cl_warncmd 0\n");
- Cbuf_AddText("exec config.cfg\n");
- Cbuf_AddText("exec frontend.cfg\n");
- Cbuf_AddText ("cl_warncmd 1\n");
- }
- }
- // parse player slot, high bit means spectator
- cl.playernum = MSG_ReadByte ();
- if (cl.playernum & 128)
- {
- cl.spectator = true;
- cl.playernum &= ~128;
- }
- // get the full level name
- str = MSG_ReadString ();
- strncpy (cl.levelname, str, sizeof(cl.levelname)-1);
- // get the movevars
- movevars.gravity = MSG_ReadFloat();
- movevars.stopspeed = MSG_ReadFloat();
- movevars.maxspeed = MSG_ReadFloat();
- movevars.spectatormaxspeed = MSG_ReadFloat();
- movevars.accelerate = MSG_ReadFloat();
- movevars.airaccelerate = MSG_ReadFloat();
- movevars.wateraccelerate = MSG_ReadFloat();
- movevars.friction = MSG_ReadFloat();
- movevars.waterfriction = MSG_ReadFloat();
- movevars.entgravity = MSG_ReadFloat();
- // seperate the printfs so the server message can have a color
- Con_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
- Con_Printf ("%c%s\n", 2, str);
- // ask for the sound list next
- memset(cl.sound_name, 0, sizeof(cl.sound_name));
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- // MSG_WriteString (&cls.netchan.message, va("soundlist %i 0", cl.servercount));
- MSG_WriteString (&cls.netchan.message, va(soundlist_name, cl.servercount, 0));
- // now waiting for downloads, etc
- cls.state = ca_onserver;
- }
- /*
- ==================
- CL_ParseSoundlist
- ==================
- */
- void CL_ParseSoundlist (void)
- {
- int numsounds;
- char *str;
- int n;
- // precache sounds
- // memset (cl.sound_precache, 0, sizeof(cl.sound_precache));
- numsounds = MSG_ReadByte();
- for (;;) {
- str = MSG_ReadString ();
- if (!str[0])
- break;
- numsounds++;
- if (numsounds == MAX_SOUNDS)
- Host_EndGame ("Server sent too many sound_precache");
- strcpy (cl.sound_name[numsounds], str);
- }
- n = MSG_ReadByte();
- if (n) {
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- // MSG_WriteString (&cls.netchan.message, va("soundlist %i %i", cl.servercount, n));
- MSG_WriteString (&cls.netchan.message, va(soundlist_name, cl.servercount, n));
- return;
- }
- cls.downloadnumber = 0;
- cls.downloadtype = dl_sound;
- Sound_NextDownload ();
- }
- /*
- ==================
- CL_ParseModellist
- ==================
- */
- void CL_ParseModellist (void)
- {
- int nummodels;
- char *str;
- int n;
- // precache models and note certain default indexes
- nummodels = MSG_ReadByte();
- for (;;)
- {
- str = MSG_ReadString ();
- if (!str[0])
- break;
- nummodels++;
- if (nummodels==MAX_MODELS)
- Host_EndGame ("Server sent too many model_precache");
- strcpy (cl.model_name[nummodels], str);
- if (!strcmp(cl.model_name[nummodels],"progs/spike.mdl"))
- cl_spikeindex = nummodels;
- if (!strcmp(cl.model_name[nummodels],"progs/player.mdl"))
- cl_playerindex = nummodels;
- if (!strcmp(cl.model_name[nummodels],"progs/flag.mdl"))
- cl_flagindex = nummodels;
- }
- n = MSG_ReadByte();
- if (n) {
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- // MSG_WriteString (&cls.netchan.message, va("modellist %i %i", cl.servercount, n));
- MSG_WriteString (&cls.netchan.message, va(modellist_name, cl.servercount, n));
- return;
- }
- cls.downloadnumber = 0;
- cls.downloadtype = dl_model;
- Model_NextDownload ();
- }
- /*
- ==================
- CL_ParseBaseline
- ==================
- */
- void CL_ParseBaseline (entity_state_t *es)
- {
- int i;
-
- es->modelindex = MSG_ReadByte ();
- es->frame = MSG_ReadByte ();
- es->colormap = MSG_ReadByte();
- es->skinnum = MSG_ReadByte();
- for (i=0 ; i<3 ; i++)
- {
- es->origin[i] = MSG_ReadCoord ();
- es->angles[i] = MSG_ReadAngle ();
- }
- }
- /*
- =====================
- CL_ParseStatic
- Static entities are non-interactive world objects
- like torches
- =====================
- */
- void CL_ParseStatic (void)
- {
- entity_t *ent;
- int i;
- entity_state_t es;
- CL_ParseBaseline (&es);
-
- i = cl.num_statics;
- if (i >= MAX_STATIC_ENTITIES)
- Host_EndGame ("Too many static entities");
- ent = &cl_static_entities[i];
- cl.num_statics++;
- // copy it to the current state
- ent->model = cl.model_precache[es.modelindex];
- ent->frame = es.frame;
- ent->colormap = vid.colormap;
- ent->skinnum = es.skinnum;
- VectorCopy (es.origin, ent->origin);
- VectorCopy (es.angles, ent->angles);
-
- R_AddEfrags (ent);
- }
- /*
- ===================
- CL_ParseStaticSound
- ===================
- */
- void CL_ParseStaticSound (void)
- {
- vec3_t org;
- int sound_num, vol, atten;
- int i;
-
- for (i=0 ; i<3 ; i++)
- org[i] = MSG_ReadCoord ();
- sound_num = MSG_ReadByte ();
- vol = MSG_ReadByte ();
- atten = MSG_ReadByte ();
-
- S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
- }
- /*
- =====================================================================
- ACTION MESSAGES
- =====================================================================
- */
- /*
- ==================
- CL_ParseStartSoundPacket
- ==================
- */
- void CL_ParseStartSoundPacket(void)
- {
- vec3_t pos;
- int channel, ent;
- int sound_num;
- int volume;
- float attenuation;
- int i;
-
- channel = MSG_ReadShort();
- if (channel & SND_VOLUME)
- volume = MSG_ReadByte ();
- else
- volume = DEFAULT_SOUND_PACKET_VOLUME;
-
- if (channel & SND_ATTENUATION)
- attenuation = MSG_ReadByte () / 64.0;
- else
- attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
-
- sound_num = MSG_ReadByte ();
- for (i=0 ; i<3 ; i++)
- pos[i] = MSG_ReadCoord ();
-
- ent = (channel>>3)&1023;
- channel &= 7;
- if (ent > MAX_EDICTS)
- Host_EndGame ("CL_ParseStartSoundPacket: ent = %i", ent);
-
- S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);
- }
- /*
- ==================
- CL_ParseClientdata
- Server information pertaining to this client only, sent every frame
- ==================
- */
- void CL_ParseClientdata (void)
- {
- int i;
- float latency;
- frame_t *frame;
- // calculate simulated time of message
- oldparsecountmod = parsecountmod;
- i = cls.netchan.incoming_acknowledged;
- cl.parsecount = i;
- i &= UPDATE_MASK;
- parsecountmod = i;
- frame = &cl.frames[i];
- parsecounttime = cl.frames[i].senttime;
- frame->receivedtime = realtime;
- // calculate latency
- latency = frame->receivedtime - frame->senttime;
- if (latency < 0 || latency > 1.0)
- {
- // Con_Printf ("Odd latency: %5.2f\n", latency);
- }
- else
- {
- // drift the average latency towards the observed latency
- if (latency < cls.latency)
- cls.latency = latency;
- else
- cls.latency += 0.001; // drift up, so correction are needed
- }
- }
- /*
- =====================
- CL_NewTranslation
- =====================
- */
- void CL_NewTranslation (int slot)
- {
- #ifdef GLQUAKE
- if (slot > MAX_CLIENTS)
- Sys_Error ("CL_NewTranslation: slot > MAX_CLIENTS");
- R_TranslatePlayerSkin(slot);
- #else
- int i, j;
- int top, bottom;
- byte *dest, *source;
- player_info_t *player;
- char s[512];
- if (slot > MAX_CLIENTS)
- Sys_Error ("CL_NewTranslation: slot > MAX_CLIENTS");
- player = &cl.players[slot];
- strcpy(s, Info_ValueForKey(player->userinfo, "skin"));
- COM_StripExtension(s, s);
- if (player->skin && !stricmp(s, player->skin->name))
- player->skin = NULL;
- if (player->_topcolor != player->topcolor ||
- player->_bottomcolor != player->bottomcolor || !player->skin) {
- player->_topcolor = player->topcolor;
- player->_bottomcolor = player->bottomcolor;
- dest = player->translations;
- source = vid.colormap;
- memcpy (dest, vid.colormap, sizeof(player->translations));
- top = player->topcolor;
- if (top > 13 || top < 0)
- top = 13;
- top *= 16;
- bottom = player->bottomcolor;
- if (bottom > 13 || bottom < 0)
- bottom = 13;
- bottom *= 16;
- for (i=0 ; i<VID_GRADES ; i++, dest += 256, source+=256)
- {
- if (top < 128) // the artists made some backwards ranges. sigh.
- memcpy (dest + TOP_RANGE, source + top, 16);
- else
- for (j=0 ; j<16 ; j++)
- dest[TOP_RANGE+j] = source[top+15-j];
-
- if (bottom < 128)
- memcpy (dest + BOTTOM_RANGE, source + bottom, 16);
- else
- for (j=0 ; j<16 ; j++)
- dest[BOTTOM_RANGE+j] = source[bottom+15-j];
- }
- }
- #endif
- }
- /*
- ==============
- CL_UpdateUserinfo
- ==============
- */
- void CL_ProcessUserInfo (int slot, player_info_t *player)
- {
- strncpy (player->name, Info_ValueForKey (player->userinfo, "name"), sizeof(player->name)-1);
- player->topcolor = atoi(Info_ValueForKey (player->userinfo, "topcolor"));
- player->bottomcolor = atoi(Info_ValueForKey (player->userinfo, "bottomcolor"));
- if (Info_ValueForKey (player->userinfo, "*spectator")[0])
- player->spectator = true;
- else
- player->spectator = false;
- if (cls.state == ca_active)
- Skin_Find (player);
- Sbar_Changed ();
- CL_NewTranslation (slot);
- }
- /*
- ==============
- CL_UpdateUserinfo
- ==============
- */
- void CL_UpdateUserinfo (void)
- {
- int slot;
- player_info_t *player;
- slot = MSG_ReadByte ();
- if (slot >= MAX_CLIENTS)
- Host_EndGame ("CL_ParseServerMessage: svc_updateuserinfo > MAX_SCOREBOARD");
- player = &cl.players[slot];
- player->userid = MSG_ReadLong ();
- strncpy (player->userinfo, MSG_ReadString(), sizeof(player->userinfo)-1);
- CL_ProcessUserInfo (slot, player);
- }
- /*
- ==============
- CL_SetInfo
- ==============
- */
- void CL_SetInfo (void)
- {
- int slot;
- player_info_t *player;
- char key[MAX_MSGLEN];
- char value[MAX_MSGLEN];
- slot = MSG_ReadByte ();
- if (slot >= MAX_CLIENTS)
- Host_EndGame ("CL_ParseServerMessage: svc_setinfo > MAX_SCOREBOARD");
- player = &cl.players[slot];
- strncpy (key, MSG_ReadString(), sizeof(key) - 1);
- key[sizeof(key) - 1] = 0;
- strncpy (value, MSG_ReadString(), sizeof(value) - 1);
- key[sizeof(value) - 1] = 0;
- Con_DPrintf("SETINFO %s: %s=%s\n", player->name, key, value);
- Info_SetValueForKey (player->userinfo, key, value, MAX_INFO_STRING);
- CL_ProcessUserInfo (slot, player);
- }
- /*
- ==============
- CL_ServerInfo
- ==============
- */
- void CL_ServerInfo (void)
- {
- int slot;
- player_info_t *player;
- char key[MAX_MSGLEN];
- char value[MAX_MSGLEN];
- strncpy (key, MSG_ReadString(), sizeof(key) - 1);
- key[sizeof(key) - 1] = 0;
- strncpy (value, MSG_ReadString(), sizeof(value) - 1);
- key[sizeof(value) - 1] = 0;
- Con_DPrintf("SERVERINFO: %s=%s\n", key, value);
- Info_SetValueForKey (cl.serverinfo, key, value, MAX_SERVERINFO_STRING);
- }
- /*
- =====================
- CL_SetStat
- =====================
- */
- void CL_SetStat (int stat, int value)
- {
- int j;
- if (stat < 0 || stat >= MAX_CL_STATS)
- Sys_Error ("CL_SetStat: %i is invalid", stat);
- Sbar_Changed ();
-
- if (stat == STAT_ITEMS)
- { // set flash times
- Sbar_Changed ();
- for (j=0 ; j<32 ; j++)
- if ( (value & (1<<j)) && !(cl.stats[stat] & (1<<j)))
- cl.item_gettime[j] = cl.time;
- }
- cl.stats[stat] = value;
- }
- /*
- ==============
- CL_MuzzleFlash
- ==============
- */
- void CL_MuzzleFlash (void)
- {
- vec3_t fv, rv, uv;
- dlight_t *dl;
- int i;
- player_state_t *pl;
- i = MSG_ReadShort ();
- if ((unsigned)(i-1) >= MAX_CLIENTS)
- return;
- #ifdef GLQUAKE
- // don't draw our own muzzle flash in gl if flashblending
- if (i-1 == cl.playernum && gl_flashblend.value)
- return;
- #endif
- pl = &cl.frames[parsecountmod].playerstate[i-1];
- dl = CL_AllocDlight (i);
- VectorCopy (pl->origin, dl->origin);
- AngleVectors (pl->viewangles, fv, rv, uv);
-
- VectorMA (dl->origin, 18, fv, dl->origin);
- dl->radius = 200 + (rand()&31);
- dl->minlight = 32;
- dl->die = cl.time + 0.1;
- dl->color[0] = 0.2;
- dl->color[1] = 0.1;
- dl->color[2] = 0.05;
- dl->color[3] = 0.7;
- }
- #define SHOWNET(x) if(cl_shownet.value==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
- /*
- =====================
- CL_ParseServerMessage
- =====================
- */
- int received_framecount;
- void CL_ParseServerMessage (void)
- {
- int cmd;
- char *s;
- int i, j;
- received_framecount = host_framecount;
- cl.last_servermessage = realtime;
- CL_ClearProjectiles ();
- //
- // if recording demos, copy the message out
- //
- if (cl_shownet.value == 1)
- Con_Printf ("%i ",net_message.cursize);
- else if (cl_shownet.value == 2)
- Con_Printf ("------------------\n");
- CL_ParseClientdata ();
- //
- // parse the message
- //
- while (1)
- {
- if (msg_badread)
- {
- Host_EndGame ("CL_ParseServerMessage: Bad server message");
- break;
- }
- cmd = MSG_ReadByte ();
- if (cmd == -1)
- {
- msg_readcount++; // so the EOM showner has the right value
- SHOWNET("END OF MESSAGE");
- break;
- }
- SHOWNET(svc_strings[cmd]);
-
- // other commands
- switch (cmd)
- {
- default:
- Host_EndGame ("CL_ParseServerMessage: Illegible server message");
- break;
-
- case svc_nop:
- // Con_Printf ("svc_nop\n");
- break;
-
- case svc_disconnect:
- if (cls.state == ca_connected)
- Host_EndGame ("Server disconnected\n"
- "Server version may not be compatible");
- else
- Host_EndGame ("Server disconnected");
- break;
- case svc_print:
- i = MSG_ReadByte ();
- if (i == PRINT_CHAT)
- {
- S_LocalSound ("misc/talk.wav");
- con_ormask = 128;
- }
- Con_Printf ("%s", MSG_ReadString ());
- con_ormask = 0;
- break;
-
- case svc_centerprint:
- SCR_CenterPrint (MSG_ReadString ());
- break;
-
- case svc_stufftext:
- s = MSG_ReadString ();
- Con_DPrintf ("stufftext: %s\n", s);
- Cbuf_AddText (s);
- break;
-
- case svc_damage:
- V_ParseDamage ();
- break;
-
- case svc_serverdata:
- Cbuf_Execute (); // make sure any stuffed commands are done
- CL_ParseServerData ();
- vid.recalc_refdef = true; // leave full screen intermission
- break;
-
- case svc_setangle:
- for (i=0 ; i<3 ; i++)
- cl.viewangles[i] = MSG_ReadAngle ();
- // cl.viewangles[PITCH] = cl.viewangles[ROLL] = 0;
- break;
-
- case svc_lightstyle:
- i = MSG_ReadByte ();
- if (i >= MAX_LIGHTSTYLES)
- Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES");
- Q_strcpy (cl_lightstyle[i].map, MSG_ReadString());
- cl_lightstyle[i].length = Q_strlen(cl_lightstyle[i].map);
- break;
-
- case svc_sound:
- CL_ParseStartSoundPacket();
- break;
-
- case svc_stopsound:
- i = MSG_ReadShort();
- S_StopSound(i>>3, i&7);
- break;
-
- case svc_updatefrags:
- Sbar_Changed ();
- i = MSG_ReadByte ();
- if (i >= MAX_CLIENTS)
- Host_EndGame ("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD");
- cl.players[i].frags = MSG_ReadShort ();
- break;
- case svc_updateping:
- i = MSG_ReadByte ();
- if (i >= MAX_CLIENTS)
- Host_EndGame ("CL_ParseServerMessage: svc_updateping > MAX_SCOREBOARD");
- cl.players[i].ping = MSG_ReadShort ();
- break;
-
- case svc_updatepl:
- i = MSG_ReadByte ();
- if (i >= MAX_CLIENTS)
- Host_EndGame ("CL_ParseServerMessage: svc_updatepl > MAX_SCOREBOARD");
- cl.players[i].pl = MSG_ReadByte ();
- break;
-
- case svc_updateentertime:
- // time is sent over as seconds ago
- i = MSG_ReadByte ();
- if (i >= MAX_CLIENTS)
- Host_EndGame ("CL_ParseServerMessage: svc_updateentertime > MAX_SCOREBOARD");
- cl.players[i].entertime = realtime - MSG_ReadFloat ();
- break;
-
- case svc_spawnbaseline:
- i = MSG_ReadShort ();
- CL_ParseBaseline (&cl_baselines[i]);
- break;
- case svc_spawnstatic:
- CL_ParseStatic ();
- break;
- case svc_temp_entity:
- CL_ParseTEnt ();
- break;
- case svc_killedmonster:
- cl.stats[STAT_MONSTERS]++;
- break;
- case svc_foundsecret:
- cl.stats[STAT_SECRETS]++;
- break;
- case svc_updatestat:
- i = MSG_ReadByte ();
- j = MSG_ReadByte ();
- CL_SetStat (i, j);
- break;
- case svc_updatestatlong:
- i = MSG_ReadByte ();
- j = MSG_ReadLong ();
- CL_SetStat (i, j);
- break;
-
- case svc_spawnstaticsound:
- CL_ParseStaticSound ();
- break;
- case svc_cdtrack:
- cl.cdtrack = MSG_ReadByte ();
- CDAudio_Play ((byte)cl.cdtrack, true);
- break;
- case svc_intermission:
- cl.intermission = 1;
- cl.completed_time = realtime;
- vid.recalc_refdef = true; // go to full screen
- for (i=0 ; i<3 ; i++)
- cl.simorg[i] = MSG_ReadCoord ();
- for (i=0 ; i<3 ; i++)
- cl.simangles[i] = MSG_ReadAngle ();
- VectorCopy (vec3_origin, cl.simvel);
- break;
- case svc_finale:
- cl.intermission = 2;
- cl.completed_time = realtime;
- vid.recalc_refdef = true; // go to full screen
- SCR_CenterPrint (MSG_ReadString ());
- break;
-
- case svc_sellscreen:
- Cmd_ExecuteString ("help");
- break;
- case svc_smallkick:
- cl.punchangle = -2;
- break;
- case svc_bigkick:
- cl.punchangle = -4;
- break;
- case svc_muzzleflash:
- CL_MuzzleFlash ();
- break;
- case svc_updateuserinfo:
- CL_UpdateUserinfo ();
- break;
- case svc_setinfo:
- CL_SetInfo ();
- break;
- case svc_serverinfo:
- CL_ServerInfo ();
- break;
- case svc_download:
- CL_ParseDownload ();
- break;
- case svc_playerinfo:
- CL_ParsePlayerinfo ();
- break;
- case svc_nails:
- CL_ParseProjectiles ();
- break;
- case svc_chokecount: // some preceding packets were choked
- i = MSG_ReadByte ();
- for (j=0 ; j<i ; j++)
- cl.frames[ (cls.netchan.incoming_acknowledged-1-j)&UPDATE_MASK ].receivedtime = -2;
- break;
- case svc_modellist:
- CL_ParseModellist ();
- break;
- case svc_soundlist:
- CL_ParseSoundlist ();
- break;
- case svc_packetentities:
- CL_ParsePacketEntities (false);
- break;
- case svc_deltapacketentities:
- CL_ParsePacketEntities (true);
- break;
- case svc_maxspeed :
- movevars.maxspeed = MSG_ReadFloat();
- break;
- case svc_entgravity :
- movevars.entgravity = MSG_ReadFloat();
- break;
- case svc_setpause:
- cl.paused = MSG_ReadByte ();
- if (cl.paused)
- CDAudio_Pause ();
- else
- CDAudio_Resume ();
- break;
- }
- }
- CL_SetSolidEntities ();
- }
|