12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703 |
- /*
- 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.
- */
- // sv_user.c -- server code for moving users
- #include "qwsvdef.h"
- edict_t *sv_player;
- usercmd_t cmd;
- cvar_t cl_rollspeed = {"cl_rollspeed", "200"};
- cvar_t cl_rollangle = {"cl_rollangle", "2.0"};
- cvar_t sv_spectalk = {"sv_spectalk", "1"};
- cvar_t sv_mapcheck = {"sv_mapcheck", "1"};
- extern vec3_t player_mins;
- extern int fp_messages, fp_persecond, fp_secondsdead;
- extern char fp_msg[];
- extern cvar_t pausable;
- /*
- ============================================================
- USER STRINGCMD EXECUTION
- host_client and sv_player will be valid.
- ============================================================
- */
- /*
- ================
- SV_New_f
- Sends the first message from the server to a connected client.
- This will be sent on the initial connection and upon each server load.
- ================
- */
- void SV_New_f (void)
- {
- char *gamedir;
- int playernum;
- if (host_client->state == cs_spawned)
- return;
- host_client->state = cs_connected;
- host_client->connection_started = realtime;
- // send the info about the new client to all connected clients
- // SV_FullClientUpdate (host_client, &sv.reliable_datagram);
- // host_client->sendinfo = true;
- gamedir = Info_ValueForKey (svs.info, "*gamedir");
- if (!gamedir[0])
- gamedir = "qw";
- //NOTE: This doesn't go through ClientReliableWrite since it's before the user
- //spawns. These functions are written to not overflow
- if (host_client->num_backbuf) {
- Con_Printf("WARNING %s: [SV_New] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize);
- host_client->num_backbuf = 0;
- SZ_Clear(&host_client->netchan.message);
- }
- // send the serverdata
- MSG_WriteByte (&host_client->netchan.message, svc_serverdata);
- MSG_WriteLong (&host_client->netchan.message, PROTOCOL_VERSION);
- MSG_WriteLong (&host_client->netchan.message, svs.spawncount);
- MSG_WriteString (&host_client->netchan.message, gamedir);
- playernum = NUM_FOR_EDICT(host_client->edict)-1;
- if (host_client->spectator)
- playernum |= 128;
- MSG_WriteByte (&host_client->netchan.message, playernum);
- // send full levelname
- MSG_WriteString (&host_client->netchan.message, PR_GetString(sv.edicts->v.message));
- // send the movevars
- MSG_WriteFloat(&host_client->netchan.message, movevars.gravity);
- MSG_WriteFloat(&host_client->netchan.message, movevars.stopspeed);
- MSG_WriteFloat(&host_client->netchan.message, movevars.maxspeed);
- MSG_WriteFloat(&host_client->netchan.message, movevars.spectatormaxspeed);
- MSG_WriteFloat(&host_client->netchan.message, movevars.accelerate);
- MSG_WriteFloat(&host_client->netchan.message, movevars.airaccelerate);
- MSG_WriteFloat(&host_client->netchan.message, movevars.wateraccelerate);
- MSG_WriteFloat(&host_client->netchan.message, movevars.friction);
- MSG_WriteFloat(&host_client->netchan.message, movevars.waterfriction);
- MSG_WriteFloat(&host_client->netchan.message, movevars.entgravity);
- // send music
- MSG_WriteByte (&host_client->netchan.message, svc_cdtrack);
- MSG_WriteByte (&host_client->netchan.message, sv.edicts->v.sounds);
- // send server info string
- MSG_WriteByte (&host_client->netchan.message, svc_stufftext);
- MSG_WriteString (&host_client->netchan.message, va("fullserverinfo \"%s\"\n", svs.info) );
- }
- /*
- ==================
- SV_Soundlist_f
- ==================
- */
- void SV_Soundlist_f (void)
- {
- char **s;
- int n;
- if (host_client->state != cs_connected)
- {
- Con_Printf ("soundlist not valid -- allready spawned\n");
- return;
- }
- // handle the case of a level changing while a client was connecting
- if ( atoi(Cmd_Argv(1)) != svs.spawncount )
- {
- Con_Printf ("SV_Soundlist_f from different level\n");
- SV_New_f ();
- return;
- }
- n = atoi(Cmd_Argv(2));
-
- //NOTE: This doesn't go through ClientReliableWrite since it's before the user
- //spawns. These functions are written to not overflow
- if (host_client->num_backbuf) {
- Con_Printf("WARNING %s: [SV_Soundlist] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize);
- host_client->num_backbuf = 0;
- SZ_Clear(&host_client->netchan.message);
- }
- MSG_WriteByte (&host_client->netchan.message, svc_soundlist);
- MSG_WriteByte (&host_client->netchan.message, n);
- for (s = sv.sound_precache+1 + n ;
- *s && host_client->netchan.message.cursize < (MAX_MSGLEN/2);
- s++, n++)
- MSG_WriteString (&host_client->netchan.message, *s);
- MSG_WriteByte (&host_client->netchan.message, 0);
- // next msg
- if (*s)
- MSG_WriteByte (&host_client->netchan.message, n);
- else
- MSG_WriteByte (&host_client->netchan.message, 0);
- }
- /*
- ==================
- SV_Modellist_f
- ==================
- */
- void SV_Modellist_f (void)
- {
- char **s;
- int n;
- if (host_client->state != cs_connected)
- {
- Con_Printf ("modellist not valid -- allready spawned\n");
- return;
- }
-
- // handle the case of a level changing while a client was connecting
- if ( atoi(Cmd_Argv(1)) != svs.spawncount )
- {
- Con_Printf ("SV_Modellist_f from different level\n");
- SV_New_f ();
- return;
- }
- n = atoi(Cmd_Argv(2));
- //NOTE: This doesn't go through ClientReliableWrite since it's before the user
- //spawns. These functions are written to not overflow
- if (host_client->num_backbuf) {
- Con_Printf("WARNING %s: [SV_Modellist] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize);
- host_client->num_backbuf = 0;
- SZ_Clear(&host_client->netchan.message);
- }
- MSG_WriteByte (&host_client->netchan.message, svc_modellist);
- MSG_WriteByte (&host_client->netchan.message, n);
- for (s = sv.model_precache+1+n ;
- *s && host_client->netchan.message.cursize < (MAX_MSGLEN/2);
- s++, n++)
- MSG_WriteString (&host_client->netchan.message, *s);
- MSG_WriteByte (&host_client->netchan.message, 0);
- // next msg
- if (*s)
- MSG_WriteByte (&host_client->netchan.message, n);
- else
- MSG_WriteByte (&host_client->netchan.message, 0);
- }
- /*
- ==================
- SV_PreSpawn_f
- ==================
- */
- void SV_PreSpawn_f (void)
- {
- unsigned buf;
- unsigned check;
- if (host_client->state != cs_connected)
- {
- Con_Printf ("prespawn not valid -- allready spawned\n");
- return;
- }
-
- // handle the case of a level changing while a client was connecting
- if ( atoi(Cmd_Argv(1)) != svs.spawncount )
- {
- Con_Printf ("SV_PreSpawn_f from different level\n");
- SV_New_f ();
- return;
- }
-
- buf = atoi(Cmd_Argv(2));
- if (buf >= sv.num_signon_buffers)
- buf = 0;
- if (!buf) {
- // should be three numbers following containing checksums
- check = atoi(Cmd_Argv(3));
- // Con_DPrintf("Client check = %d\n", check);
- if (sv_mapcheck.value && check != sv.worldmodel->checksum &&
- check != sv.worldmodel->checksum2) {
- SV_ClientPrintf (host_client, PRINT_HIGH,
- "Map model file does not match (%s), %i != %i/%i.\n"
- "You may need a new version of the map, or the proper install files.\n",
- sv.modelname, check, sv.worldmodel->checksum, sv.worldmodel->checksum2);
- SV_DropClient (host_client);
- return;
- }
- host_client->checksum = check;
- }
- //NOTE: This doesn't go through ClientReliableWrite since it's before the user
- //spawns. These functions are written to not overflow
- if (host_client->num_backbuf) {
- Con_Printf("WARNING %s: [SV_PreSpawn] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize);
- host_client->num_backbuf = 0;
- SZ_Clear(&host_client->netchan.message);
- }
- SZ_Write (&host_client->netchan.message,
- sv.signon_buffers[buf],
- sv.signon_buffer_size[buf]);
- buf++;
- if (buf == sv.num_signon_buffers)
- { // all done prespawning
- MSG_WriteByte (&host_client->netchan.message, svc_stufftext);
- MSG_WriteString (&host_client->netchan.message, va("cmd spawn %i 0\n",svs.spawncount) );
- }
- else
- { // need to prespawn more
- MSG_WriteByte (&host_client->netchan.message, svc_stufftext);
- MSG_WriteString (&host_client->netchan.message,
- va("cmd prespawn %i %i\n", svs.spawncount, buf) );
- }
- }
- /*
- ==================
- SV_Spawn_f
- ==================
- */
- void SV_Spawn_f (void)
- {
- int i;
- client_t *client;
- edict_t *ent;
- eval_t *val;
- int n;
- if (host_client->state != cs_connected)
- {
- Con_Printf ("Spawn not valid -- allready spawned\n");
- return;
- }
- // handle the case of a level changing while a client was connecting
- if ( atoi(Cmd_Argv(1)) != svs.spawncount )
- {
- Con_Printf ("SV_Spawn_f from different level\n");
- SV_New_f ();
- return;
- }
- n = atoi(Cmd_Argv(2));
- // make sure n is valid
- if ( n < 0 || n > MAX_CLIENTS )
- {
- Con_Printf ("SV_Spawn_f invalid client start\n");
- SV_New_f ();
- return;
- }
-
- // send all current names, colors, and frag counts
- // FIXME: is this a good thing?
- SZ_Clear (&host_client->netchan.message);
- // send current status of all other players
- // normally this could overflow, but no need to check due to backbuf
- for (i=n, client = svs.clients + n ; i<MAX_CLIENTS ; i++, client++)
- SV_FullClientUpdateToClient (client, host_client);
-
- // send all current light styles
- for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
- {
- ClientReliableWrite_Begin (host_client, svc_lightstyle,
- 3 + (sv.lightstyles[i] ? strlen(sv.lightstyles[i]) : 1));
- ClientReliableWrite_Byte (host_client, (char)i);
- ClientReliableWrite_String (host_client, sv.lightstyles[i]);
- }
- // set up the edict
- ent = host_client->edict;
- memset (&ent->v, 0, progs->entityfields * 4);
- ent->v.colormap = NUM_FOR_EDICT(ent);
- ent->v.team = 0; // FIXME
- ent->v.netname = PR_SetString(host_client->name);
- host_client->entgravity = 1.0;
- val = GetEdictFieldValue(ent, "gravity");
- if (val)
- val->_float = 1.0;
- host_client->maxspeed = sv_maxspeed.value;
- val = GetEdictFieldValue(ent, "maxspeed");
- if (val)
- val->_float = sv_maxspeed.value;
- //
- // force stats to be updated
- //
- memset (host_client->stats, 0, sizeof(host_client->stats));
- ClientReliableWrite_Begin (host_client, svc_updatestatlong, 6);
- ClientReliableWrite_Byte (host_client, STAT_TOTALSECRETS);
- ClientReliableWrite_Long (host_client, pr_global_struct->total_secrets);
- ClientReliableWrite_Begin (host_client, svc_updatestatlong, 6);
- ClientReliableWrite_Byte (host_client, STAT_TOTALMONSTERS);
- ClientReliableWrite_Long (host_client, pr_global_struct->total_monsters);
- ClientReliableWrite_Begin (host_client, svc_updatestatlong, 6);
- ClientReliableWrite_Byte (host_client, STAT_SECRETS);
- ClientReliableWrite_Long (host_client, pr_global_struct->found_secrets);
- ClientReliableWrite_Begin (host_client, svc_updatestatlong, 6);
- ClientReliableWrite_Byte (host_client, STAT_MONSTERS);
- ClientReliableWrite_Long (host_client, pr_global_struct->killed_monsters);
- // get the client to check and download skins
- // when that is completed, a begin command will be issued
- ClientReliableWrite_Begin (host_client, svc_stufftext, 8);
- ClientReliableWrite_String (host_client, "skins\n" );
- }
- /*
- ==================
- SV_SpawnSpectator
- ==================
- */
- void SV_SpawnSpectator (void)
- {
- int i;
- edict_t *e;
- VectorCopy (vec3_origin, sv_player->v.origin);
- VectorCopy (vec3_origin, sv_player->v.view_ofs);
- sv_player->v.view_ofs[2] = 22;
- // search for an info_playerstart to spawn the spectator at
- for (i=MAX_CLIENTS-1 ; i<sv.num_edicts ; i++)
- {
- e = EDICT_NUM(i);
- if (!strcmp(PR_GetString(e->v.classname), "info_player_start"))
- {
- VectorCopy (e->v.origin, sv_player->v.origin);
- return;
- }
- }
- }
- /*
- ==================
- SV_Begin_f
- ==================
- */
- void SV_Begin_f (void)
- {
- unsigned pmodel = 0, emodel = 0;
- int i;
- if (host_client->state == cs_spawned)
- return; // don't begin again
- host_client->state = cs_spawned;
-
- // handle the case of a level changing while a client was connecting
- if ( atoi(Cmd_Argv(1)) != svs.spawncount )
- {
- Con_Printf ("SV_Begin_f from different level\n");
- SV_New_f ();
- return;
- }
- if (host_client->spectator)
- {
- SV_SpawnSpectator ();
- if (SpectatorConnect) {
- // copy spawn parms out of the client_t
- for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
- (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];
-
- // call the spawn function
- pr_global_struct->time = sv.time;
- pr_global_struct->self = EDICT_TO_PROG(sv_player);
- PR_ExecuteProgram (SpectatorConnect);
- }
- }
- else
- {
- // copy spawn parms out of the client_t
- for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
- (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];
- // call the spawn function
- pr_global_struct->time = sv.time;
- pr_global_struct->self = EDICT_TO_PROG(sv_player);
- PR_ExecuteProgram (pr_global_struct->ClientConnect);
- // actually spawn the player
- pr_global_struct->time = sv.time;
- pr_global_struct->self = EDICT_TO_PROG(sv_player);
- PR_ExecuteProgram (pr_global_struct->PutClientInServer);
- }
- // clear the net statistics, because connecting gives a bogus picture
- host_client->netchan.frame_latency = 0;
- host_client->netchan.frame_rate = 0;
- host_client->netchan.drop_count = 0;
- host_client->netchan.good_count = 0;
- //check he's not cheating
- pmodel = atoi(Info_ValueForKey (host_client->userinfo, "pmodel"));
- emodel = atoi(Info_ValueForKey (host_client->userinfo, "emodel"));
- if (pmodel != sv.model_player_checksum ||
- emodel != sv.eyes_player_checksum)
- SV_BroadcastPrintf (PRINT_HIGH, "%s WARNING: non standard player/eyes model detected\n", host_client->name);
- // if we are paused, tell the client
- if (sv.paused) {
- ClientReliableWrite_Begin (host_client, svc_setpause, 2);
- ClientReliableWrite_Byte (host_client, sv.paused);
- SV_ClientPrintf(host_client, PRINT_HIGH, "Server is paused.\n");
- }
- #if 0
- //
- // send a fixangle over the reliable channel to make sure it gets there
- // Never send a roll angle, because savegames can catch the server
- // in a state where it is expecting the client to correct the angle
- // and it won't happen if the game was just loaded, so you wind up
- // with a permanent head tilt
- ent = EDICT_NUM( 1 + (host_client - svs.clients) );
- MSG_WriteByte (&host_client->netchan.message, svc_setangle);
- for (i=0 ; i < 2 ; i++)
- MSG_WriteAngle (&host_client->netchan.message, ent->v.angles[i] );
- MSG_WriteAngle (&host_client->netchan.message, 0 );
- #endif
- }
- //=============================================================================
- /*
- ==================
- SV_NextDownload_f
- ==================
- */
- void SV_NextDownload_f (void)
- {
- byte buffer[1024];
- int r;
- int percent;
- int size;
- if (!host_client->download)
- return;
- r = host_client->downloadsize - host_client->downloadcount;
- if (r > 768)
- r = 768;
- r = fread (buffer, 1, r, host_client->download);
- ClientReliableWrite_Begin (host_client, svc_download, 6+r);
- ClientReliableWrite_Short (host_client, r);
- host_client->downloadcount += r;
- size = host_client->downloadsize;
- if (!size)
- size = 1;
- percent = host_client->downloadcount*100/size;
- ClientReliableWrite_Byte (host_client, percent);
- ClientReliableWrite_SZ (host_client, buffer, r);
- if (host_client->downloadcount != host_client->downloadsize)
- return;
- fclose (host_client->download);
- host_client->download = NULL;
- }
- void OutofBandPrintf(netadr_t where, char *fmt, ...)
- {
- va_list argptr;
- char send[1024];
-
- send[0] = 0xff;
- send[1] = 0xff;
- send[2] = 0xff;
- send[3] = 0xff;
- send[4] = A2C_PRINT;
- va_start (argptr, fmt);
- vsprintf (send+5, fmt, argptr);
- va_end (argptr);
- NET_SendPacket (strlen(send)+1, send, where);
- }
- /*
- ==================
- SV_NextUpload
- ==================
- */
- void SV_NextUpload (void)
- {
- byte buffer[1024];
- int r;
- int percent;
- int size;
- client_t *client;
- if (!*host_client->uploadfn) {
- SV_ClientPrintf(host_client, PRINT_HIGH, "Upload denied\n");
- ClientReliableWrite_Begin (host_client, svc_stufftext, 8);
- ClientReliableWrite_String (host_client, "stopul");
- // suck out rest of packet
- size = MSG_ReadShort (); MSG_ReadByte ();
- msg_readcount += size;
- return;
- }
- size = MSG_ReadShort ();
- percent = MSG_ReadByte ();
- if (!host_client->upload)
- {
- host_client->upload = fopen(host_client->uploadfn, "wb");
- if (!host_client->upload) {
- Sys_Printf("Can't create %s\n", host_client->uploadfn);
- ClientReliableWrite_Begin (host_client, svc_stufftext, 8);
- ClientReliableWrite_String (host_client, "stopul");
- *host_client->uploadfn = 0;
- return;
- }
- Sys_Printf("Receiving %s from %d...\n", host_client->uploadfn, host_client->userid);
- if (host_client->remote_snap)
- OutofBandPrintf(host_client->snap_from, "Server receiving %s from %d...\n", host_client->uploadfn, host_client->userid);
- }
- fwrite (net_message.data + msg_readcount, 1, size, host_client->upload);
- msg_readcount += size;
- Con_DPrintf ("UPLOAD: %d received\n", size);
- if (percent != 100) {
- ClientReliableWrite_Begin (host_client, svc_stufftext, 8);
- ClientReliableWrite_String (host_client, "nextul\n");
- } else {
- fclose (host_client->upload);
- host_client->upload = NULL;
- Sys_Printf("%s upload completed.\n", host_client->uploadfn);
- if (host_client->remote_snap) {
- char *p;
- if ((p = strchr(host_client->uploadfn, '/')) != NULL)
- p++;
- else
- p = host_client->uploadfn;
- OutofBandPrintf(host_client->snap_from, "%s upload completed.\nTo download, enter:\ndownload %s\n",
- host_client->uploadfn, p);
- }
- }
- }
- /*
- ==================
- SV_BeginDownload_f
- ==================
- */
- void SV_BeginDownload_f(void)
- {
- char *name;
- extern cvar_t allow_download;
- extern cvar_t allow_download_skins;
- extern cvar_t allow_download_models;
- extern cvar_t allow_download_sounds;
- extern cvar_t allow_download_maps;
- extern int file_from_pak; // ZOID did file come from pak?
- name = Cmd_Argv(1);
- // hacked by zoid to allow more conrol over download
- // first off, no .. or global allow check
- if (strstr (name, "..") || !allow_download.value
- // leading dot is no good
- || *name == '.'
- // leading slash bad as well, must be in subdir
- || *name == '/'
- // next up, skin check
- || (strncmp(name, "skins/", 6) == 0 && !allow_download_skins.value)
- // now models
- || (strncmp(name, "progs/", 6) == 0 && !allow_download_models.value)
- // now sounds
- || (strncmp(name, "sound/", 6) == 0 && !allow_download_sounds.value)
- // now maps (note special case for maps, must not be in pak)
- || (strncmp(name, "maps/", 6) == 0 && !allow_download_maps.value)
- // MUST be in a subdirectory
- || !strstr (name, "/") )
- { // don't allow anything with .. path
- ClientReliableWrite_Begin (host_client, svc_download, 4);
- ClientReliableWrite_Short (host_client, -1);
- ClientReliableWrite_Byte (host_client, 0);
- return;
- }
- if (host_client->download) {
- fclose (host_client->download);
- host_client->download = NULL;
- }
- // lowercase name (needed for casesen file systems)
- {
- char *p;
- for (p = name; *p; p++)
- *p = (char)tolower(*p);
- }
- host_client->downloadsize = COM_FOpenFile (name, &host_client->download);
- host_client->downloadcount = 0;
- if (!host_client->download
- // special check for maps, if it came from a pak file, don't allow
- // download ZOID
- || (strncmp(name, "maps/", 5) == 0 && file_from_pak))
- {
- if (host_client->download) {
- fclose(host_client->download);
- host_client->download = NULL;
- }
- Sys_Printf ("Couldn't download %s to %s\n", name, host_client->name);
- ClientReliableWrite_Begin (host_client, svc_download, 4);
- ClientReliableWrite_Short (host_client, -1);
- ClientReliableWrite_Byte (host_client, 0);
- return;
- }
- SV_NextDownload_f ();
- Sys_Printf ("Downloading %s to %s\n", name, host_client->name);
- }
- //=============================================================================
- /*
- ==================
- SV_Say
- ==================
- */
- void SV_Say (qboolean team)
- {
- client_t *client;
- int j, tmp;
- char *p;
- char text[2048];
- char t1[32], *t2;
- if (Cmd_Argc () < 2)
- return;
- if (team)
- {
- strncpy (t1, Info_ValueForKey (host_client->userinfo, "team"), 31);
- t1[31] = 0;
- }
- if (host_client->spectator && (!sv_spectalk.value || team))
- sprintf (text, "[SPEC] %s: ", host_client->name);
- else if (team)
- sprintf (text, "(%s): ", host_client->name);
- else {
- sprintf (text, "%s: ", host_client->name);
- }
- if (fp_messages) {
- if (!sv.paused && realtime<host_client->lockedtill) {
- SV_ClientPrintf(host_client, PRINT_CHAT,
- "You can't talk for %d more seconds\n",
- (int) (host_client->lockedtill - realtime));
- return;
- }
- tmp = host_client->whensaidhead - fp_messages + 1;
- if (tmp < 0)
- tmp = 10+tmp;
- if (!sv.paused &&
- host_client->whensaid[tmp] && (realtime-host_client->whensaid[tmp] < fp_persecond)) {
- host_client->lockedtill = realtime + fp_secondsdead;
- if (fp_msg[0])
- SV_ClientPrintf(host_client, PRINT_CHAT,
- "FloodProt: %s\n", fp_msg);
- else
- SV_ClientPrintf(host_client, PRINT_CHAT,
- "FloodProt: You can't talk for %d seconds.\n", fp_secondsdead);
- return;
- }
- host_client->whensaidhead++;
- if (host_client->whensaidhead > 9)
- host_client->whensaidhead = 0;
- host_client->whensaid[host_client->whensaidhead] = realtime;
- }
- p = Cmd_Args();
- if (*p == '"')
- {
- p++;
- p[Q_strlen(p)-1] = 0;
- }
- Q_strcat(text, p);
- Q_strcat(text, "\n");
- Sys_Printf ("%s", text);
- for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++)
- {
- if (client->state != cs_spawned)
- continue;
- if (host_client->spectator && !sv_spectalk.value)
- if (!client->spectator)
- continue;
- if (team)
- {
- // the spectator team
- if (host_client->spectator) {
- if (!client->spectator)
- continue;
- } else {
- t2 = Info_ValueForKey (client->userinfo, "team");
- if (strcmp(t1, t2) || client->spectator)
- continue; // on different teams
- }
- }
- SV_ClientPrintf(client, PRINT_CHAT, "%s", text);
- }
- }
- /*
- ==================
- SV_Say_f
- ==================
- */
- void SV_Say_f(void)
- {
- SV_Say (false);
- }
- /*
- ==================
- SV_Say_Team_f
- ==================
- */
- void SV_Say_Team_f(void)
- {
- SV_Say (true);
- }
- //============================================================================
- /*
- =================
- SV_Pings_f
- The client is showing the scoreboard, so send new ping times for all
- clients
- =================
- */
- void SV_Pings_f (void)
- {
- client_t *client;
- int j;
- for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++)
- {
- if (client->state != cs_spawned)
- continue;
- ClientReliableWrite_Begin (host_client, svc_updateping, 4);
- ClientReliableWrite_Byte (host_client, j);
- ClientReliableWrite_Short (host_client, SV_CalcPing(client));
- ClientReliableWrite_Begin (host_client, svc_updatepl, 4);
- ClientReliableWrite_Byte (host_client, j);
- ClientReliableWrite_Byte (host_client, client->lossage);
- }
- }
- /*
- ==================
- SV_Kill_f
- ==================
- */
- void SV_Kill_f (void)
- {
- if (sv_player->v.health <= 0)
- {
- SV_ClientPrintf (host_client, PRINT_HIGH, "Can't suicide -- allready dead!\n");
- return;
- }
-
- pr_global_struct->time = sv.time;
- pr_global_struct->self = EDICT_TO_PROG(sv_player);
- PR_ExecuteProgram (pr_global_struct->ClientKill);
- }
- /*
- ==================
- SV_TogglePause
- ==================
- */
- void SV_TogglePause (const char *msg)
- {
- int i;
- client_t *cl;
- sv.paused ^= 1;
- if (msg)
- SV_BroadcastPrintf (PRINT_HIGH, "%s", msg);
- // send notification to all clients
- for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++)
- {
- if (!cl->state)
- continue;
- ClientReliableWrite_Begin (cl, svc_setpause, 2);
- ClientReliableWrite_Byte (cl, sv.paused);
- }
- }
- /*
- ==================
- SV_Pause_f
- ==================
- */
- void SV_Pause_f (void)
- {
- int i;
- client_t *cl;
- char st[sizeof(host_client->name) + 32];
- if (!pausable.value) {
- SV_ClientPrintf (host_client, PRINT_HIGH, "Pause not allowed.\n");
- return;
- }
- if (host_client->spectator) {
- SV_ClientPrintf (host_client, PRINT_HIGH, "Spectators can not pause.\n");
- return;
- }
- if (sv.paused)
- sprintf (st, "%s paused the game\n", host_client->name);
- else
- sprintf (st, "%s unpaused the game\n", host_client->name);
- SV_TogglePause(st);
- }
- /*
- =================
- SV_Drop_f
- The client is going to disconnect, so remove the connection immediately
- =================
- */
- void SV_Drop_f (void)
- {
- SV_EndRedirect ();
- if (!host_client->spectator)
- SV_BroadcastPrintf (PRINT_HIGH, "%s dropped\n", host_client->name);
- SV_DropClient (host_client);
- }
- /*
- =================
- SV_PTrack_f
- Change the bandwidth estimate for a client
- =================
- */
- void SV_PTrack_f (void)
- {
- int i;
- edict_t *ent, *tent;
-
- if (!host_client->spectator)
- return;
- if (Cmd_Argc() != 2)
- {
- // turn off tracking
- host_client->spec_track = 0;
- ent = EDICT_NUM(host_client - svs.clients + 1);
- tent = EDICT_NUM(0);
- ent->v.goalentity = EDICT_TO_PROG(tent);
- return;
- }
-
- i = atoi(Cmd_Argv(1));
- if (i < 0 || i >= MAX_CLIENTS || svs.clients[i].state != cs_spawned ||
- svs.clients[i].spectator) {
- SV_ClientPrintf (host_client, PRINT_HIGH, "Invalid client to track\n");
- host_client->spec_track = 0;
- ent = EDICT_NUM(host_client - svs.clients + 1);
- tent = EDICT_NUM(0);
- ent->v.goalentity = EDICT_TO_PROG(tent);
- return;
- }
- host_client->spec_track = i + 1; // now tracking
- ent = EDICT_NUM(host_client - svs.clients + 1);
- tent = EDICT_NUM(i + 1);
- ent->v.goalentity = EDICT_TO_PROG(tent);
- }
- /*
- =================
- SV_Rate_f
- Change the bandwidth estimate for a client
- =================
- */
- void SV_Rate_f (void)
- {
- int rate;
-
- if (Cmd_Argc() != 2)
- {
- SV_ClientPrintf (host_client, PRINT_HIGH, "Current rate is %i\n",
- (int)(1.0/host_client->netchan.rate + 0.5));
- return;
- }
-
- rate = atoi(Cmd_Argv(1));
- if (rate < 500)
- rate = 500;
- if (rate > 10000)
- rate = 10000;
- SV_ClientPrintf (host_client, PRINT_HIGH, "Net rate set to %i\n", rate);
- host_client->netchan.rate = 1.0/rate;
- }
- /*
- =================
- SV_Msg_f
- Change the message level for a client
- =================
- */
- void SV_Msg_f (void)
- {
- if (Cmd_Argc() != 2)
- {
- SV_ClientPrintf (host_client, PRINT_HIGH, "Current msg level is %i\n",
- host_client->messagelevel);
- return;
- }
-
- host_client->messagelevel = atoi(Cmd_Argv(1));
- SV_ClientPrintf (host_client, PRINT_HIGH, "Msg level set to %i\n", host_client->messagelevel);
- }
- /*
- ==================
- SV_SetInfo_f
- Allow clients to change userinfo
- ==================
- */
- void SV_SetInfo_f (void)
- {
- int i;
- char oldval[MAX_INFO_STRING];
- if (Cmd_Argc() == 1)
- {
- Con_Printf ("User info settings:\n");
- Info_Print (host_client->userinfo);
- return;
- }
- if (Cmd_Argc() != 3)
- {
- Con_Printf ("usage: setinfo [ <key> <value> ]\n");
- return;
- }
- if (Cmd_Argv(1)[0] == '*')
- return; // don't set priveledged values
- strcpy(oldval, Info_ValueForKey(host_client->userinfo, Cmd_Argv(1)));
- Info_SetValueForKey (host_client->userinfo, Cmd_Argv(1), Cmd_Argv(2), MAX_INFO_STRING);
- // name is extracted below in ExtractFromUserInfo
- // strncpy (host_client->name, Info_ValueForKey (host_client->userinfo, "name")
- // , sizeof(host_client->name)-1);
- // SV_FullClientUpdate (host_client, &sv.reliable_datagram);
- // host_client->sendinfo = true;
- if (!strcmp(Info_ValueForKey(host_client->userinfo, Cmd_Argv(1)), oldval))
- return; // key hasn't changed
- // process any changed values
- SV_ExtractFromUserinfo (host_client);
- i = host_client - svs.clients;
- MSG_WriteByte (&sv.reliable_datagram, svc_setinfo);
- MSG_WriteByte (&sv.reliable_datagram, i);
- MSG_WriteString (&sv.reliable_datagram, Cmd_Argv(1));
- MSG_WriteString (&sv.reliable_datagram, Info_ValueForKey(host_client->userinfo, Cmd_Argv(1)));
- }
- /*
- ==================
- SV_ShowServerinfo_f
- Dumps the serverinfo info string
- ==================
- */
- void SV_ShowServerinfo_f (void)
- {
- Info_Print (svs.info);
- }
- void SV_NoSnap_f(void)
- {
- if (*host_client->uploadfn) {
- *host_client->uploadfn = 0;
- SV_BroadcastPrintf (PRINT_HIGH, "%s refused remote screenshot\n", host_client->name);
- }
- }
- typedef struct
- {
- char *name;
- void (*func) (void);
- } ucmd_t;
- ucmd_t ucmds[] =
- {
- {"new", SV_New_f},
- {"modellist", SV_Modellist_f},
- {"soundlist", SV_Soundlist_f},
- {"prespawn", SV_PreSpawn_f},
- {"spawn", SV_Spawn_f},
- {"begin", SV_Begin_f},
- {"drop", SV_Drop_f},
- {"pings", SV_Pings_f},
- // issued by hand at client consoles
- {"rate", SV_Rate_f},
- {"kill", SV_Kill_f},
- {"pause", SV_Pause_f},
- {"msg", SV_Msg_f},
- {"say", SV_Say_f},
- {"say_team", SV_Say_Team_f},
- {"setinfo", SV_SetInfo_f},
- {"serverinfo", SV_ShowServerinfo_f},
- {"download", SV_BeginDownload_f},
- {"nextdl", SV_NextDownload_f},
- {"ptrack", SV_PTrack_f}, //ZOID - used with autocam
- {"snap", SV_NoSnap_f},
-
- {NULL, NULL}
- };
- /*
- ==================
- SV_ExecuteUserCommand
- ==================
- */
- void SV_ExecuteUserCommand (char *s)
- {
- ucmd_t *u;
-
- Cmd_TokenizeString (s);
- sv_player = host_client->edict;
- SV_BeginRedirect (RD_CLIENT);
- for (u=ucmds ; u->name ; u++)
- if (!strcmp (Cmd_Argv(0), u->name) )
- {
- u->func ();
- break;
- }
- if (!u->name)
- Con_Printf ("Bad user command: %s\n", Cmd_Argv(0));
- SV_EndRedirect ();
- }
- /*
- ===========================================================================
- USER CMD EXECUTION
- ===========================================================================
- */
- /*
- ===============
- V_CalcRoll
- Used by view and sv_user
- ===============
- */
- float V_CalcRoll (vec3_t angles, vec3_t velocity)
- {
- vec3_t forward, right, up;
- float sign;
- float side;
- float value;
-
- AngleVectors (angles, forward, right, up);
- side = DotProduct (velocity, right);
- sign = side < 0 ? -1 : 1;
- side = fabs(side);
-
- value = cl_rollangle.value;
- if (side < cl_rollspeed.value)
- side = side * value / cl_rollspeed.value;
- else
- side = value;
-
- return side*sign;
-
- }
- //============================================================================
- vec3_t pmove_mins, pmove_maxs;
- /*
- ====================
- AddLinksToPmove
- ====================
- */
- void AddLinksToPmove ( areanode_t *node )
- {
- link_t *l, *next;
- edict_t *check;
- int pl;
- int i;
- physent_t *pe;
- pl = EDICT_TO_PROG(sv_player);
- // touch linked edicts
- for (l = node->solid_edicts.next ; l != &node->solid_edicts ; l = next)
- {
- next = l->next;
- check = EDICT_FROM_AREA(l);
- if (check->v.owner == pl)
- continue; // player's own missile
- if (check->v.solid == SOLID_BSP
- || check->v.solid == SOLID_BBOX
- || check->v.solid == SOLID_SLIDEBOX)
- {
- if (check == sv_player)
- continue;
- for (i=0 ; i<3 ; i++)
- if (check->v.absmin[i] > pmove_maxs[i]
- || check->v.absmax[i] < pmove_mins[i])
- break;
- if (i != 3)
- continue;
- if (pmove.numphysent == MAX_PHYSENTS)
- return;
- pe = &pmove.physents[pmove.numphysent];
- pmove.numphysent++;
- VectorCopy (check->v.origin, pe->origin);
- pe->info = NUM_FOR_EDICT(check);
- if (check->v.solid == SOLID_BSP)
- pe->model = sv.models[(int)(check->v.modelindex)];
- else
- {
- pe->model = NULL;
- VectorCopy (check->v.mins, pe->mins);
- VectorCopy (check->v.maxs, pe->maxs);
- }
- }
- }
-
- // recurse down both sides
- if (node->axis == -1)
- return;
- if ( pmove_maxs[node->axis] > node->dist )
- AddLinksToPmove ( node->children[0] );
- if ( pmove_mins[node->axis] < node->dist )
- AddLinksToPmove ( node->children[1] );
- }
- /*
- ================
- AddAllEntsToPmove
- For debugging
- ================
- */
- void AddAllEntsToPmove (void)
- {
- int e;
- edict_t *check;
- int i;
- physent_t *pe;
- int pl;
- pl = EDICT_TO_PROG(sv_player);
- check = NEXT_EDICT(sv.edicts);
- for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
- {
- if (check->free)
- continue;
- if (check->v.owner == pl)
- continue;
- if (check->v.solid == SOLID_BSP
- || check->v.solid == SOLID_BBOX
- || check->v.solid == SOLID_SLIDEBOX)
- {
- if (check == sv_player)
- continue;
- for (i=0 ; i<3 ; i++)
- if (check->v.absmin[i] > pmove_maxs[i]
- || check->v.absmax[i] < pmove_mins[i])
- break;
- if (i != 3)
- continue;
- pe = &pmove.physents[pmove.numphysent];
- VectorCopy (check->v.origin, pe->origin);
- pmove.physents[pmove.numphysent].info = e;
- if (check->v.solid == SOLID_BSP)
- pe->model = sv.models[(int)(check->v.modelindex)];
- else
- {
- pe->model = NULL;
- VectorCopy (check->v.mins, pe->mins);
- VectorCopy (check->v.maxs, pe->maxs);
- }
- if (++pmove.numphysent == MAX_PHYSENTS)
- break;
- }
- }
- }
- /*
- ===========
- SV_PreRunCmd
- ===========
- Done before running a player command. Clears the touch array
- */
- byte playertouch[(MAX_EDICTS+7)/8];
- void SV_PreRunCmd(void)
- {
- memset(playertouch, 0, sizeof(playertouch));
- }
- /*
- ===========
- SV_RunCmd
- ===========
- */
- void SV_RunCmd (usercmd_t *ucmd)
- {
- edict_t *ent;
- int i, n;
- int oldmsec;
- cmd = *ucmd;
- // chop up very long commands
- if (cmd.msec > 50)
- {
- oldmsec = ucmd->msec;
- cmd.msec = oldmsec/2;
- SV_RunCmd (&cmd);
- cmd.msec = oldmsec/2;
- cmd.impulse = 0;
- SV_RunCmd (&cmd);
- return;
- }
- if (!sv_player->v.fixangle)
- VectorCopy (ucmd->angles, sv_player->v.v_angle);
- sv_player->v.button0 = ucmd->buttons & 1;
- sv_player->v.button2 = (ucmd->buttons & 2)>>1;
- if (ucmd->impulse)
- sv_player->v.impulse = ucmd->impulse;
- //
- // angles
- // show 1/3 the pitch angle and all the roll angle
- if (sv_player->v.health > 0)
- {
- if (!sv_player->v.fixangle)
- {
- sv_player->v.angles[PITCH] = -sv_player->v.v_angle[PITCH]/3;
- sv_player->v.angles[YAW] = sv_player->v.v_angle[YAW];
- }
- sv_player->v.angles[ROLL] =
- V_CalcRoll (sv_player->v.angles, sv_player->v.velocity)*4;
- }
- host_frametime = ucmd->msec * 0.001;
- if (host_frametime > 0.1)
- host_frametime = 0.1;
- if (!host_client->spectator)
- {
- pr_global_struct->frametime = host_frametime;
- pr_global_struct->time = sv.time;
- pr_global_struct->self = EDICT_TO_PROG(sv_player);
- PR_ExecuteProgram (pr_global_struct->PlayerPreThink);
- SV_RunThink (sv_player);
- }
- for (i=0 ; i<3 ; i++)
- pmove.origin[i] = sv_player->v.origin[i] + (sv_player->v.mins[i] - player_mins[i]);
- VectorCopy (sv_player->v.velocity, pmove.velocity);
- VectorCopy (sv_player->v.v_angle, pmove.angles);
- pmove.spectator = host_client->spectator;
- pmove.waterjumptime = sv_player->v.teleport_time;
- pmove.numphysent = 1;
- pmove.physents[0].model = sv.worldmodel;
- pmove.cmd = *ucmd;
- pmove.dead = sv_player->v.health <= 0;
- pmove.oldbuttons = host_client->oldbuttons;
- movevars.entgravity = host_client->entgravity;
- movevars.maxspeed = host_client->maxspeed;
- for (i=0 ; i<3 ; i++)
- {
- pmove_mins[i] = pmove.origin[i] - 256;
- pmove_maxs[i] = pmove.origin[i] + 256;
- }
- #if 1
- AddLinksToPmove ( sv_areanodes );
- #else
- AddAllEntsToPmove ();
- #endif
- #if 0
- {
- int before, after;
- before = PM_TestPlayerPosition (pmove.origin);
- PlayerMove ();
- after = PM_TestPlayerPosition (pmove.origin);
- if (sv_player->v.health > 0 && before && !after )
- Con_Printf ("player %s got stuck in playermove!!!!\n", host_client->name);
- }
- #else
- PlayerMove ();
- #endif
- host_client->oldbuttons = pmove.oldbuttons;
- sv_player->v.teleport_time = pmove.waterjumptime;
- sv_player->v.waterlevel = waterlevel;
- sv_player->v.watertype = watertype;
- if (onground != -1)
- {
- sv_player->v.flags = (int)sv_player->v.flags | FL_ONGROUND;
- sv_player->v.groundentity = EDICT_TO_PROG(EDICT_NUM(pmove.physents[onground].info));
- }
- else
- sv_player->v.flags = (int)sv_player->v.flags & ~FL_ONGROUND;
- for (i=0 ; i<3 ; i++)
- sv_player->v.origin[i] = pmove.origin[i] - (sv_player->v.mins[i] - player_mins[i]);
- #if 0
- // truncate velocity the same way the net protocol will
- for (i=0 ; i<3 ; i++)
- sv_player->v.velocity[i] = (int)pmove.velocity[i];
- #else
- VectorCopy (pmove.velocity, sv_player->v.velocity);
- #endif
- VectorCopy (pmove.angles, sv_player->v.v_angle);
- if (!host_client->spectator)
- {
- // link into place and touch triggers
- SV_LinkEdict (sv_player, true);
- // touch other objects
- for (i=0 ; i<pmove.numtouch ; i++)
- {
- n = pmove.physents[pmove.touchindex[i]].info;
- ent = EDICT_NUM(n);
- if (!ent->v.touch || (playertouch[n/8]&(1<<(n%8))))
- continue;
- pr_global_struct->self = EDICT_TO_PROG(ent);
- pr_global_struct->other = EDICT_TO_PROG(sv_player);
- PR_ExecuteProgram (ent->v.touch);
- playertouch[n/8] |= 1 << (n%8);
- }
- }
- }
- /*
- ===========
- SV_PostRunCmd
- ===========
- Done after running a player command.
- */
- void SV_PostRunCmd(void)
- {
- // run post-think
- if (!host_client->spectator) {
- pr_global_struct->time = sv.time;
- pr_global_struct->self = EDICT_TO_PROG(sv_player);
- PR_ExecuteProgram (pr_global_struct->PlayerPostThink);
- SV_RunNewmis ();
- } else if (SpectatorThink) {
- pr_global_struct->time = sv.time;
- pr_global_struct->self = EDICT_TO_PROG(sv_player);
- PR_ExecuteProgram (SpectatorThink);
- }
- }
- /*
- ===================
- SV_ExecuteClientMessage
- The current net_message is parsed for the given client
- ===================
- */
- void SV_ExecuteClientMessage (client_t *cl)
- {
- int c;
- char *s;
- usercmd_t oldest, oldcmd, newcmd;
- client_frame_t *frame;
- vec3_t o;
- qboolean move_issued = false; //only allow one move command
- int checksumIndex;
- byte checksum, calculatedChecksum;
- int seq_hash;
- // calc ping time
- frame = &cl->frames[cl->netchan.incoming_acknowledged & UPDATE_MASK];
- frame->ping_time = realtime - frame->senttime;
- // make sure the reply sequence number matches the incoming
- // sequence number
- if (cl->netchan.incoming_sequence >= cl->netchan.outgoing_sequence)
- cl->netchan.outgoing_sequence = cl->netchan.incoming_sequence;
- else
- cl->send_message = false; // don't reply, sequences have slipped
- // save time for ping calculations
- cl->frames[cl->netchan.outgoing_sequence & UPDATE_MASK].senttime = realtime;
- cl->frames[cl->netchan.outgoing_sequence & UPDATE_MASK].ping_time = -1;
- host_client = cl;
- sv_player = host_client->edict;
- // seq_hash = (cl->netchan.incoming_sequence & 0xffff) ; // ^ QW_CHECK_HASH;
- seq_hash = cl->netchan.incoming_sequence;
-
- // mark time so clients will know how much to predict
- // other players
- cl->localtime = sv.time;
- cl->delta_sequence = -1; // no delta unless requested
- while (1)
- {
- if (msg_badread)
- {
- Con_Printf ("SV_ReadClientMessage: badread\n");
- SV_DropClient (cl);
- return;
- }
- c = MSG_ReadByte ();
- if (c == -1)
- break;
-
- switch (c)
- {
- default:
- Con_Printf ("SV_ReadClientMessage: unknown command char\n");
- SV_DropClient (cl);
- return;
-
- case clc_nop:
- break;
- case clc_delta:
- cl->delta_sequence = MSG_ReadByte ();
- break;
- case clc_move:
- if (move_issued)
- return; // someone is trying to cheat...
- move_issued = true;
- checksumIndex = MSG_GetReadCount();
- checksum = (byte)MSG_ReadByte ();
- // read loss percentage
- cl->lossage = MSG_ReadByte();
- MSG_ReadDeltaUsercmd (&nullcmd, &oldest);
- MSG_ReadDeltaUsercmd (&oldest, &oldcmd);
- MSG_ReadDeltaUsercmd (&oldcmd, &newcmd);
- if ( cl->state != cs_spawned )
- break;
- // if the checksum fails, ignore the rest of the packet
- calculatedChecksum = COM_BlockSequenceCRCByte(
- net_message.data + checksumIndex + 1,
- MSG_GetReadCount() - checksumIndex - 1,
- seq_hash);
- if (calculatedChecksum != checksum)
- {
- Con_DPrintf ("Failed command checksum for %s(%d) (%d != %d)\n",
- cl->name, cl->netchan.incoming_sequence, checksum, calculatedChecksum);
- return;
- }
- if (!sv.paused) {
- SV_PreRunCmd();
- if (net_drop < 20)
- {
- while (net_drop > 2)
- {
- SV_RunCmd (&cl->lastcmd);
- net_drop--;
- }
- if (net_drop > 1)
- SV_RunCmd (&oldest);
- if (net_drop > 0)
- SV_RunCmd (&oldcmd);
- }
- SV_RunCmd (&newcmd);
- SV_PostRunCmd();
- }
- cl->lastcmd = newcmd;
- cl->lastcmd.buttons = 0; // avoid multiple fires on lag
- break;
- case clc_stringcmd:
- s = MSG_ReadString ();
- SV_ExecuteUserCommand (s);
- break;
- case clc_tmove:
- o[0] = MSG_ReadCoord();
- o[1] = MSG_ReadCoord();
- o[2] = MSG_ReadCoord();
- // only allowed by spectators
- if (host_client->spectator) {
- VectorCopy(o, sv_player->v.origin);
- SV_LinkEdict(sv_player, false);
- }
- break;
- case clc_upload:
- SV_NextUpload();
- break;
- }
- }
- }
- /*
- ==============
- SV_UserInit
- ==============
- */
- void SV_UserInit (void)
- {
- Cvar_RegisterVariable (&cl_rollspeed);
- Cvar_RegisterVariable (&cl_rollangle);
- Cvar_RegisterVariable (&sv_spectalk);
- Cvar_RegisterVariable (&sv_mapcheck);
- }
|