123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807 |
- /*
- Copyright (C) 1997-2001 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 "client.h"
- char *svc_strings[256] =
- {
- "svc_bad",
- "svc_muzzleflash",
- "svc_muzzlflash2",
- "svc_temp_entity",
- "svc_layout",
- "svc_inventory",
- "svc_nop",
- "svc_disconnect",
- "svc_reconnect",
- "svc_sound",
- "svc_print",
- "svc_stufftext",
- "svc_serverdata",
- "svc_configstring",
- "svc_spawnbaseline",
- "svc_centerprint",
- "svc_download",
- "svc_playerinfo",
- "svc_packetentities",
- "svc_deltapacketentities",
- "svc_frame"
- };
- //=============================================================================
- void CL_DownloadFileName(char *dest, int destlen, char *fn)
- {
- if (strncmp(fn, "players", 7) == 0)
- Com_sprintf (dest, destlen, "%s/%s", BASEDIRNAME, fn);
- else
- Com_sprintf (dest, destlen, "%s/%s", FS_Gamedir(), fn);
- }
- /*
- ===============
- CL_CheckOrDownloadFile
- Returns true if the file exists, otherwise it attempts
- to start a download from the server.
- ===============
- */
- qboolean CL_CheckOrDownloadFile (char *filename)
- {
- FILE *fp;
- char name[MAX_OSPATH];
- if (strstr (filename, ".."))
- {
- Com_Printf ("Refusing to download a path with ..\n");
- return true;
- }
- if (FS_LoadFile (filename, NULL) != -1)
- { // it exists, no need to download
- return true;
- }
- strcpy (cls.downloadname, filename);
- // 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");
- //ZOID
- // check to see if we already have a tmp for this file, if so, try to resume
- // open the file if not opened yet
- CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
- // FS_CreatePath (name);
- fp = fopen (name, "r+b");
- if (fp) { // it exists
- int len;
- fseek(fp, 0, SEEK_END);
- len = ftell(fp);
- cls.download = fp;
- // give the server an offset to start the download
- Com_Printf ("Resuming %s\n", cls.downloadname);
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- MSG_WriteString (&cls.netchan.message,
- va("download %s %i", cls.downloadname, len));
- } else {
- Com_Printf ("Downloading %s\n", cls.downloadname);
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- MSG_WriteString (&cls.netchan.message,
- va("download %s", cls.downloadname));
- }
- cls.downloadnumber++;
- return false;
- }
- /*
- ===============
- CL_Download_f
- Request a download from the server
- ===============
- */
- void CL_Download_f (void)
- {
- char filename[MAX_OSPATH];
- if (Cmd_Argc() != 2) {
- Com_Printf("Usage: download <filename>\n");
- return;
- }
- Com_sprintf(filename, sizeof(filename), "%s", Cmd_Argv(1));
- if (strstr (filename, ".."))
- {
- Com_Printf ("Refusing to download a path with ..\n");
- return;
- }
- if (FS_LoadFile (filename, NULL) != -1)
- { // it exists, no need to download
- Com_Printf("File already exists.\n");
- return;
- }
- strcpy (cls.downloadname, filename);
- Com_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++;
- }
- /*
- ======================
- CL_RegisterSounds
- ======================
- */
- void CL_RegisterSounds (void)
- {
- int i;
- S_BeginRegistration ();
- CL_RegisterTEntSounds ();
- for (i=1 ; i<MAX_SOUNDS ; i++)
- {
- if (!cl.configstrings[CS_SOUNDS+i][0])
- break;
- cl.sound_precache[i] = S_RegisterSound (cl.configstrings[CS_SOUNDS+i]);
- Sys_SendKeyEvents (); // pump message loop
- }
- S_EndRegistration ();
- }
- /*
- =====================
- CL_ParseDownload
- A download message has been received from the server
- =====================
- */
- void CL_ParseDownload (void)
- {
- int size, percent;
- char name[MAX_OSPATH];
- int r;
- // read the data
- size = MSG_ReadShort (&net_message);
- percent = MSG_ReadByte (&net_message);
- if (size == -1)
- {
- Com_Printf ("Server does not have this file.\n");
- if (cls.download)
- {
- // if here, we tried to resume a file but the server said no
- fclose (cls.download);
- cls.download = NULL;
- }
- CL_RequestNextDownload ();
- return;
- }
- // open the file if not opened yet
- if (!cls.download)
- {
- CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
- FS_CreatePath (name);
- cls.download = fopen (name, "wb");
- if (!cls.download)
- {
- net_message.readcount += size;
- Com_Printf ("Failed to open %s\n", cls.downloadtempname);
- CL_RequestNextDownload ();
- return;
- }
- }
- fwrite (net_message.data + net_message.readcount, 1, size, cls.download);
- net_message.readcount += size;
- if (percent != 100)
- {
- // request next block
- // change display routines by zoid
- #if 0
- Com_Printf (".");
- if (10*(percent/10) != cls.downloadpercent)
- {
- cls.downloadpercent = 10*(percent/10);
- Com_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];
- // Com_Printf ("100%%\n");
- fclose (cls.download);
- // rename the temp file to it's final name
- CL_DownloadFileName(oldn, sizeof(oldn), cls.downloadtempname);
- CL_DownloadFileName(newn, sizeof(newn), cls.downloadname);
- r = rename (oldn, newn);
- if (r)
- Com_Printf ("failed to rename.\n");
- cls.download = NULL;
- cls.downloadpercent = 0;
- // get another file if needed
- CL_RequestNextDownload ();
- }
- }
- /*
- =====================================================================
- SERVER CONNECTING MESSAGES
- =====================================================================
- */
- /*
- ==================
- CL_ParseServerData
- ==================
- */
- void CL_ParseServerData (void)
- {
- extern cvar_t *fs_gamedirvar;
- char *str;
- int i;
-
- Com_DPrintf ("Serverdata packet received.\n");
- //
- // wipe the client_state_t struct
- //
- CL_ClearState ();
- cls.state = ca_connected;
- // parse protocol version number
- i = MSG_ReadLong (&net_message);
- cls.serverProtocol = i;
- // BIG HACK to let demos from release work with the 3.0x patch!!!
- if (Com_ServerState() && PROTOCOL_VERSION == 34)
- {
- }
- else if (i != PROTOCOL_VERSION)
- Com_Error (ERR_DROP,"Server returned version %i, not %i", i, PROTOCOL_VERSION);
- cl.servercount = MSG_ReadLong (&net_message);
- cl.attractloop = MSG_ReadByte (&net_message);
- // game directory
- str = MSG_ReadString (&net_message);
- strncpy (cl.gamedir, str, sizeof(cl.gamedir)-1);
- // set gamedir
- if ((*str && (!fs_gamedirvar->string || !*fs_gamedirvar->string || strcmp(fs_gamedirvar->string, str))) || (!*str && (fs_gamedirvar->string || *fs_gamedirvar->string)))
- Cvar_Set("game", str);
- // parse player entity number
- cl.playernum = MSG_ReadShort (&net_message);
- // get the full level name
- str = MSG_ReadString (&net_message);
- if (cl.playernum == -1)
- { // playing a cinematic or showing a pic, not a level
- SCR_PlayCinematic (str);
- }
- else
- {
- // seperate the printfs so the server message can have a color
- Com_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");
- Com_Printf ("%c%s\n", 2, str);
- // need to prep refresh at next oportunity
- cl.refresh_prepped = false;
- }
- }
- /*
- ==================
- CL_ParseBaseline
- ==================
- */
- void CL_ParseBaseline (void)
- {
- entity_state_t *es;
- int bits;
- int newnum;
- entity_state_t nullstate;
- memset (&nullstate, 0, sizeof(nullstate));
- newnum = CL_ParseEntityBits (&bits);
- es = &cl_entities[newnum].baseline;
- CL_ParseDelta (&nullstate, es, newnum, bits);
- }
- /*
- ================
- CL_LoadClientinfo
- ================
- */
- void CL_LoadClientinfo (clientinfo_t *ci, char *s)
- {
- int i;
- char *t;
- char model_name[MAX_QPATH];
- char skin_name[MAX_QPATH];
- char model_filename[MAX_QPATH];
- char skin_filename[MAX_QPATH];
- char weapon_filename[MAX_QPATH];
- strncpy(ci->cinfo, s, sizeof(ci->cinfo));
- ci->cinfo[sizeof(ci->cinfo)-1] = 0;
- // isolate the player's name
- strncpy(ci->name, s, sizeof(ci->name));
- ci->name[sizeof(ci->name)-1] = 0;
- t = strstr (s, "\\");
- if (t)
- {
- ci->name[t-s] = 0;
- s = t+1;
- }
- if (cl_noskins->value || *s == 0)
- {
- Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
- Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/weapon.md2");
- Com_sprintf (skin_filename, sizeof(skin_filename), "players/male/grunt.pcx");
- Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/male/grunt_i.pcx");
- ci->model = re.RegisterModel (model_filename);
- memset(ci->weaponmodel, 0, sizeof(ci->weaponmodel));
- ci->weaponmodel[0] = re.RegisterModel (weapon_filename);
- ci->skin = re.RegisterSkin (skin_filename);
- ci->icon = re.RegisterPic (ci->iconname);
- }
- else
- {
- // isolate the model name
- strcpy (model_name, s);
- t = strstr(model_name, "/");
- if (!t)
- t = strstr(model_name, "\\");
- if (!t)
- t = model_name;
- *t = 0;
- // isolate the skin name
- strcpy (skin_name, s + strlen(model_name) + 1);
- // model file
- Com_sprintf (model_filename, sizeof(model_filename), "players/%s/tris.md2", model_name);
- ci->model = re.RegisterModel (model_filename);
- if (!ci->model)
- {
- strcpy(model_name, "male");
- Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
- ci->model = re.RegisterModel (model_filename);
- }
- // skin file
- Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
- ci->skin = re.RegisterSkin (skin_filename);
- // if we don't have the skin and the model wasn't male,
- // see if the male has it (this is for CTF's skins)
- if (!ci->skin && Q_stricmp(model_name, "male"))
- {
- // change model to male
- strcpy(model_name, "male");
- Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
- ci->model = re.RegisterModel (model_filename);
- // see if the skin exists for the male model
- Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
- ci->skin = re.RegisterSkin (skin_filename);
- }
- // if we still don't have a skin, it means that the male model didn't have
- // it, so default to grunt
- if (!ci->skin) {
- // see if the skin exists for the male model
- Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/grunt.pcx", model_name, skin_name);
- ci->skin = re.RegisterSkin (skin_filename);
- }
- // weapon file
- for (i = 0; i < num_cl_weaponmodels; i++) {
- Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/%s/%s", model_name, cl_weaponmodels[i]);
- ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
- if (!ci->weaponmodel[i] && strcmp(model_name, "cyborg") == 0) {
- // try male
- Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/%s", cl_weaponmodels[i]);
- ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
- }
- if (!cl_vwep->value)
- break; // only one when vwep is off
- }
- // icon file
- Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/%s/%s_i.pcx", model_name, skin_name);
- ci->icon = re.RegisterPic (ci->iconname);
- }
- // must have loaded all data types to be valud
- if (!ci->skin || !ci->icon || !ci->model || !ci->weaponmodel[0])
- {
- ci->skin = NULL;
- ci->icon = NULL;
- ci->model = NULL;
- ci->weaponmodel[0] = NULL;
- return;
- }
- }
- /*
- ================
- CL_ParseClientinfo
- Load the skin, icon, and model for a client
- ================
- */
- void CL_ParseClientinfo (int player)
- {
- char *s;
- clientinfo_t *ci;
- s = cl.configstrings[player+CS_PLAYERSKINS];
- ci = &cl.clientinfo[player];
- CL_LoadClientinfo (ci, s);
- }
- /*
- ================
- CL_ParseConfigString
- ================
- */
- void CL_ParseConfigString (void)
- {
- int i;
- char *s;
- i = MSG_ReadShort (&net_message);
- if (i < 0 || i >= MAX_CONFIGSTRINGS)
- Com_Error (ERR_DROP, "configstring > MAX_CONFIGSTRINGS");
- s = MSG_ReadString(&net_message);
- strcpy (cl.configstrings[i], s);
- // do something apropriate
- if (i >= CS_LIGHTS && i < CS_LIGHTS+MAX_LIGHTSTYLES)
- CL_SetLightstyle (i - CS_LIGHTS);
- else if (i == CS_CDTRACK)
- {
- if (cl.refresh_prepped)
- CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
- }
- else if (i >= CS_MODELS && i < CS_MODELS+MAX_MODELS)
- {
- if (cl.refresh_prepped)
- {
- cl.model_draw[i-CS_MODELS] = re.RegisterModel (cl.configstrings[i]);
- if (cl.configstrings[i][0] == '*')
- cl.model_clip[i-CS_MODELS] = CM_InlineModel (cl.configstrings[i]);
- else
- cl.model_clip[i-CS_MODELS] = NULL;
- }
- }
- else if (i >= CS_SOUNDS && i < CS_SOUNDS+MAX_MODELS)
- {
- if (cl.refresh_prepped)
- cl.sound_precache[i-CS_SOUNDS] = S_RegisterSound (cl.configstrings[i]);
- }
- else if (i >= CS_IMAGES && i < CS_IMAGES+MAX_MODELS)
- {
- if (cl.refresh_prepped)
- cl.image_precache[i-CS_IMAGES] = re.RegisterPic (cl.configstrings[i]);
- }
- else if (i >= CS_PLAYERSKINS && i < CS_PLAYERSKINS+MAX_CLIENTS)
- {
- if (cl.refresh_prepped)
- CL_ParseClientinfo (i-CS_PLAYERSKINS);
- }
- }
- /*
- =====================================================================
- ACTION MESSAGES
- =====================================================================
- */
- /*
- ==================
- CL_ParseStartSoundPacket
- ==================
- */
- void CL_ParseStartSoundPacket(void)
- {
- vec3_t pos_v;
- float *pos;
- int channel, ent;
- int sound_num;
- float volume;
- float attenuation;
- int flags;
- float ofs;
- flags = MSG_ReadByte (&net_message);
- sound_num = MSG_ReadByte (&net_message);
- if (flags & SND_VOLUME)
- volume = MSG_ReadByte (&net_message) / 255.0;
- else
- volume = DEFAULT_SOUND_PACKET_VOLUME;
-
- if (flags & SND_ATTENUATION)
- attenuation = MSG_ReadByte (&net_message) / 64.0;
- else
- attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
- if (flags & SND_OFFSET)
- ofs = MSG_ReadByte (&net_message) / 1000.0;
- else
- ofs = 0;
- if (flags & SND_ENT)
- { // entity reletive
- channel = MSG_ReadShort(&net_message);
- ent = channel>>3;
- if (ent > MAX_EDICTS)
- Com_Error (ERR_DROP,"CL_ParseStartSoundPacket: ent = %i", ent);
- channel &= 7;
- }
- else
- {
- ent = 0;
- channel = 0;
- }
- if (flags & SND_POS)
- { // positioned in space
- MSG_ReadPos (&net_message, pos_v);
-
- pos = pos_v;
- }
- else // use entity number
- pos = NULL;
- if (!cl.sound_precache[sound_num])
- return;
- S_StartSound (pos, ent, channel, cl.sound_precache[sound_num], volume, attenuation, ofs);
- }
- void SHOWNET(char *s)
- {
- if (cl_shownet->value>=2)
- Com_Printf ("%3i:%s\n", net_message.readcount-1, s);
- }
- /*
- =====================
- CL_ParseServerMessage
- =====================
- */
- void CL_ParseServerMessage (void)
- {
- int cmd;
- char *s;
- int i;
- //
- // if recording demos, copy the message out
- //
- if (cl_shownet->value == 1)
- Com_Printf ("%i ",net_message.cursize);
- else if (cl_shownet->value >= 2)
- Com_Printf ("------------------\n");
- //
- // parse the message
- //
- while (1)
- {
- if (net_message.readcount > net_message.cursize)
- {
- Com_Error (ERR_DROP,"CL_ParseServerMessage: Bad server message");
- break;
- }
- cmd = MSG_ReadByte (&net_message);
- if (cmd == -1)
- {
- SHOWNET("END OF MESSAGE");
- break;
- }
- if (cl_shownet->value>=2)
- {
- if (!svc_strings[cmd])
- Com_Printf ("%3i:BAD CMD %i\n", net_message.readcount-1,cmd);
- else
- SHOWNET(svc_strings[cmd]);
- }
-
- // other commands
- switch (cmd)
- {
- default:
- Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
- break;
-
- case svc_nop:
- // Com_Printf ("svc_nop\n");
- break;
-
- case svc_disconnect:
- Com_Error (ERR_DISCONNECT,"Server disconnected\n");
- break;
- case svc_reconnect:
- Com_Printf ("Server disconnected, reconnecting\n");
- if (cls.download) {
- //ZOID, close download
- fclose (cls.download);
- cls.download = NULL;
- }
- cls.state = ca_connecting;
- cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
- break;
- case svc_print:
- i = MSG_ReadByte (&net_message);
- if (i == PRINT_CHAT)
- {
- S_StartLocalSound ("misc/talk.wav");
- con.ormask = 128;
- }
- Com_Printf ("%s", MSG_ReadString (&net_message));
- con.ormask = 0;
- break;
-
- case svc_centerprint:
- SCR_CenterPrint (MSG_ReadString (&net_message));
- break;
-
- case svc_stufftext:
- s = MSG_ReadString (&net_message);
- Com_DPrintf ("stufftext: %s\n", s);
- Cbuf_AddText (s);
- break;
-
- case svc_serverdata:
- Cbuf_Execute (); // make sure any stuffed commands are done
- CL_ParseServerData ();
- break;
-
- case svc_configstring:
- CL_ParseConfigString ();
- break;
-
- case svc_sound:
- CL_ParseStartSoundPacket();
- break;
-
- case svc_spawnbaseline:
- CL_ParseBaseline ();
- break;
- case svc_temp_entity:
- CL_ParseTEnt ();
- break;
- case svc_muzzleflash:
- CL_ParseMuzzleFlash ();
- break;
- case svc_muzzleflash2:
- CL_ParseMuzzleFlash2 ();
- break;
- case svc_download:
- CL_ParseDownload ();
- break;
- case svc_frame:
- CL_ParseFrame ();
- break;
- case svc_inventory:
- CL_ParseInventory ();
- break;
- case svc_layout:
- s = MSG_ReadString (&net_message);
- strncpy (cl.layout, s, sizeof(cl.layout)-1);
- break;
- case svc_playerinfo:
- case svc_packetentities:
- case svc_deltapacketentities:
- Com_Error (ERR_DROP, "Out of place frame data");
- break;
- }
- }
- CL_AddNetgraph ();
- //
- // we don't know if it is ok to save a demo message until
- // after we have parsed the frame
- //
- if (cls.demorecording && !cls.demowaiting)
- CL_WriteDemoMessage ();
- }
|