2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 // sv_main.c -- server main program
28 void VM_CustomStats_Clear (void);
29 void EntityFrameCSQC_ClearVersions (void);
30 void EntityFrameCSQC_InitClientVersions (int client, qboolean clear);
31 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats);
32 void EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int numstates, const entity_state_t *states);
35 // select which protocol to host, this is fed to Protocol_EnumForName
36 cvar_t sv_protocolname = {0, "sv_protocolname", "DP7", "selects network protocol to host for (values include QUAKE, QUAKEDP, NEHAHRAMOVIE, DP1 and up)"};
37 cvar_t sv_ratelimitlocalplayer = {0, "sv_ratelimitlocalplayer", "0", "whether to apply rate limiting to the local player in a listen server (only useful for testing)"};
38 cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "10000", "upper limit on client rate cvar, should reflect your network connection quality"};
39 cvar_t sv_allowdownloads = {0, "sv_allowdownloads", "1", "whether to allow clients to download files from the server (does not affect http downloads)"};
40 cvar_t sv_allowdownloads_inarchive = {0, "sv_allowdownloads_inarchive", "0", "whether to allow downloads from archives (pak/pk3)"};
41 cvar_t sv_allowdownloads_archive = {0, "sv_allowdownloads_archive", "0", "whether to allow downloads of archives (pak/pk3)"};
42 cvar_t sv_allowdownloads_config = {0, "sv_allowdownloads_config", "0", "whether to allow downloads of config files (cfg)"};
43 cvar_t sv_allowdownloads_dlcache = {0, "sv_allowdownloads_dlcache", "0", "whether to allow downloads of dlcache files (dlcache/)"};
45 extern cvar_t sv_random_seed;
47 static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"}; // fast but loose
48 static cvar_t sv_cullentities_trace = {0, "sv_cullentities_trace", "0", "somewhat slow but very tight culling of hidden entities, minimizes network traffic and makes wallhack cheats useless"}; // tends to get false negatives, uses a timeout to keep entities visible a short time after becoming hidden
49 static cvar_t sv_cullentities_trace_samples = {0, "sv_cullentities_trace_samples", "1", "number of samples to test for entity culling"};
50 static cvar_t sv_cullentities_trace_samples_extra = {0, "sv_cullentities_trace_samples_extra", "2", "number of samples to test for entity culling when the entity affects its surroundings by e.g. dlight"};
51 static cvar_t sv_cullentities_trace_enlarge = {0, "sv_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
52 static cvar_t sv_cullentities_trace_delay = {0, "sv_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
53 static cvar_t sv_cullentities_trace_prediction = {0, "sv_cullentities_trace_prediction", "1", "also trace from the predicted player position"};
54 static cvar_t sv_cullentities_nevercullbmodels = {0, "sv_cullentities_nevercullbmodels", "0", "if enabled the clients are always notified of moving doors and lifts and other submodels of world (warning: eats a lot of network bandwidth on some levels!)"};
55 static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
56 static cvar_t sv_entpatch = {0, "sv_entpatch", "1", "enables loading of .ent files to override entities in the bsp (for example Threewave CTF server pack contains .ent patch files enabling play of CTF on id1 maps)"};
58 cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebouncedownslopes", "1", "prevents MOVETYPE_BOUNCE (grenades) from getting stuck when fired down a downward sloping surface"};
59 cvar_t sv_gameplayfix_noairborncorpse = {0, "sv_gameplayfix_noairborncorpse", "1", "causes entities (corpses) sitting ontop of moving entities (players) to fall when the moving entity (player) is no longer supporting them"};
60 cvar_t sv_gameplayfix_stepdown = {0, "sv_gameplayfix_stepdown", "0", "attempts to step down stairs, not just up them (prevents the familiar thud..thud..thud.. when running down stairs and slopes)"};
61 cvar_t sv_gameplayfix_stepwhilejumping = {0, "sv_gameplayfix_stepwhilejumping", "1", "applies step-up onto a ledge even while airborn, useful if you would otherwise just-miss the floor when running across small areas with gaps (for instance running across the moving platforms in dm2, or jumping to the megahealth and red armor in dm2 rather than using the bridge)"};
62 cvar_t sv_gameplayfix_swiminbmodels = {0, "sv_gameplayfix_swiminbmodels", "1", "causes pointcontents (used to determine if you are in a liquid) to check bmodel entities as well as the world model, so you can swim around in (possibly moving) water bmodel entities"};
63 cvar_t sv_gameplayfix_setmodelrealbox = {0, "sv_gameplayfix_setmodelrealbox", "1", "fixes a bug in Quake that made setmodel always set the entity box to ('-16 -16 -16', '16 16 16') rather than properly checking the model box, breaks some poorly coded mods"};
64 cvar_t sv_gameplayfix_blowupfallenzombies = {0, "sv_gameplayfix_blowupfallenzombies", "1", "causes findradius to detect SOLID_NOT entities such as zombies and corpses on the floor, allowing splash damage to apply to them"};
65 cvar_t sv_gameplayfix_findradiusdistancetobox = {0, "sv_gameplayfix_findradiusdistancetobox", "1", "causes findradius to check the distance to the corner of a box rather than the center of the box, makes findradius detect bmodels such as very large doors that would otherwise be unaffected by splash damage"};
66 cvar_t sv_gameplayfix_qwplayerphysics = {0, "sv_gameplayfix_qwplayerphysics", "1", "changes water jumping to make it easier to get out of water, and prevents friction on landing when bunnyhopping"};
67 cvar_t sv_gameplayfix_upwardvelocityclearsongroundflag = {0, "sv_gameplayfix_upwardvelocityclearsongroundflag", "1", "prevents monsters, items, and most other objects from being stuck to the floor when pushed around by damage, and other situations in mods"};
68 cvar_t sv_gameplayfix_droptofloorstartsolid = {0, "sv_gameplayfix_droptofloorstartsolid", "1", "prevents items and monsters that start in a solid area from falling out of the level (makes droptofloor treat trace_startsolid as an acceptable outcome)"};
70 cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
72 // TODO: move these cvars here
73 extern cvar_t sv_clmovement_enable;
74 extern cvar_t sv_clmovement_minping;
75 extern cvar_t sv_clmovement_minping_disabletime;
76 extern cvar_t sv_clmovement_waitforinput;
81 mempool_t *sv_mempool = NULL;
83 //============================================================================
85 extern void SV_Phys_Init (void);
86 static void SV_SaveEntFile_f(void);
87 static void SV_StartDownload_f(void);
88 static void SV_Download_f(void);
90 void SV_AreaStats_f(void)
92 World_PrintAreaStats(&sv.world, "server");
102 // init the csqc progs cvars, since they are updated/used by the server code
103 // TODO: fix this since this is a quick hack to make some of [515]'s broken code run ;) [9/13/2006 Black]
104 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
105 extern cvar_t csqc_progcrc;
106 extern cvar_t csqc_progsize;
107 Cvar_RegisterVariable (&csqc_progname);
108 Cvar_RegisterVariable (&csqc_progcrc);
109 Cvar_RegisterVariable (&csqc_progsize);
111 Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
112 Cmd_AddCommand("sv_areastats", SV_AreaStats_f, "prints statistics on entity culling during collision traces");
113 Cmd_AddCommand_WithClientCommand("sv_startdownload", NULL, SV_StartDownload_f, "begins sending a file to the client (network protocol use only)");
114 Cmd_AddCommand_WithClientCommand("download", NULL, SV_Download_f, "downloads a specified file from the server");
115 Cvar_RegisterVariable (&sv_maxvelocity);
116 Cvar_RegisterVariable (&sv_gravity);
117 Cvar_RegisterVariable (&sv_friction);
118 Cvar_RegisterVariable (&sv_waterfriction);
119 Cvar_RegisterVariable (&sv_edgefriction);
120 Cvar_RegisterVariable (&sv_stopspeed);
121 Cvar_RegisterVariable (&sv_maxspeed);
122 Cvar_RegisterVariable (&sv_maxairspeed);
123 Cvar_RegisterVariable (&sv_accelerate);
124 Cvar_RegisterVariable (&sv_airaccelerate);
125 Cvar_RegisterVariable (&sv_wateraccelerate);
126 Cvar_RegisterVariable (&sv_clmovement_enable);
127 Cvar_RegisterVariable (&sv_clmovement_minping);
128 Cvar_RegisterVariable (&sv_clmovement_minping_disabletime);
129 Cvar_RegisterVariable (&sv_clmovement_waitforinput);
130 Cvar_RegisterVariable (&sv_idealpitchscale);
131 Cvar_RegisterVariable (&sv_aim);
132 Cvar_RegisterVariable (&sv_nostep);
133 Cvar_RegisterVariable (&sv_cullentities_pvs);
134 Cvar_RegisterVariable (&sv_cullentities_trace);
135 Cvar_RegisterVariable (&sv_cullentities_trace_samples);
136 Cvar_RegisterVariable (&sv_cullentities_trace_samples_extra);
137 Cvar_RegisterVariable (&sv_cullentities_trace_enlarge);
138 Cvar_RegisterVariable (&sv_cullentities_trace_delay);
139 Cvar_RegisterVariable (&sv_cullentities_trace_prediction);
140 Cvar_RegisterVariable (&sv_cullentities_nevercullbmodels);
141 Cvar_RegisterVariable (&sv_cullentities_stats);
142 Cvar_RegisterVariable (&sv_entpatch);
143 Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
144 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
145 Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
146 Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
147 Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
148 Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
149 Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
150 Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
151 Cvar_RegisterVariable (&sv_gameplayfix_qwplayerphysics);
152 Cvar_RegisterVariable (&sv_gameplayfix_upwardvelocityclearsongroundflag);
153 Cvar_RegisterVariable (&sv_gameplayfix_droptofloorstartsolid);
154 Cvar_RegisterVariable (&sv_protocolname);
155 Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
156 Cvar_RegisterVariable (&sv_maxrate);
157 Cvar_RegisterVariable (&sv_allowdownloads);
158 Cvar_RegisterVariable (&sv_allowdownloads_inarchive);
159 Cvar_RegisterVariable (&sv_allowdownloads_archive);
160 Cvar_RegisterVariable (&sv_allowdownloads_config);
161 Cvar_RegisterVariable (&sv_allowdownloads_dlcache);
162 Cvar_RegisterVariable (&sv_progs);
167 sv_mempool = Mem_AllocPool("server", 0, NULL);
170 static void SV_SaveEntFile_f(void)
172 char basename[MAX_QPATH];
173 if (!sv.active || !sv.worldmodel)
175 Con_Print("Not running a server\n");
178 FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
179 FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
184 =============================================================================
188 =============================================================================
195 Make sure the event gets sent to all clients
198 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
202 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
204 MSG_WriteByte (&sv.datagram, svc_particle);
205 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
206 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
207 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
208 for (i=0 ; i<3 ; i++)
209 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
210 MSG_WriteByte (&sv.datagram, count);
211 MSG_WriteByte (&sv.datagram, color);
212 SV_FlushBroadcastMessages();
219 Make sure the event gets sent to all clients
222 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
224 if (modelindex >= 256 || startframe >= 256)
226 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
228 MSG_WriteByte (&sv.datagram, svc_effect2);
229 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
230 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
231 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
232 MSG_WriteShort (&sv.datagram, modelindex);
233 MSG_WriteShort (&sv.datagram, startframe);
234 MSG_WriteByte (&sv.datagram, framecount);
235 MSG_WriteByte (&sv.datagram, framerate);
239 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
241 MSG_WriteByte (&sv.datagram, svc_effect);
242 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
243 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
244 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
245 MSG_WriteByte (&sv.datagram, modelindex);
246 MSG_WriteByte (&sv.datagram, startframe);
247 MSG_WriteByte (&sv.datagram, framecount);
248 MSG_WriteByte (&sv.datagram, framerate);
250 SV_FlushBroadcastMessages();
257 Each entity can have eight independant sound sources, like voice,
260 Channel 0 is an auto-allocate channel, the others override anything
261 already running on that entity/channel pair.
263 An attenuation of 0 will play full volume everywhere in the level.
264 Larger attenuations will drop off. (max 4 attenuation)
268 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
270 int sound_num, field_mask, i, ent;
272 if (volume < 0 || volume > 255)
274 Con_Printf ("SV_StartSound: volume = %i\n", volume);
278 if (attenuation < 0 || attenuation > 4)
280 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
284 if (channel < 0 || channel > 7)
286 Con_Printf ("SV_StartSound: channel = %i\n", channel);
290 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
293 // find precache number for sound
294 sound_num = SV_SoundIndex(sample, 1);
298 ent = PRVM_NUM_FOR_EDICT(entity);
301 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
302 field_mask |= SND_VOLUME;
303 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
304 field_mask |= SND_ATTENUATION;
306 field_mask |= SND_LARGEENTITY;
307 if (sound_num >= 256 || channel >= 8)
308 field_mask |= SND_LARGESOUND;
310 // directed messages go only to the entity they are targeted on
311 MSG_WriteByte (&sv.datagram, svc_sound);
312 MSG_WriteByte (&sv.datagram, field_mask);
313 if (field_mask & SND_VOLUME)
314 MSG_WriteByte (&sv.datagram, volume);
315 if (field_mask & SND_ATTENUATION)
316 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
317 if (field_mask & SND_LARGEENTITY)
319 MSG_WriteShort (&sv.datagram, ent);
320 MSG_WriteByte (&sv.datagram, channel);
323 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
324 if (field_mask & SND_LARGESOUND)
325 MSG_WriteShort (&sv.datagram, sound_num);
327 MSG_WriteByte (&sv.datagram, sound_num);
328 for (i = 0;i < 3;i++)
329 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
330 SV_FlushBroadcastMessages();
334 ==============================================================================
338 ==============================================================================
345 Sends the first message from the server to a connected client.
346 This will be sent on the initial connection and upon each server load.
349 void SV_SendServerinfo (client_t *client)
354 // we know that this client has a netconnection and thus is not a bot
356 // edicts get reallocated on level changes, so we need to update it here
357 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
359 // clear cached stuff that depends on the level
360 client->weaponmodel[0] = 0;
361 client->weaponmodelindex = 0;
363 // LordHavoc: clear entityframe tracking
364 client->latestframenum = 0;
366 if (client->entitydatabase)
367 EntityFrame_FreeDatabase(client->entitydatabase);
368 if (client->entitydatabase4)
369 EntityFrame4_FreeDatabase(client->entitydatabase4);
370 if (client->entitydatabase5)
371 EntityFrame5_FreeDatabase(client->entitydatabase5);
373 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
375 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
376 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
377 else if (sv.protocol == PROTOCOL_DARKPLACES4)
378 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
380 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
383 SZ_Clear (&client->netconnection->message);
384 MSG_WriteByte (&client->netconnection->message, svc_print);
385 dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
386 MSG_WriteString (&client->netconnection->message,message);
388 //[515]: init csprogs according to version of svprogs, check the crc, etc.
389 if (sv.csqc_progname[0])
392 Con_DPrintf("sending csqc info to client (\"%s\" with size %i and crc %i)\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
393 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
394 MSG_WriteString (&client->netconnection->message, va("csqc_progname %s\n", sv.csqc_progname));
395 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
396 MSG_WriteString (&client->netconnection->message, va("csqc_progsize %i\n", sv.csqc_progsize));
397 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
398 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", sv.csqc_progcrc));
399 //[515]: init stufftext string (it is sent before svc_serverinfo)
400 val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.SV_InitCmd);
403 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
404 MSG_WriteString (&client->netconnection->message, va("%s\n", PRVM_GetString(val->string)));
408 if (sv_allowdownloads.integer)
410 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
411 MSG_WriteString (&client->netconnection->message, "cl_serverextension_download 1");
414 // send at this time so it's guaranteed to get executed at the right time
418 host_client = client;
419 Curl_SendRequirements();
423 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
424 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
425 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
427 if (!coop.integer && deathmatch.integer)
428 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
430 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
432 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
434 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
435 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
436 MSG_WriteByte (&client->netconnection->message, 0);
438 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
439 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
440 MSG_WriteByte (&client->netconnection->message, 0);
443 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
444 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
445 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
448 MSG_WriteByte (&client->netconnection->message, svc_setview);
449 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
451 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
452 MSG_WriteByte (&client->netconnection->message, 1);
454 client->spawned = false; // need prespawn, spawn, etc
456 // clear movement info until client enters the new level properly
457 memset(&client->cmd, 0, sizeof(client->cmd));
458 client->movesequence = 0;
459 #ifdef NUM_PING_TIMES
460 for (i = 0;i < NUM_PING_TIMES;i++)
461 client->ping_times[i] = 0;
462 client->num_pings = 0;
471 Initializes a client_t for a new net connection. This will only be called
472 once for a player each game, not once for each level change.
475 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
479 float spawn_parms[NUM_SPAWN_PARMS];
481 client = svs.clients + clientnum;
483 if(netconnection)//[515]: bots don't play with csqc =)
484 EntityFrameCSQC_InitClientVersions(clientnum, false);
486 // set up the client_t
488 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
489 memset (client, 0, sizeof(*client));
490 client->active = true;
491 client->netconnection = netconnection;
493 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
495 strlcpy(client->name, "unconnected", sizeof(client->name));
496 strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
497 client->spawned = false;
498 client->edict = PRVM_EDICT_NUM(clientnum+1);
499 if (client->netconnection)
500 client->netconnection->message.allowoverflow = true; // we can catch it
501 // prepare the unreliable message buffer
502 client->unreliablemsg.data = client->unreliablemsg_data;
503 client->unreliablemsg.maxsize = sizeof(client->unreliablemsg_data);
504 // updated by receiving "rate" command from client
505 client->rate = NET_MINRATE;
506 // no limits for local player
507 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
508 client->rate = 1000000000;
509 client->connecttime = realtime;
512 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
515 // call the progs to get default spawn parms for the new client
516 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
517 prog->globals.server->self = 0;
518 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
519 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
520 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
522 // set up the entity for this client (including .colormap, .team, etc)
523 PRVM_ED_ClearEdict(client->edict);
526 // don't call SendServerinfo for a fresh botclient because its fields have
527 // not been set up by the qc yet
528 if (client->netconnection)
529 SV_SendServerinfo (client);
531 client->spawned = true;
536 ===============================================================================
540 ===============================================================================
544 =============================================================================
546 The PVS must include a small area around the client to allow head bobbing
547 or other small motion on the client side. Otherwise, a bob might cause an
548 entity that should be visible to not show up, especially when the bob
551 =============================================================================
554 int sv_writeentitiestoclient_pvsbytes;
555 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
557 static int numsendentities;
558 static entity_state_t sendentities[MAX_EDICTS];
559 static entity_state_t *sendentitiesindex[MAX_EDICTS];
561 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
564 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
565 unsigned int customizeentityforclient;
567 vec3_t cullmins, cullmaxs;
571 // EF_NODRAW prevents sending for any reason except for your own
572 // client, so we must keep all clients in this superset
573 effects = (unsigned)ent->fields.server->effects;
575 // we can omit invisible entities with no effects that are not clients
576 // LordHavoc: this could kill tags attached to an invisible entity, I
577 // just hope we never have to support that case
578 i = (int)ent->fields.server->modelindex;
579 modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
582 i = (int)(PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_size)->_float * 0.25f);
583 glowsize = (unsigned char)bound(0, i, 255);
584 if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_trail)->_float)
585 flags |= RENDER_GLOWTRAIL;
587 f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[0]*256;
588 light[0] = (unsigned short)bound(0, f, 65535);
589 f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[1]*256;
590 light[1] = (unsigned short)bound(0, f, 65535);
591 f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[2]*256;
592 light[2] = (unsigned short)bound(0, f, 65535);
593 f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.light_lev)->_float;
594 light[3] = (unsigned short)bound(0, f, 65535);
595 lightstyle = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.style)->_float;
596 lightpflags = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.pflags)->_float;
598 if (gamemode == GAME_TENEBRAE)
600 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
604 lightpflags |= PFLAGS_FULLDYNAMIC;
606 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
610 light[0] = (int)(0.2*256);
611 light[1] = (int)(1.0*256);
612 light[2] = (int)(0.2*256);
614 lightpflags |= PFLAGS_FULLDYNAMIC;
618 specialvisibilityradius = 0;
619 if (lightpflags & PFLAGS_FULLDYNAMIC)
620 specialvisibilityradius = max(specialvisibilityradius, light[3]);
622 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
623 if (flags & RENDER_GLOWTRAIL)
624 specialvisibilityradius = max(specialvisibilityradius, 100);
625 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
627 if (effects & EF_BRIGHTFIELD)
628 specialvisibilityradius = max(specialvisibilityradius, 80);
629 if (effects & EF_MUZZLEFLASH)
630 specialvisibilityradius = max(specialvisibilityradius, 100);
631 if (effects & EF_BRIGHTLIGHT)
632 specialvisibilityradius = max(specialvisibilityradius, 400);
633 if (effects & EF_DIMLIGHT)
634 specialvisibilityradius = max(specialvisibilityradius, 200);
635 if (effects & EF_RED)
636 specialvisibilityradius = max(specialvisibilityradius, 200);
637 if (effects & EF_BLUE)
638 specialvisibilityradius = max(specialvisibilityradius, 200);
639 if (effects & EF_FLAME)
640 specialvisibilityradius = max(specialvisibilityradius, 250);
641 if (effects & EF_STARDUST)
642 specialvisibilityradius = max(specialvisibilityradius, 100);
645 // early culling checks
646 // (final culling is done by SV_MarkWriteEntityStateToClient)
647 customizeentityforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.customizeentityforclient)->function;
648 if (!customizeentityforclient)
650 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
652 // this 2 billion unit check is actually to detect NAN origins
653 // (we really don't want to send those)
654 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
662 VectorCopy(ent->fields.server->origin, cs->origin);
663 VectorCopy(ent->fields.server->angles, cs->angles);
665 cs->effects = effects;
666 cs->colormap = (unsigned)ent->fields.server->colormap;
667 cs->modelindex = modelindex;
668 cs->skin = (unsigned)ent->fields.server->skin;
669 cs->frame = (unsigned)ent->fields.server->frame;
670 cs->viewmodelforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)->edict;
671 cs->exteriormodelforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.exteriormodeltoclient)->edict;
672 cs->nodrawtoclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.nodrawtoclient)->edict;
673 cs->drawonlytoclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.drawonlytoclient)->edict;
674 cs->customizeentityforclient = customizeentityforclient;
675 cs->tagentity = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)->edict;
676 cs->tagindex = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float;
677 cs->glowsize = glowsize;
679 // don't need to init cs->colormod because the defaultstate did that for us
680 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
681 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod);
682 if (val->vector[0] || val->vector[1] || val->vector[2])
684 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
685 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
686 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
689 cs->modelindex = modelindex;
692 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)->_float * 255.0f);
696 cs->alpha = (unsigned char)bound(0, i, 255);
699 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderamt)->_float);
703 cs->alpha = (unsigned char)bound(0, i, 255);
707 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)->_float * 16.0f);
711 cs->scale = (unsigned char)bound(0, i, 255);
715 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_color)->_float);
717 cs->glowcolor = (int)f;
719 if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.fullbright)->_float)
720 cs->effects |= EF_FULLBRIGHT;
722 if (ent->fields.server->movetype == MOVETYPE_STEP)
723 cs->flags |= RENDER_STEP;
724 if ((cs->effects & EF_LOWPRECISION) && cs->origin[0] >= -32768 && cs->origin[1] >= -32768 && cs->origin[2] >= -32768 && cs->origin[0] <= 32767 && cs->origin[1] <= 32767 && cs->origin[2] <= 32767)
725 cs->flags |= RENDER_LOWPRECISION;
726 if (ent->fields.server->colormap >= 1024)
727 cs->flags |= RENDER_COLORMAPPED;
728 if (cs->viewmodelforclient)
729 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
731 cs->light[0] = light[0];
732 cs->light[1] = light[1];
733 cs->light[2] = light[2];
734 cs->light[3] = light[3];
735 cs->lightstyle = lightstyle;
736 cs->lightpflags = lightpflags;
738 cs->specialvisibilityradius = specialvisibilityradius;
740 // calculate the visible box of this entity (don't use the physics box
741 // as that is often smaller than a model, and would not count
742 // specialvisibilityradius)
743 if ((model = sv.models[modelindex]))
745 float scale = cs->scale * (1.0f / 16.0f);
746 if (cs->angles[0] || cs->angles[2]) // pitch and roll
748 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
749 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
751 else if (cs->angles[1])
753 VectorMA(cs->origin, scale, model->yawmins, cullmins);
754 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
758 VectorMA(cs->origin, scale, model->normalmins, cullmins);
759 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
764 // if there is no model (or it could not be loaded), use the physics box
765 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
766 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
768 if (specialvisibilityradius)
770 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
771 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
772 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
773 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
774 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
775 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
777 // calculate center of bbox for network prioritization purposes
778 VectorMAM(0.5f, cullmins, 0.5f, cullmaxs, cs->netcenter);
779 // if culling box has moved, update pvs cluster links
780 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
782 VectorCopy(cullmins, ent->priv.server->cullmins);
783 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
784 // a value of -1 for pvs_numclusters indicates that the links are not
785 // cached, and should be re-tested each time, this is the case if the
786 // culling box touches too many pvs clusters to store, or if the world
787 // model does not support FindBoxClusters
788 ent->priv.server->pvs_numclusters = -1;
789 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
791 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
792 if (i <= MAX_ENTITYCLUSTERS)
793 ent->priv.server->pvs_numclusters = i;
800 void SV_PrepareEntitiesForSending(void)
804 // send all entities that touch the pvs
806 sendentitiesindex[0] = NULL;
807 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
808 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
810 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
812 sendentitiesindex[e] = sendentities + numsendentities;
818 static int sententitiesmark = 0;
819 static int sententities[MAX_EDICTS];
820 static int sententitiesconsideration[MAX_EDICTS];
821 static int sv_writeentitiestoclient_culled_pvs;
822 static int sv_writeentitiestoclient_culled_trace;
823 static int sv_writeentitiestoclient_visibleentities;
824 static int sv_writeentitiestoclient_totalentities;
825 //static entity_frame_t sv_writeentitiestoclient_entityframe;
826 static int sv_writeentitiestoclient_clentnum;
827 static vec3_t sv_writeentitiestoclient_testeye;
828 static client_t *sv_writeentitiestoclient_client;
830 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
835 if (sententitiesconsideration[s->number] == sententitiesmark)
837 sententitiesconsideration[s->number] = sententitiesmark;
838 sv_writeentitiestoclient_totalentities++;
840 if (s->customizeentityforclient)
842 prog->globals.server->self = s->number;
843 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
844 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
845 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
849 // never reject player
850 if (s->number != sv_writeentitiestoclient_clentnum)
852 // check various rejection conditions
853 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
855 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
857 if (s->effects & EF_NODRAW)
859 // LordHavoc: only send entities with a model or important effects
860 if (!s->modelindex && s->specialvisibilityradius == 0)
863 isbmodel = (model = sv.models[s->modelindex]) != NULL && model->name[0] == '*';
864 // viewmodels don't have visibility checking
865 if (s->viewmodelforclient)
867 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
870 else if (s->tagentity)
872 // tag attached entities simply check their parent
873 if (!sendentitiesindex[s->tagentity])
875 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
876 if (sententities[s->tagentity] != sententitiesmark)
879 // always send world submodels in newer protocols because they don't
880 // generate much traffic (in old protocols they hog bandwidth)
881 // but only if sv_cullentities_alwayssendbmodels is on
882 else if (!(s->effects & EF_NODEPTHTEST) && (!isbmodel || !sv_cullentities_nevercullbmodels.integer || sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE))
884 // entity has survived every check so far, check if visible
885 ed = PRVM_EDICT_NUM(s->number);
887 // if not touching a visible leaf
888 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
890 if (ed->priv.server->pvs_numclusters < 0)
892 // entity too big for clusters list
893 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
895 sv_writeentitiestoclient_culled_pvs++;
902 // check cached clusters list
903 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
904 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
906 if (i == ed->priv.server->pvs_numclusters)
908 sv_writeentitiestoclient_culled_pvs++;
914 // or not seen by random tracelines
915 if (sv_cullentities_trace.integer && !isbmodel)
917 int samples = s->specialvisibilityradius ? sv_cullentities_trace_samples_extra.integer : sv_cullentities_trace_samples.integer;
918 float enlarge = sv_cullentities_trace_enlarge.value;
920 qboolean visible = TRUE;
924 if(Mod_CanSeeBox_Trace(samples, enlarge, sv.worldmodel, sv_writeentitiestoclient_testeye, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
925 break; // directly visible from the server's view
927 if(sv_cullentities_trace_prediction.integer)
931 // get player velocity
932 float predtime = bound(0, host_client->ping, 0.2); // / 2
933 // sorry, no wallhacking by high ping please, and at 200ms
934 // ping a FPS is annoying to play anyway and a player is
935 // likely to have changed his direction
936 VectorMA(sv_writeentitiestoclient_testeye, predtime, host_client->edict->fields.server->velocity, predeye);
937 if(sv.worldmodel->brush.TraceLineOfSight(sv.worldmodel, sv_writeentitiestoclient_testeye, predeye)) // must be able to go there...
939 if(Mod_CanSeeBox_Trace(samples, enlarge, sv.worldmodel, predeye, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
940 break; // directly visible from the predicted view
944 //Con_DPrintf("Trying to walk into solid in a pingtime... not predicting for culling\n");
948 // when we get here, we can't see the entity
954 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + sv_cullentities_trace_delay.value;
956 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
958 sv_writeentitiestoclient_culled_trace++;
965 // this just marks it for sending
966 // FIXME: it would be more efficient to send here, but the entity
967 // compressor isn't that flexible
968 sv_writeentitiestoclient_visibleentities++;
969 sententities[s->number] = sententitiesmark;
972 entity_state_t sendstates[MAX_EDICTS];
973 extern int csqc_clientnum;
975 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg)
977 int i, numsendstates;
980 // if there isn't enough space to accomplish anything, skip it
981 if (msg->cursize + 25 > msg->maxsize)
984 sv_writeentitiestoclient_client = client;
986 sv_writeentitiestoclient_culled_pvs = 0;
987 sv_writeentitiestoclient_culled_trace = 0;
988 sv_writeentitiestoclient_visibleentities = 0;
989 sv_writeentitiestoclient_totalentities = 0;
991 // find the client's PVS
992 // the real place being tested from
993 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
994 sv_writeentitiestoclient_pvsbytes = 0;
995 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
996 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
998 sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
999 csqc_clientnum = sv_writeentitiestoclient_clentnum - 1;
1003 for (i = 0;i < numsendentities;i++)
1004 SV_MarkWriteEntityStateToClient(sendentities + i);
1007 for (i = 0;i < numsendentities;i++)
1009 if (sententities[sendentities[i].number] == sententitiesmark)
1011 s = &sendstates[numsendstates++];
1012 *s = sendentities[i];
1013 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
1014 s->flags |= RENDER_EXTERIORMODEL;
1018 if (sv_cullentities_stats.integer)
1019 Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d trace\n", client->name, sv_writeentitiestoclient_totalentities, sv_writeentitiestoclient_visibleentities, sv_writeentitiestoclient_culled_pvs + sv_writeentitiestoclient_culled_trace, sv_writeentitiestoclient_culled_pvs, sv_writeentitiestoclient_culled_trace);
1021 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
1023 if (client->entitydatabase5)
1024 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, client->movesequence);
1025 else if (client->entitydatabase4)
1027 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
1028 Protocol_WriteStatsReliable();
1030 else if (client->entitydatabase)
1032 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
1033 Protocol_WriteStatsReliable();
1037 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
1038 Protocol_WriteStatsReliable();
1048 void SV_CleanupEnts (void)
1053 ent = PRVM_NEXT_EDICT(prog->edicts);
1054 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
1055 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
1060 SV_WriteClientdataToMessage
1064 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1068 prvm_edict_t *other;
1076 // send a damage message
1078 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
1080 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
1081 MSG_WriteByte (msg, svc_damage);
1082 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
1083 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
1084 for (i=0 ; i<3 ; i++)
1085 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
1087 ent->fields.server->dmg_take = 0;
1088 ent->fields.server->dmg_save = 0;
1092 // send the current viewpos offset from the view entity
1094 SV_SetIdealPitch (); // how much to look up / down ideally
1096 // a fixangle might get lost in a dropped packet. Oh well.
1097 if(ent->fields.server->fixangle)
1099 // angle fixing was requested by global thinking code...
1100 // so store the current angles for later use
1101 memcpy(host_client->fixangle_angles, ent->fields.server->angles, sizeof(host_client->fixangle_angles));
1102 host_client->fixangle_angles_set = TRUE;
1104 // and clear fixangle for the next frame
1105 ent->fields.server->fixangle = 0;
1108 if (host_client->fixangle_angles_set)
1110 MSG_WriteByte (msg, svc_setangle);
1111 for (i=0 ; i < 3 ; i++)
1112 MSG_WriteAngle (msg, host_client->fixangle_angles[i], sv.protocol);
1113 host_client->fixangle_angles_set = FALSE;
1116 // stuff the sigil bits into the high bits of items for sbar, or else
1118 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.items2);
1119 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1120 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1122 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1124 VectorClear(punchvector);
1125 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.punchvector)))
1126 VectorCopy(val->vector, punchvector);
1128 // cache weapon model name and index in client struct to save time
1129 // (this search can be almost 1% of cpu time!)
1130 s = PRVM_GetString(ent->fields.server->weaponmodel);
1131 if (strcmp(s, client->weaponmodel))
1133 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1134 client->weaponmodelindex = SV_ModelIndex(s, 1);
1138 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewzoom)))
1139 viewzoom = (int)(val->_float * 255.0f);
1145 if ((int)ent->fields.server->flags & FL_ONGROUND)
1146 bits |= SU_ONGROUND;
1147 if (ent->fields.server->waterlevel >= 2)
1149 if (ent->fields.server->idealpitch)
1150 bits |= SU_IDEALPITCH;
1152 for (i=0 ; i<3 ; i++)
1154 if (ent->fields.server->punchangle[i])
1155 bits |= (SU_PUNCH1<<i);
1156 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1158 bits |= (SU_PUNCHVEC1<<i);
1159 if (ent->fields.server->velocity[i])
1160 bits |= (SU_VELOCITY1<<i);
1163 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1164 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1165 stats[STAT_ITEMS] = items;
1166 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1167 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1168 stats[STAT_WEAPON] = client->weaponmodelindex;
1169 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1170 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1171 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1172 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1173 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1174 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1175 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1176 stats[STAT_VIEWZOOM] = viewzoom;
1177 stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1178 stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1179 // the QC bumps these itself by sending svc_'s, so we have to keep them
1180 // zero or they'll be corrected by the engine
1181 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1182 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1184 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1186 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1188 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1189 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1191 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1192 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1193 if (viewzoom != 255)
1194 bits |= SU_VIEWZOOM;
1199 if (bits >= 16777216)
1203 MSG_WriteByte (msg, svc_clientdata);
1204 MSG_WriteShort (msg, bits);
1205 if (bits & SU_EXTEND1)
1206 MSG_WriteByte(msg, bits >> 16);
1207 if (bits & SU_EXTEND2)
1208 MSG_WriteByte(msg, bits >> 24);
1210 if (bits & SU_VIEWHEIGHT)
1211 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1213 if (bits & SU_IDEALPITCH)
1214 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1216 for (i=0 ; i<3 ; i++)
1218 if (bits & (SU_PUNCH1<<i))
1220 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1221 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1223 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1225 if (bits & (SU_PUNCHVEC1<<i))
1227 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1228 MSG_WriteCoord16i(msg, punchvector[i]);
1230 MSG_WriteCoord32f(msg, punchvector[i]);
1232 if (bits & (SU_VELOCITY1<<i))
1234 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1235 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1237 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1241 if (bits & SU_ITEMS)
1242 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1244 if (sv.protocol == PROTOCOL_DARKPLACES5)
1246 if (bits & SU_WEAPONFRAME)
1247 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1248 if (bits & SU_ARMOR)
1249 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1250 if (bits & SU_WEAPON)
1251 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1252 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1253 MSG_WriteShort (msg, stats[STAT_AMMO]);
1254 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1255 MSG_WriteShort (msg, stats[STAT_NAILS]);
1256 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1257 MSG_WriteShort (msg, stats[STAT_CELLS]);
1258 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1259 if (bits & SU_VIEWZOOM)
1260 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1262 else if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1264 if (bits & SU_WEAPONFRAME)
1265 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1266 if (bits & SU_ARMOR)
1267 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1268 if (bits & SU_WEAPON)
1269 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1270 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1271 MSG_WriteByte (msg, stats[STAT_AMMO]);
1272 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1273 MSG_WriteByte (msg, stats[STAT_NAILS]);
1274 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1275 MSG_WriteByte (msg, stats[STAT_CELLS]);
1276 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1278 for (i = 0;i < 32;i++)
1279 if (stats[STAT_WEAPON] & (1<<i))
1281 MSG_WriteByte (msg, i);
1284 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1285 if (bits & SU_VIEWZOOM)
1287 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1288 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1290 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1295 void SV_FlushBroadcastMessages(void)
1299 if (sv.datagram.cursize <= 0)
1301 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1303 if (!client->spawned || !client->netconnection || client->unreliablemsg.cursize + sv.datagram.cursize > client->unreliablemsg.maxsize || client->unreliablemsg_splitpoints >= (int)(sizeof(client->unreliablemsg_splitpoint)/sizeof(client->unreliablemsg_splitpoint[0])))
1305 SZ_Write(&client->unreliablemsg, sv.datagram.data, sv.datagram.cursize);
1306 client->unreliablemsg_splitpoint[client->unreliablemsg_splitpoints++] = client->unreliablemsg.cursize;
1308 SZ_Clear(&sv.datagram);
1311 void SV_WriteUnreliableMessages(client_t *client, sizebuf_t *msg)
1313 // scan the splitpoints to find out how many we can fit in
1314 int numsegments, j, split;
1315 for (numsegments = 0;numsegments < client->unreliablemsg_splitpoints;numsegments++)
1316 if (msg->cursize + client->unreliablemsg_splitpoint[numsegments] > msg->maxsize)
1318 if (numsegments > 0)
1320 // some will fit, so add the ones that will fit
1321 split = client->unreliablemsg_splitpoint[numsegments-1];
1322 SZ_Write(msg, client->unreliablemsg.data, split);
1323 // remove the part we sent, keeping any remaining data
1324 client->unreliablemsg.cursize -= split;
1325 if (client->unreliablemsg.cursize > 0)
1326 memmove(client->unreliablemsg.data, client->unreliablemsg.data + split, client->unreliablemsg.cursize);
1327 // adjust remaining splitpoints
1328 client->unreliablemsg_splitpoints -= numsegments;
1329 for (j = 0;j < client->unreliablemsg_splitpoints;j++)
1330 client->unreliablemsg_splitpoint[j] = client->unreliablemsg_splitpoint[numsegments + j] - split;
1335 =======================
1336 SV_SendClientDatagram
1337 =======================
1339 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1340 void SV_SendClientDatagram (client_t *client)
1342 int rate, maxrate, maxsize, maxsize2, downloadsize;
1344 int stats[MAX_CL_STATS];
1346 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1348 // for good singleplayer, send huge packets
1349 maxsize = sizeof(sv_sendclientdatagram_buf);
1350 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1352 else if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1354 // no rate limiting support on older protocols because dp protocols
1355 // 1-4 kick the client off if they overflow, and quake protocol shows
1356 // less than the full entity set if rate limited
1362 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1363 maxrate = max(NET_MINRATE, sv_maxrate.integer);
1364 if (sv_maxrate.integer != maxrate)
1365 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1367 // this rate limiting does not understand sys_ticrate 0
1368 // (but no one should be running that on a server!)
1369 rate = bound(NET_MINRATE, client->rate, maxrate);
1370 rate = (int)(rate * sys_ticrate.value);
1371 maxsize = bound(50, rate, 1400);
1375 // while downloading, limit entity updates to half the packet
1376 // (any leftover space will be used for downloading)
1377 if (host_client->download_file)
1380 msg.data = sv_sendclientdatagram_buf;
1381 msg.maxsize = maxsize;
1384 if (host_client->spawned)
1386 MSG_WriteByte (&msg, svc_time);
1387 MSG_WriteFloat (&msg, sv.time);
1389 // add the client specific data to the datagram
1390 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1391 // now update the stats[] array using any registered custom fields
1392 VM_SV_UpdateCustomStats (client, client->edict, &msg, stats);
1393 // set host_client->statsdeltabits
1394 Protocol_UpdateClientStats (stats);
1396 // add as many queued unreliable messages (effects) as we can fit
1397 // limit effects to half of the remaining space
1398 msg.maxsize -= (msg.maxsize - msg.cursize) / 2;
1399 if (client->unreliablemsg.cursize)
1400 SV_WriteUnreliableMessages (client, &msg);
1402 msg.maxsize = maxsize;
1404 // now write as many entities as we can fit, and also sends stats
1405 SV_WriteEntitiesToClient (client, client->edict, &msg);
1407 else if (realtime > client->keepalivetime)
1409 // the player isn't totally in the game yet
1410 // send small keepalive messages if too much time has passed
1411 msg.maxsize = maxsize2;
1412 client->keepalivetime = realtime + 5;
1413 MSG_WriteChar (&msg, svc_nop);
1416 msg.maxsize = maxsize2;
1418 // if a download is active, see if there is room to fit some download data
1420 downloadsize = maxsize * 2 - msg.cursize - 7;
1421 if (host_client->download_file && host_client->download_started && downloadsize > 0)
1423 fs_offset_t downloadstart;
1424 unsigned char data[1400];
1425 downloadstart = FS_Tell(host_client->download_file);
1426 downloadsize = min(downloadsize, (int)sizeof(data));
1427 downloadsize = FS_Read(host_client->download_file, data, downloadsize);
1428 // note this sends empty messages if at the end of the file, which is
1429 // necessary to keep the packet loss logic working
1430 // (the last blocks may be lost and need to be re-sent, and that will
1431 // only occur if the client acks the empty end messages, revealing
1432 // a gap in the download progress, causing the last blocks to be
1434 MSG_WriteChar (&msg, svc_downloaddata);
1435 MSG_WriteLong (&msg, downloadstart);
1436 MSG_WriteShort (&msg, downloadsize);
1437 if (downloadsize > 0)
1438 SZ_Write (&msg, data, downloadsize);
1441 // send the datagram
1442 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1446 =======================
1447 SV_UpdateToReliableMessages
1448 =======================
1450 void SV_UpdateToReliableMessages (void)
1459 // check for changes to be sent over the reliable streams
1460 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1462 // update the host_client fields we care about according to the entity fields
1463 host_client->edict = PRVM_EDICT_NUM(i+1);
1466 name = PRVM_GetString(host_client->edict->fields.server->netname);
1469 // always point the string back at host_client->name to keep it safe
1470 strlcpy (host_client->name, name, sizeof (host_client->name));
1471 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1472 if (strcmp(host_client->old_name, host_client->name))
1474 if (host_client->spawned)
1475 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1476 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1477 // send notification to all clients
1478 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1479 MSG_WriteByte (&sv.reliable_datagram, i);
1480 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1483 // DP_SV_CLIENTCOLORS
1484 // this is always found (since it's added by the progs loader)
1485 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
1486 host_client->colors = (int)val->_float;
1487 if (host_client->old_colors != host_client->colors)
1489 host_client->old_colors = host_client->colors;
1490 // send notification to all clients
1491 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1492 MSG_WriteByte (&sv.reliable_datagram, i);
1493 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1496 // NEXUIZ_PLAYERMODEL
1497 if( prog->fieldoffsets.playermodel >= 0 ) {
1498 model = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string);
1501 // always point the string back at host_client->name to keep it safe
1502 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1503 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1506 // NEXUIZ_PLAYERSKIN
1507 if( prog->fieldoffsets.playerskin >= 0 ) {
1508 skin = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string);
1511 // always point the string back at host_client->name to keep it safe
1512 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1513 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1517 host_client->frags = (int)host_client->edict->fields.server->frags;
1518 if (host_client->old_frags != host_client->frags)
1520 host_client->old_frags = host_client->frags;
1521 // send notification to all clients
1522 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1523 MSG_WriteByte (&sv.reliable_datagram, i);
1524 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1528 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1529 if (client->netconnection)
1530 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1532 SZ_Clear (&sv.reliable_datagram);
1537 =======================
1538 SV_SendClientMessages
1539 =======================
1541 void SV_SendClientMessages (void)
1543 int i, prepared = false;
1545 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1546 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1548 SV_FlushBroadcastMessages();
1550 // update frags, names, etc
1551 SV_UpdateToReliableMessages();
1553 // build individual updates
1554 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1556 if (!host_client->active)
1558 if (!host_client->netconnection)
1561 if (host_client->netconnection->message.overflowed)
1563 SV_DropClient (true); // if the message couldn't send, kick off
1570 // only prepare entities once per frame
1571 SV_PrepareEntitiesForSending();
1573 SV_SendClientDatagram (host_client);
1576 // clear muzzle flashes
1580 void SV_StartDownload_f(void)
1582 if (host_client->download_file)
1583 host_client->download_started = true;
1586 void SV_Download_f(void)
1588 const char *whichpack, *whichpack2, *extension;
1590 if (Cmd_Argc() != 2)
1592 SV_ClientPrintf("usage: download <filename>\n");
1596 if (FS_CheckNastyPath(Cmd_Argv(1), false))
1598 SV_ClientPrintf("Download rejected: nasty filename \"%s\"\n", Cmd_Argv(1));
1602 if (host_client->download_file)
1604 // at this point we'll assume the previous download should be aborted
1605 Con_DPrintf("Download of %s aborted by %s starting a new download\n", host_client->download_name, host_client->name);
1606 Host_ClientCommands("\nstopdownload\n");
1608 // close the file and reset variables
1609 FS_Close(host_client->download_file);
1610 host_client->download_file = NULL;
1611 host_client->download_name[0] = 0;
1612 host_client->download_expectedposition = 0;
1613 host_client->download_started = false;
1616 if (!sv_allowdownloads.integer)
1618 SV_ClientPrintf("Downloads are disabled on this server\n");
1619 Host_ClientCommands("\nstopdownload\n");
1623 strlcpy(host_client->download_name, Cmd_Argv(1), sizeof(host_client->download_name));
1624 extension = FS_FileExtension(host_client->download_name);
1626 // host_client is asking to download a specified file
1627 if (developer.integer >= 100)
1628 Con_Printf("Download request for %s by %s\n", host_client->download_name, host_client->name);
1630 if (!FS_FileExists(host_client->download_name))
1632 SV_ClientPrintf("Download rejected: server does not have the file \"%s\"\nYou may need to separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name);
1633 Host_ClientCommands("\nstopdownload\n");
1637 // check if the user is trying to download part of registered Quake(r)
1638 whichpack = FS_WhichPack(host_client->download_name);
1639 whichpack2 = FS_WhichPack("gfx/pop.lmp");
1640 if ((whichpack && whichpack2 && !strcasecmp(whichpack, whichpack2)) || FS_IsRegisteredQuakePack(host_client->download_name))
1642 SV_ClientPrintf("Download rejected: file \"%s\" is part of registered Quake(r)\nYou must purchase Quake(r) from id Software or a retailer to get this file\nPlease go to http://www.idsoftware.com/games/quake/quake/index.php?game_section=buy\n", host_client->download_name);
1643 Host_ClientCommands("\nstopdownload\n");
1647 // check if the server has forbidden archive downloads entirely
1648 if (!sv_allowdownloads_inarchive.integer)
1650 whichpack = FS_WhichPack(host_client->download_name);
1653 SV_ClientPrintf("Download rejected: file \"%s\" is in an archive (\"%s\")\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name, whichpack);
1654 Host_ClientCommands("\nstopdownload\n");
1659 if (!sv_allowdownloads_config.integer)
1661 if (!strcasecmp(extension, "cfg"))
1663 SV_ClientPrintf("Download rejected: file \"%s\" is a .cfg file which is forbidden for security reasons\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name);
1664 Host_ClientCommands("\nstopdownload\n");
1669 if (!sv_allowdownloads_dlcache.integer)
1671 if (!strncasecmp(host_client->download_name, "dlcache/", 8))
1673 SV_ClientPrintf("Download rejected: file \"%s\" is in the dlcache/ directory which is forbidden for security reasons\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name);
1674 Host_ClientCommands("\nstopdownload\n");
1679 if (!sv_allowdownloads_archive.integer)
1681 if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
1683 SV_ClientPrintf("Download rejected: file \"%s\" is an archive\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name);
1684 Host_ClientCommands("\nstopdownload\n");
1689 host_client->download_file = FS_Open(host_client->download_name, "rb", true, false);
1690 if (!host_client->download_file)
1692 SV_ClientPrintf("Download rejected: server could not open the file \"%s\"\n", host_client->download_name);
1693 Host_ClientCommands("\nstopdownload\n");
1697 if (FS_FileSize(host_client->download_file) > 1<<30)
1699 SV_ClientPrintf("Download rejected: file \"%s\" is very large\n", host_client->download_name);
1700 Host_ClientCommands("\nstopdownload\n");
1701 FS_Close(host_client->download_file);
1702 host_client->download_file = NULL;
1706 Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
1708 Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name);
1710 host_client->download_expectedposition = 0;
1711 host_client->download_started = false;
1713 // the rest of the download process is handled in SV_SendClientDatagram
1714 // and other code dealing with svc_downloaddata and clc_ackdownloaddata
1716 // no svc_downloaddata messages will be sent until sv_startdownload is
1717 // sent by the client
1721 ==============================================================================
1725 ==============================================================================
1734 int SV_ModelIndex(const char *s, int precachemode)
1736 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1737 char filename[MAX_QPATH];
1741 //if (precachemode == 2)
1743 strlcpy(filename, s, sizeof(filename));
1744 for (i = 2;i < limit;i++)
1746 if (!sv.model_precache[i][0])
1750 if (sv.state != ss_loading && (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5))
1752 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1755 if (precachemode == 1)
1756 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1757 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1758 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1759 if (sv.state != ss_loading)
1761 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1762 MSG_WriteShort(&sv.reliable_datagram, i);
1763 MSG_WriteString(&sv.reliable_datagram, filename);
1767 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1770 if (!strcmp(sv.model_precache[i], filename))
1773 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1783 int SV_SoundIndex(const char *s, int precachemode)
1785 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1786 char filename[MAX_QPATH];
1790 //if (precachemode == 2)
1792 strlcpy(filename, s, sizeof(filename));
1793 for (i = 1;i < limit;i++)
1795 if (!sv.sound_precache[i][0])
1799 if (sv.state != ss_loading && (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5))
1801 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1804 if (precachemode == 1)
1805 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1806 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1807 if (sv.state != ss_loading)
1809 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1810 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1811 MSG_WriteString(&sv.reliable_datagram, filename);
1815 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1818 if (!strcmp(sv.sound_precache[i], filename))
1821 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1825 // MUST match effectnameindex_t in client.h
1826 static const char *standardeffectnames[EFFECT_TOTAL] =
1834 "TE_SUPERSPIKEQUAD",
1850 "TE_TEI_BIGEXPLOSION",
1868 SV_ParticleEffectIndex
1872 int SV_ParticleEffectIndex(const char *name)
1874 int i, argc, linenumber, effectnameindex;
1875 fs_offset_t filesize;
1876 unsigned char *filedata;
1877 const char *text, *textstart, *textend;
1878 char argv[16][1024];
1879 if (!sv.particleeffectnamesloaded)
1881 sv.particleeffectnamesloaded = true;
1882 memset(sv.particleeffectname, 0, sizeof(sv.particleeffectname));
1883 for (i = 0;i < EFFECT_TOTAL;i++)
1884 strlcpy(sv.particleeffectname[i], standardeffectnames[i], sizeof(sv.particleeffectname[i]));
1885 filedata = FS_LoadFile("effectinfo.txt", tempmempool, true, &filesize);
1888 textstart = (const char *)filedata;
1889 textend = (const char *)filedata + filesize;
1891 for (linenumber = 1;;linenumber++)
1896 if (!COM_ParseToken(&text, true) || !strcmp(com_token, "\n"))
1900 strlcpy(argv[argc], com_token, sizeof(argv[argc]));
1904 if (com_token[0] == 0)
1905 break; // if the loop exited and it's not a \n, it's EOF
1908 if (!strcmp(argv[0], "effect"))
1912 for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME;effectnameindex++)
1914 if (sv.particleeffectname[effectnameindex][0])
1916 if (!strcmp(sv.particleeffectname[effectnameindex], argv[1]))
1921 strlcpy(sv.particleeffectname[effectnameindex], argv[1], sizeof(sv.particleeffectname[effectnameindex]));
1925 // if we run out of names, abort
1926 if (effectnameindex == SV_MAX_PARTICLEEFFECTNAME)
1928 Con_Printf("effectinfo.txt:%i: too many effects!\n", linenumber);
1937 // search for the name
1938 for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME && sv.particleeffectname[effectnameindex][0];effectnameindex++)
1939 if (!strcmp(sv.particleeffectname[effectnameindex], name))
1940 return effectnameindex;
1941 // return 0 if we couldn't find it
1951 void SV_CreateBaseline (void)
1953 int i, entnum, large;
1954 prvm_edict_t *svent;
1956 // LordHavoc: clear *all* states (note just active ones)
1957 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1959 // get the current server version
1960 svent = PRVM_EDICT_NUM(entnum);
1962 // LordHavoc: always clear state values, whether the entity is in use or not
1963 svent->priv.server->baseline = defaultstate;
1965 if (svent->priv.server->free)
1967 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1970 // create entity baseline
1971 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1972 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1973 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1974 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1975 if (entnum > 0 && entnum <= svs.maxclients)
1977 svent->priv.server->baseline.colormap = entnum;
1978 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1982 svent->priv.server->baseline.colormap = 0;
1983 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1987 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1990 // add to the message
1992 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1994 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1995 MSG_WriteShort (&sv.signon, entnum);
1999 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
2000 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
2004 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
2005 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
2007 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
2008 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
2009 for (i=0 ; i<3 ; i++)
2011 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
2012 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
2022 Grabs the current state of each client for saving across the
2023 transition to another level
2026 void SV_SaveSpawnparms (void)
2030 svs.serverflags = (int)prog->globals.server->serverflags;
2032 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2034 if (!host_client->active)
2037 // call the progs to get default spawn parms for the new client
2038 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2039 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
2040 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
2041 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
2045 void SV_IncreaseEdicts(void)
2049 int oldmax_edicts = prog->max_edicts;
2050 void *oldedictsengineprivate = prog->edictprivate;
2051 void *oldedictsfields = prog->edictsfields;
2052 void *oldmoved_edicts = sv.moved_edicts;
2054 if (prog->max_edicts >= MAX_EDICTS)
2057 // links don't survive the transition, so unlink everything
2058 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2060 if (!ent->priv.server->free)
2061 SV_UnlinkEdict(prog->edicts + i);
2062 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
2064 World_Clear(&sv.world);
2066 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
2067 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
2068 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
2069 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2071 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
2072 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
2074 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2076 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
2077 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
2078 // link every entity except world
2079 if (!ent->priv.server->free)
2080 SV_LinkEdict(ent, false);
2083 PR_Free(oldedictsengineprivate);
2084 PR_Free(oldedictsfields);
2085 PR_Free(oldmoved_edicts);
2092 This is called at the start of each level
2095 extern float scr_centertime_off;
2097 void SV_SpawnServer (const char *server)
2102 model_t *worldmodel;
2103 char modelname[sizeof(sv.modelname)];
2105 Con_DPrintf("SpawnServer: %s\n", server);
2107 if (cls.state != ca_dedicated)
2108 SCR_BeginLoadingPlaque();
2110 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
2111 worldmodel = Mod_ForName(modelname, false, true, true);
2112 if (!worldmodel || !worldmodel->TraceBox)
2114 Con_Printf("Couldn't load map %s\n", modelname);
2118 // let's not have any servers with no name
2119 if (hostname.string[0] == 0)
2120 Cvar_Set ("hostname", "UNNAMED");
2121 scr_centertime_off = 0;
2123 svs.changelevel_issued = false; // now safe to issue another
2125 // make the map a required file for clients
2126 Curl_ClearRequirements();
2127 Curl_RequireFile(modelname);
2130 // tell all connected clients that we are going to a new level
2135 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
2137 if (client->netconnection)
2139 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
2140 MSG_WriteString(&client->netconnection->message, "reconnect\n");
2147 NetConn_OpenServerPorts(true);
2151 // make cvars consistant
2154 Cvar_SetValue ("deathmatch", 0);
2155 // LordHavoc: it can be useful to have skills outside the range 0-3...
2156 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
2157 //Cvar_SetValue ("skill", (float)current_skill);
2158 current_skill = (int)(skill.value + 0.5);
2161 // set up the new server
2163 memset (&sv, 0, sizeof(sv));
2164 // if running a local client, make sure it doesn't try to access the last
2165 // level's data which is no longer valiud
2168 if(*sv_random_seed.string)
2170 srand(sv_random_seed.integer);
2171 Con_Printf("NOTE: random seed is %d; use for debugging/benchmarking only!\nUnset sv_random_seed to get real random numbers again.\n", sv_random_seed.integer);
2178 strlcpy (sv.name, server, sizeof (sv.name));
2180 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
2181 if (sv.protocol == PROTOCOL_UNKNOWN)
2184 Protocol_Names(buffer, sizeof(buffer));
2185 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
2186 sv.protocol = PROTOCOL_QUAKE;
2191 // load progs to get entity field count
2192 //PR_LoadProgs ( sv_progs.string );
2194 // allocate server memory
2195 /*// start out with just enough room for clients and a reasonable estimate of entities
2196 prog->max_edicts = max(svs.maxclients + 1, 512);
2197 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
2199 // prvm_edict_t structures (hidden from progs)
2200 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
2201 // engine private structures (hidden from progs)
2202 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
2203 // progs fields, often accessed by server
2204 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
2205 // used by PushMove to move back pushed entities
2206 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2207 /*for (i = 0;i < prog->max_edicts;i++)
2209 ent = prog->edicts + i;
2210 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
2211 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
2214 // reset client csqc entity versions right away.
2215 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2216 EntityFrameCSQC_InitClientVersions(i, true);
2218 sv.datagram.maxsize = sizeof(sv.datagram_buf);
2219 sv.datagram.cursize = 0;
2220 sv.datagram.data = sv.datagram_buf;
2222 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
2223 sv.reliable_datagram.cursize = 0;
2224 sv.reliable_datagram.data = sv.reliable_datagram_buf;
2226 sv.signon.maxsize = sizeof(sv.signon_buf);
2227 sv.signon.cursize = 0;
2228 sv.signon.data = sv.signon_buf;
2230 // leave slots at start for clients only
2231 //prog->num_edicts = svs.maxclients+1;
2233 sv.state = ss_loading;
2234 prog->allowworldwrites = true;
2237 prog->globals.server->time = sv.time = 1.0;
2240 worldmodel->used = true;
2242 strlcpy (sv.name, server, sizeof (sv.name));
2243 strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
2244 sv.worldmodel = worldmodel;
2245 sv.models[1] = sv.worldmodel;
2248 // clear world interaction links
2250 VectorCopy(sv.worldmodel->normalmins, sv.world.areagrid_mins);
2251 VectorCopy(sv.worldmodel->normalmaxs, sv.world.areagrid_maxs);
2252 World_Clear(&sv.world);
2254 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
2256 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
2257 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
2258 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
2260 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
2261 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
2265 // load the rest of the entities
2267 // AK possible hack since num_edicts is still 0
2268 ent = PRVM_EDICT_NUM(0);
2269 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
2270 ent->priv.server->free = false;
2271 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
2272 ent->fields.server->modelindex = 1; // world model
2273 ent->fields.server->solid = SOLID_BSP;
2274 ent->fields.server->movetype = MOVETYPE_PUSH;
2275 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->mins);
2276 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->maxs);
2277 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->absmin);
2278 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->absmax);
2281 prog->globals.server->coop = coop.integer;
2283 prog->globals.server->deathmatch = deathmatch.integer;
2285 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
2287 // serverflags are for cross level information (sigils)
2288 prog->globals.server->serverflags = svs.serverflags;
2290 // we need to reset the spawned flag on all connected clients here so that
2291 // their thinks don't run during startup (before PutClientInServer)
2292 // we also need to set up the client entities now
2293 // and we need to set the ->edict pointers to point into the progs edicts
2294 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2296 host_client->spawned = false;
2297 host_client->edict = PRVM_EDICT_NUM(i + 1);
2298 PRVM_ED_ClearEdict(host_client->edict);
2301 // load replacement entity file if found
2302 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
2304 Con_Printf("Loaded maps/%s.ent\n", sv.name);
2305 PRVM_ED_LoadFromFile (entities);
2309 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
2312 // LordHavoc: clear world angles (to fix e3m3.bsp)
2313 VectorClear(prog->edicts->fields.server->angles);
2315 // all setup is completed, any further precache statements are errors
2316 sv.state = ss_active;
2317 prog->allowworldwrites = false;
2319 // run two frames to allow everything to settle
2320 for (i = 0;i < 2;i++)
2328 // create a baseline for more efficient communications
2329 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
2330 SV_CreateBaseline ();
2332 // send serverinfo to all connected clients, and set up botclients coming back from a level change
2333 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2335 if (!host_client->active)
2337 if (host_client->netconnection)
2338 SV_SendServerinfo(host_client);
2342 // if client is a botclient coming from a level change, we need to
2343 // set up client info that normally requires networking
2345 // copy spawn parms out of the client_t
2346 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
2347 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
2349 // call the spawn function
2350 host_client->clientconnectcalled = true;
2351 prog->globals.server->time = sv.time;
2352 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2353 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
2354 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
2355 host_client->spawned = true;
2359 Con_DPrint("Server spawned.\n");
2360 NetConn_Heartbeat (2);
2365 /////////////////////////////////////////////////////
2368 void SV_VM_CB_BeginIncreaseEdicts(void)
2373 PRVM_Free( sv.moved_edicts );
2374 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2376 // links don't survive the transition, so unlink everything
2377 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2379 if (!ent->priv.server->free)
2380 World_UnlinkEdict(prog->edicts + i);
2381 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
2383 World_Clear(&sv.world);
2386 void SV_VM_CB_EndIncreaseEdicts(void)
2391 // link every entity except world
2392 for (i = 1, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2393 if (!ent->priv.server->free)
2394 SV_LinkEdict(ent, false);
2397 void SV_VM_CB_InitEdict(prvm_edict_t *e)
2399 // LordHavoc: for consistency set these here
2400 int num = PRVM_NUM_FOR_EDICT(e) - 1;
2402 e->priv.server->move = false; // don't move on first frame
2404 if (num >= 0 && num < svs.maxclients)
2407 // set colormap and team on newly created player entity
2408 e->fields.server->colormap = num + 1;
2409 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
2410 // set netname/clientcolors back to client values so that
2411 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
2413 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
2414 if ((val = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.clientcolors)))
2415 val->_float = svs.clients[num].colors;
2416 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
2417 if( prog->fieldoffsets.playermodel >= 0 )
2418 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
2419 if( prog->fieldoffsets.playerskin >= 0 )
2420 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
2424 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
2426 World_UnlinkEdict(ed); // unlink from world bsp
2428 ed->fields.server->model = 0;
2429 ed->fields.server->takedamage = 0;
2430 ed->fields.server->modelindex = 0;
2431 ed->fields.server->colormap = 0;
2432 ed->fields.server->skin = 0;
2433 ed->fields.server->frame = 0;
2434 VectorClear(ed->fields.server->origin);
2435 VectorClear(ed->fields.server->angles);
2436 ed->fields.server->nextthink = -1;
2437 ed->fields.server->solid = 0;
2440 void SV_VM_CB_CountEdicts(void)
2444 int active, models, solid, step;
2446 active = models = solid = step = 0;
2447 for (i=0 ; i<prog->num_edicts ; i++)
2449 ent = PRVM_EDICT_NUM(i);
2450 if (ent->priv.server->free)
2453 if (ent->fields.server->solid)
2455 if (ent->fields.server->model)
2457 if (ent->fields.server->movetype == MOVETYPE_STEP)
2461 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2462 Con_Printf("active :%3i\n", active);
2463 Con_Printf("view :%3i\n", models);
2464 Con_Printf("touch :%3i\n", solid);
2465 Con_Printf("step :%3i\n", step);
2468 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2470 // remove things from different skill levels or deathmatch
2471 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2473 if (deathmatch.integer)
2475 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2480 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2481 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2482 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2490 cvar_t pr_checkextension = {CVAR_READONLY, "pr_checkextension", "1", "indicates to QuakeC that the standard quakec extensions system is available (if 0, quakec should not attempt to use extensions)"};
2491 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2492 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2493 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2494 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2495 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2496 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2497 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2498 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2499 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2500 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2501 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2502 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2503 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2504 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2505 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2506 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2507 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2508 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2509 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2510 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2511 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2512 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2513 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2514 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2515 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2516 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2517 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2518 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2519 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2520 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2521 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2522 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2524 void SV_VM_Init(void)
2526 Cvar_RegisterVariable (&pr_checkextension);
2527 Cvar_RegisterVariable (&nomonsters);
2528 Cvar_RegisterVariable (&gamecfg);
2529 Cvar_RegisterVariable (&scratch1);
2530 Cvar_RegisterVariable (&scratch2);
2531 Cvar_RegisterVariable (&scratch3);
2532 Cvar_RegisterVariable (&scratch4);
2533 Cvar_RegisterVariable (&savedgamecfg);
2534 Cvar_RegisterVariable (&saved1);
2535 Cvar_RegisterVariable (&saved2);
2536 Cvar_RegisterVariable (&saved3);
2537 Cvar_RegisterVariable (&saved4);
2538 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2539 if (gamemode == GAME_NEHAHRA)
2541 Cvar_RegisterVariable (&nehx00);
2542 Cvar_RegisterVariable (&nehx01);
2543 Cvar_RegisterVariable (&nehx02);
2544 Cvar_RegisterVariable (&nehx03);
2545 Cvar_RegisterVariable (&nehx04);
2546 Cvar_RegisterVariable (&nehx05);
2547 Cvar_RegisterVariable (&nehx06);
2548 Cvar_RegisterVariable (&nehx07);
2549 Cvar_RegisterVariable (&nehx08);
2550 Cvar_RegisterVariable (&nehx09);
2551 Cvar_RegisterVariable (&nehx10);
2552 Cvar_RegisterVariable (&nehx11);
2553 Cvar_RegisterVariable (&nehx12);
2554 Cvar_RegisterVariable (&nehx13);
2555 Cvar_RegisterVariable (&nehx14);
2556 Cvar_RegisterVariable (&nehx15);
2557 Cvar_RegisterVariable (&nehx16);
2558 Cvar_RegisterVariable (&nehx17);
2559 Cvar_RegisterVariable (&nehx18);
2560 Cvar_RegisterVariable (&nehx19);
2562 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2565 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2567 prvm_required_field_t reqfields[] =
2569 {ev_entity, "cursor_trace_ent"},
2570 {ev_entity, "drawonlytoclient"},
2571 {ev_entity, "exteriormodeltoclient"},
2572 {ev_entity, "nodrawtoclient"},
2573 {ev_entity, "tag_entity"},
2574 {ev_entity, "viewmodelforclient"},
2575 {ev_float, "alpha"},
2576 {ev_float, "ammo_cells1"},
2577 {ev_float, "ammo_lava_nails"},
2578 {ev_float, "ammo_multi_rockets"},
2579 {ev_float, "ammo_nails1"},
2580 {ev_float, "ammo_plasma"},
2581 {ev_float, "ammo_rockets1"},
2582 {ev_float, "ammo_shells1"},
2583 {ev_float, "button3"},
2584 {ev_float, "button4"},
2585 {ev_float, "button5"},
2586 {ev_float, "button6"},
2587 {ev_float, "button7"},
2588 {ev_float, "button8"},
2589 {ev_float, "button9"},
2590 {ev_float, "button10"},
2591 {ev_float, "button11"},
2592 {ev_float, "button12"},
2593 {ev_float, "button13"},
2594 {ev_float, "button14"},
2595 {ev_float, "button15"},
2596 {ev_float, "button16"},
2597 {ev_float, "buttonchat"},
2598 {ev_float, "buttonuse"},
2599 {ev_float, "clientcolors"},
2600 {ev_float, "cursor_active"},
2601 {ev_float, "disableclientprediction"},
2602 {ev_float, "fullbright"},
2603 {ev_float, "glow_color"},
2604 {ev_float, "glow_size"},
2605 {ev_float, "glow_trail"},
2606 {ev_float, "gravity"},
2607 {ev_float, "idealpitch"},
2608 {ev_float, "items2"},
2609 {ev_float, "light_lev"},
2610 {ev_float, "pflags"},
2612 {ev_float, "pitch_speed"},
2613 {ev_float, "pmodel"},
2614 {ev_float, "renderamt"}, // HalfLife support
2615 {ev_float, "rendermode"}, // HalfLife support
2616 {ev_float, "scale"},
2617 {ev_float, "style"},
2618 {ev_float, "tag_index"},
2619 {ev_float, "Version"},
2620 {ev_float, "viewzoom"},
2621 {ev_vector, "color"},
2622 {ev_vector, "colormod"},
2623 {ev_vector, "cursor_screen"},
2624 {ev_vector, "cursor_trace_endpos"},
2625 {ev_vector, "cursor_trace_start"},
2626 {ev_vector, "movement"},
2627 {ev_vector, "punchvector"},
2628 {ev_string, "playermodel"},
2629 {ev_string, "playerskin"},
2630 {ev_function, "SendEntity"},
2631 {ev_function, "customizeentityforclient"},
2632 // DRESK - Support for Entity Contents Transition Event
2633 {ev_function, "contentstransition"},
2636 void SV_VM_Setup(void)
2638 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
2639 extern cvar_t csqc_progcrc;
2640 extern cvar_t csqc_progsize;
2641 size_t csprogsdatasize;
2643 PRVM_InitProg( PRVM_SERVERPROG );
2645 // allocate the mempools
2646 // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
2647 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2648 prog->builtins = vm_sv_builtins;
2649 prog->numbuiltins = vm_sv_numbuiltins;
2650 prog->headercrc = PROGHEADER_CRC;
2651 prog->max_edicts = 512;
2652 prog->limit_edicts = MAX_EDICTS;
2653 prog->reserved_edicts = svs.maxclients;
2654 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2655 prog->name = "server";
2656 prog->extensionstring = vm_sv_extensions;
2657 prog->loadintoworld = true;
2659 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2660 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2661 prog->init_edict = SV_VM_CB_InitEdict;
2662 prog->free_edict = SV_VM_CB_FreeEdict;
2663 prog->count_edicts = SV_VM_CB_CountEdicts;
2664 prog->load_edict = SV_VM_CB_LoadEdict;
2665 prog->init_cmd = VM_SV_Cmd_Init;
2666 prog->reset_cmd = VM_SV_Cmd_Reset;
2667 prog->error_cmd = Host_Error;
2669 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2670 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields, 0, NULL );
2672 // some mods compiled with scrambling compilers lack certain critical
2673 // global names and field names such as "self" and "time" and "nextthink"
2674 // so we have to set these offsets manually, matching the entvars_t
2675 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, angles);
2676 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, chain);
2677 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, classname);
2678 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, frame);
2679 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, groundentity);
2680 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ideal_yaw);
2681 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, nextthink);
2682 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, think);
2683 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, yaw_speed);
2684 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, self);
2685 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, time);
2686 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_forward);
2687 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_right);
2688 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_up);
2689 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_allsolid);
2690 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_startsolid);
2691 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_fraction);
2692 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inwater);
2693 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inopen);
2694 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_endpos);
2695 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_normal);
2696 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_dist);
2697 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_ent);
2698 // OP_STATE is always supported on server (due to entvars_t)
2699 prog->flag |= PRVM_OP_STATE;
2701 VM_CustomStats_Clear();//[515]: csqc
2702 EntityFrameCSQC_ClearVersions();//[515]: csqc
2706 // see if there is a csprogs.dat installed, and if so, set the csqc_progcrc accordingly, this will be sent to connecting clients to tell them to only load a matching csprogs.dat file
2707 sv.csqc_progname[0] = 0;
2708 sv.csqc_progcrc = FS_CRCFile(csqc_progname.string, &csprogsdatasize);
2709 sv.csqc_progsize = csprogsdatasize;
2710 if (sv.csqc_progsize > 0)
2712 strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
2713 Con_DPrintf("server detected csqc progs file \"%s\" with size %i and crc %i\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
2717 void SV_VM_Begin(void)
2720 PRVM_SetProg( PRVM_SERVERPROG );
2722 prog->globals.server->time = (float) sv.time;
2725 void SV_VM_End(void)