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_jumpvelocity);
127 Cvar_RegisterVariable (&sv_airaccel_qw);
128 Cvar_RegisterVariable (&sv_airaccel_sideways_friction);
129 Cvar_RegisterVariable (&sv_clmovement_enable);
130 Cvar_RegisterVariable (&sv_clmovement_minping);
131 Cvar_RegisterVariable (&sv_clmovement_minping_disabletime);
132 Cvar_RegisterVariable (&sv_clmovement_waitforinput);
133 Cvar_RegisterVariable (&sv_idealpitchscale);
134 Cvar_RegisterVariable (&sv_aim);
135 Cvar_RegisterVariable (&sv_nostep);
136 Cvar_RegisterVariable (&sv_cullentities_pvs);
137 Cvar_RegisterVariable (&sv_cullentities_trace);
138 Cvar_RegisterVariable (&sv_cullentities_trace_samples);
139 Cvar_RegisterVariable (&sv_cullentities_trace_samples_extra);
140 Cvar_RegisterVariable (&sv_cullentities_trace_enlarge);
141 Cvar_RegisterVariable (&sv_cullentities_trace_delay);
142 Cvar_RegisterVariable (&sv_cullentities_trace_prediction);
143 Cvar_RegisterVariable (&sv_cullentities_nevercullbmodels);
144 Cvar_RegisterVariable (&sv_cullentities_stats);
145 Cvar_RegisterVariable (&sv_entpatch);
146 Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
147 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
148 Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
149 Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
150 Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
151 Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
152 Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
153 Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
154 Cvar_RegisterVariable (&sv_gameplayfix_qwplayerphysics);
155 Cvar_RegisterVariable (&sv_gameplayfix_upwardvelocityclearsongroundflag);
156 Cvar_RegisterVariable (&sv_gameplayfix_droptofloorstartsolid);
157 Cvar_RegisterVariable (&sv_protocolname);
158 Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
159 Cvar_RegisterVariable (&sv_maxrate);
160 Cvar_RegisterVariable (&sv_allowdownloads);
161 Cvar_RegisterVariable (&sv_allowdownloads_inarchive);
162 Cvar_RegisterVariable (&sv_allowdownloads_archive);
163 Cvar_RegisterVariable (&sv_allowdownloads_config);
164 Cvar_RegisterVariable (&sv_allowdownloads_dlcache);
165 Cvar_RegisterVariable (&sv_progs);
170 sv_mempool = Mem_AllocPool("server", 0, NULL);
173 static void SV_SaveEntFile_f(void)
175 char basename[MAX_QPATH];
176 if (!sv.active || !sv.worldmodel)
178 Con_Print("Not running a server\n");
181 FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
182 FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
187 =============================================================================
191 =============================================================================
198 Make sure the event gets sent to all clients
201 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
205 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
207 MSG_WriteByte (&sv.datagram, svc_particle);
208 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
209 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
210 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
211 for (i=0 ; i<3 ; i++)
212 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
213 MSG_WriteByte (&sv.datagram, count);
214 MSG_WriteByte (&sv.datagram, color);
215 SV_FlushBroadcastMessages();
222 Make sure the event gets sent to all clients
225 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
227 if (modelindex >= 256 || startframe >= 256)
229 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
231 MSG_WriteByte (&sv.datagram, svc_effect2);
232 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
233 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
234 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
235 MSG_WriteShort (&sv.datagram, modelindex);
236 MSG_WriteShort (&sv.datagram, startframe);
237 MSG_WriteByte (&sv.datagram, framecount);
238 MSG_WriteByte (&sv.datagram, framerate);
242 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
244 MSG_WriteByte (&sv.datagram, svc_effect);
245 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
246 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
247 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
248 MSG_WriteByte (&sv.datagram, modelindex);
249 MSG_WriteByte (&sv.datagram, startframe);
250 MSG_WriteByte (&sv.datagram, framecount);
251 MSG_WriteByte (&sv.datagram, framerate);
253 SV_FlushBroadcastMessages();
260 Each entity can have eight independant sound sources, like voice,
263 Channel 0 is an auto-allocate channel, the others override anything
264 already running on that entity/channel pair.
266 An attenuation of 0 will play full volume everywhere in the level.
267 Larger attenuations will drop off. (max 4 attenuation)
271 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
273 int sound_num, field_mask, i, ent;
275 if (volume < 0 || volume > 255)
277 Con_Printf ("SV_StartSound: volume = %i\n", volume);
281 if (attenuation < 0 || attenuation > 4)
283 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
287 if (channel < 0 || channel > 7)
289 Con_Printf ("SV_StartSound: channel = %i\n", channel);
293 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
296 // find precache number for sound
297 sound_num = SV_SoundIndex(sample, 1);
301 ent = PRVM_NUM_FOR_EDICT(entity);
304 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
305 field_mask |= SND_VOLUME;
306 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
307 field_mask |= SND_ATTENUATION;
309 field_mask |= SND_LARGEENTITY;
310 if (sound_num >= 256 || channel >= 8)
311 field_mask |= SND_LARGESOUND;
313 // directed messages go only to the entity they are targeted on
314 MSG_WriteByte (&sv.datagram, svc_sound);
315 MSG_WriteByte (&sv.datagram, field_mask);
316 if (field_mask & SND_VOLUME)
317 MSG_WriteByte (&sv.datagram, volume);
318 if (field_mask & SND_ATTENUATION)
319 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
320 if (field_mask & SND_LARGEENTITY)
322 MSG_WriteShort (&sv.datagram, ent);
323 MSG_WriteByte (&sv.datagram, channel);
326 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
327 if (field_mask & SND_LARGESOUND)
328 MSG_WriteShort (&sv.datagram, sound_num);
330 MSG_WriteByte (&sv.datagram, sound_num);
331 for (i = 0;i < 3;i++)
332 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
333 SV_FlushBroadcastMessages();
337 ==============================================================================
341 ==============================================================================
348 Sends the first message from the server to a connected client.
349 This will be sent on the initial connection and upon each server load.
352 void SV_SendServerinfo (client_t *client)
357 // we know that this client has a netconnection and thus is not a bot
359 // edicts get reallocated on level changes, so we need to update it here
360 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
362 // clear cached stuff that depends on the level
363 client->weaponmodel[0] = 0;
364 client->weaponmodelindex = 0;
366 // LordHavoc: clear entityframe tracking
367 client->latestframenum = 0;
369 if (client->entitydatabase)
370 EntityFrame_FreeDatabase(client->entitydatabase);
371 if (client->entitydatabase4)
372 EntityFrame4_FreeDatabase(client->entitydatabase4);
373 if (client->entitydatabase5)
374 EntityFrame5_FreeDatabase(client->entitydatabase5);
376 memset(client->stats, 0, sizeof(client->stats));
377 memset(client->statsdeltabits, 0, sizeof(client->statsdeltabits));
379 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
381 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
382 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
383 else if (sv.protocol == PROTOCOL_DARKPLACES4)
384 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
386 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
389 SZ_Clear (&client->netconnection->message);
390 MSG_WriteByte (&client->netconnection->message, svc_print);
391 dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
392 MSG_WriteString (&client->netconnection->message,message);
394 //[515]: init csprogs according to version of svprogs, check the crc, etc.
395 if (sv.csqc_progname[0])
398 Con_DPrintf("sending csqc info to client (\"%s\" with size %i and crc %i)\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
399 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
400 MSG_WriteString (&client->netconnection->message, va("csqc_progname %s\n", sv.csqc_progname));
401 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
402 MSG_WriteString (&client->netconnection->message, va("csqc_progsize %i\n", sv.csqc_progsize));
403 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
404 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", sv.csqc_progcrc));
405 //[515]: init stufftext string (it is sent before svc_serverinfo)
406 val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.SV_InitCmd);
409 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
410 MSG_WriteString (&client->netconnection->message, va("%s\n", PRVM_GetString(val->string)));
414 if (sv_allowdownloads.integer)
416 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
417 MSG_WriteString (&client->netconnection->message, "cl_serverextension_download 1");
420 // send at this time so it's guaranteed to get executed at the right time
424 host_client = client;
425 Curl_SendRequirements();
429 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
430 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
431 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
433 if (!coop.integer && deathmatch.integer)
434 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
436 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
438 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
440 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
441 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
442 MSG_WriteByte (&client->netconnection->message, 0);
444 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
445 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
446 MSG_WriteByte (&client->netconnection->message, 0);
449 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
450 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
451 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
454 MSG_WriteByte (&client->netconnection->message, svc_setview);
455 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
457 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
458 MSG_WriteByte (&client->netconnection->message, 1);
460 client->spawned = false; // need prespawn, spawn, etc
462 // clear movement info until client enters the new level properly
463 memset(&client->cmd, 0, sizeof(client->cmd));
464 client->movesequence = 0;
465 #ifdef NUM_PING_TIMES
466 for (i = 0;i < NUM_PING_TIMES;i++)
467 client->ping_times[i] = 0;
468 client->num_pings = 0;
477 Initializes a client_t for a new net connection. This will only be called
478 once for a player each game, not once for each level change.
481 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
485 float spawn_parms[NUM_SPAWN_PARMS];
487 client = svs.clients + clientnum;
489 if(netconnection)//[515]: bots don't play with csqc =)
490 EntityFrameCSQC_InitClientVersions(clientnum, false);
492 // set up the client_t
494 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
495 memset (client, 0, sizeof(*client));
496 client->active = true;
497 client->netconnection = netconnection;
499 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
501 strlcpy(client->name, "unconnected", sizeof(client->name));
502 strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
503 client->spawned = false;
504 client->edict = PRVM_EDICT_NUM(clientnum+1);
505 if (client->netconnection)
506 client->netconnection->message.allowoverflow = true; // we can catch it
507 // prepare the unreliable message buffer
508 client->unreliablemsg.data = client->unreliablemsg_data;
509 client->unreliablemsg.maxsize = sizeof(client->unreliablemsg_data);
510 // updated by receiving "rate" command from client
511 client->rate = NET_MINRATE;
512 // no limits for local player
513 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
514 client->rate = 1000000000;
515 client->connecttime = realtime;
518 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
521 // call the progs to get default spawn parms for the new client
522 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
523 prog->globals.server->self = 0;
524 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
525 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
526 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
528 // set up the entity for this client (including .colormap, .team, etc)
529 PRVM_ED_ClearEdict(client->edict);
532 // don't call SendServerinfo for a fresh botclient because its fields have
533 // not been set up by the qc yet
534 if (client->netconnection)
535 SV_SendServerinfo (client);
537 client->spawned = true;
542 ===============================================================================
546 ===============================================================================
550 =============================================================================
552 The PVS must include a small area around the client to allow head bobbing
553 or other small motion on the client side. Otherwise, a bob might cause an
554 entity that should be visible to not show up, especially when the bob
557 =============================================================================
560 int sv_writeentitiestoclient_pvsbytes;
561 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
563 static int numsendentities;
564 static entity_state_t sendentities[MAX_EDICTS];
565 static entity_state_t *sendentitiesindex[MAX_EDICTS];
567 static int sententitiesmark = 0;
568 static int sententities[MAX_EDICTS];
569 static int sententitiesconsideration[MAX_EDICTS];
570 static int sv_writeentitiestoclient_culled_pvs;
571 static int sv_writeentitiestoclient_culled_trace;
572 static int sv_writeentitiestoclient_visibleentities;
573 static int sv_writeentitiestoclient_totalentities;
574 //static entity_frame_t sv_writeentitiestoclient_entityframe;
575 static int sv_writeentitiestoclient_clentnum;
576 static vec3_t sv_writeentitiestoclient_testeye;
577 static client_t *sv_writeentitiestoclient_client;
579 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
582 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
583 unsigned int customizeentityforclient;
585 vec3_t cullmins, cullmaxs;
589 // EF_NODRAW prevents sending for any reason except for your own
590 // client, so we must keep all clients in this superset
591 effects = (unsigned)ent->fields.server->effects;
593 // we can omit invisible entities with no effects that are not clients
594 // LordHavoc: this could kill tags attached to an invisible entity, I
595 // just hope we never have to support that case
596 i = (int)ent->fields.server->modelindex;
597 modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
600 i = (int)(PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_size)->_float * 0.25f);
601 glowsize = (unsigned char)bound(0, i, 255);
602 if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_trail)->_float)
603 flags |= RENDER_GLOWTRAIL;
605 f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[0]*256;
606 light[0] = (unsigned short)bound(0, f, 65535);
607 f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[1]*256;
608 light[1] = (unsigned short)bound(0, f, 65535);
609 f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[2]*256;
610 light[2] = (unsigned short)bound(0, f, 65535);
611 f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.light_lev)->_float;
612 light[3] = (unsigned short)bound(0, f, 65535);
613 lightstyle = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.style)->_float;
614 lightpflags = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.pflags)->_float;
616 if (gamemode == GAME_TENEBRAE)
618 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
622 lightpflags |= PFLAGS_FULLDYNAMIC;
624 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
628 light[0] = (int)(0.2*256);
629 light[1] = (int)(1.0*256);
630 light[2] = (int)(0.2*256);
632 lightpflags |= PFLAGS_FULLDYNAMIC;
636 specialvisibilityradius = 0;
637 if (lightpflags & PFLAGS_FULLDYNAMIC)
638 specialvisibilityradius = max(specialvisibilityradius, light[3]);
640 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
641 if (flags & RENDER_GLOWTRAIL)
642 specialvisibilityradius = max(specialvisibilityradius, 100);
643 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
645 if (effects & EF_BRIGHTFIELD)
646 specialvisibilityradius = max(specialvisibilityradius, 80);
647 if (effects & EF_MUZZLEFLASH)
648 specialvisibilityradius = max(specialvisibilityradius, 100);
649 if (effects & EF_BRIGHTLIGHT)
650 specialvisibilityradius = max(specialvisibilityradius, 400);
651 if (effects & EF_DIMLIGHT)
652 specialvisibilityradius = max(specialvisibilityradius, 200);
653 if (effects & EF_RED)
654 specialvisibilityradius = max(specialvisibilityradius, 200);
655 if (effects & EF_BLUE)
656 specialvisibilityradius = max(specialvisibilityradius, 200);
657 if (effects & EF_FLAME)
658 specialvisibilityradius = max(specialvisibilityradius, 250);
659 if (effects & EF_STARDUST)
660 specialvisibilityradius = max(specialvisibilityradius, 100);
663 // early culling checks
664 // (final culling is done by SV_MarkWriteEntityStateToClient)
665 customizeentityforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.customizeentityforclient)->function;
666 if (!customizeentityforclient)
668 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
670 // this 2 billion unit check is actually to detect NAN origins
671 // (we really don't want to send those)
672 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
680 VectorCopy(ent->fields.server->origin, cs->origin);
681 VectorCopy(ent->fields.server->angles, cs->angles);
683 cs->effects = effects;
684 cs->colormap = (unsigned)ent->fields.server->colormap;
685 cs->modelindex = modelindex;
686 cs->skin = (unsigned)ent->fields.server->skin;
687 cs->frame = (unsigned)ent->fields.server->frame;
688 cs->viewmodelforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)->edict;
689 cs->exteriormodelforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.exteriormodeltoclient)->edict;
690 cs->nodrawtoclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.nodrawtoclient)->edict;
691 cs->drawonlytoclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.drawonlytoclient)->edict;
692 cs->customizeentityforclient = customizeentityforclient;
693 cs->tagentity = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)->edict;
694 cs->tagindex = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float;
695 cs->glowsize = glowsize;
697 // don't need to init cs->colormod because the defaultstate did that for us
698 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
699 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod);
700 if (val->vector[0] || val->vector[1] || val->vector[2])
702 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
703 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
704 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
707 cs->modelindex = modelindex;
710 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)->_float * 255.0f);
714 cs->alpha = (unsigned char)bound(0, i, 255);
717 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderamt)->_float);
721 cs->alpha = (unsigned char)bound(0, i, 255);
725 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)->_float * 16.0f);
729 cs->scale = (unsigned char)bound(0, i, 255);
733 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_color)->_float);
735 cs->glowcolor = (int)f;
737 if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.fullbright)->_float)
738 cs->effects |= EF_FULLBRIGHT;
740 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.modelflags);
741 if (val && val->_float)
742 cs->effects |= ((unsigned int)val->_float & 0xff) << 24;
744 if (ent->fields.server->movetype == MOVETYPE_STEP)
745 cs->flags |= RENDER_STEP;
746 if (cs->number != sv_writeentitiestoclient_clentnum && (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)
747 cs->flags |= RENDER_LOWPRECISION;
748 if (ent->fields.server->colormap >= 1024)
749 cs->flags |= RENDER_COLORMAPPED;
750 if (cs->viewmodelforclient)
751 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
753 cs->light[0] = light[0];
754 cs->light[1] = light[1];
755 cs->light[2] = light[2];
756 cs->light[3] = light[3];
757 cs->lightstyle = lightstyle;
758 cs->lightpflags = lightpflags;
760 cs->specialvisibilityradius = specialvisibilityradius;
762 // calculate the visible box of this entity (don't use the physics box
763 // as that is often smaller than a model, and would not count
764 // specialvisibilityradius)
765 if ((model = sv.models[modelindex]))
767 float scale = cs->scale * (1.0f / 16.0f);
768 if (cs->angles[0] || cs->angles[2]) // pitch and roll
770 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
771 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
773 else if (cs->angles[1])
775 VectorMA(cs->origin, scale, model->yawmins, cullmins);
776 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
780 VectorMA(cs->origin, scale, model->normalmins, cullmins);
781 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
786 // if there is no model (or it could not be loaded), use the physics box
787 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
788 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
790 if (specialvisibilityradius)
792 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
793 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
794 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
795 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
796 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
797 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
799 // calculate center of bbox for network prioritization purposes
800 VectorMAM(0.5f, cullmins, 0.5f, cullmaxs, cs->netcenter);
801 // if culling box has moved, update pvs cluster links
802 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
804 VectorCopy(cullmins, ent->priv.server->cullmins);
805 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
806 // a value of -1 for pvs_numclusters indicates that the links are not
807 // cached, and should be re-tested each time, this is the case if the
808 // culling box touches too many pvs clusters to store, or if the world
809 // model does not support FindBoxClusters
810 ent->priv.server->pvs_numclusters = -1;
811 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
813 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
814 if (i <= MAX_ENTITYCLUSTERS)
815 ent->priv.server->pvs_numclusters = i;
822 void SV_PrepareEntitiesForSending(void)
826 // send all entities that touch the pvs
828 sendentitiesindex[0] = NULL;
829 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
830 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
832 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
834 sendentitiesindex[e] = sendentities + numsendentities;
840 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
845 if (sententitiesconsideration[s->number] == sententitiesmark)
847 sententitiesconsideration[s->number] = sententitiesmark;
848 sv_writeentitiestoclient_totalentities++;
850 if (s->customizeentityforclient)
852 prog->globals.server->self = s->number;
853 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
854 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
855 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
859 // never reject player
860 if (s->number != sv_writeentitiestoclient_clentnum)
862 // check various rejection conditions
863 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
865 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
867 if (s->effects & EF_NODRAW)
869 // LordHavoc: only send entities with a model or important effects
870 if (!s->modelindex && s->specialvisibilityradius == 0)
873 isbmodel = (model = sv.models[s->modelindex]) != NULL && model->name[0] == '*';
874 // viewmodels don't have visibility checking
875 if (s->viewmodelforclient)
877 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
880 else if (s->tagentity)
882 // tag attached entities simply check their parent
883 if (!sendentitiesindex[s->tagentity])
885 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
886 if (sententities[s->tagentity] != sententitiesmark)
889 // always send world submodels in newer protocols because they don't
890 // generate much traffic (in old protocols they hog bandwidth)
891 // but only if sv_cullentities_alwayssendbmodels is on
892 else if (!(s->effects & EF_NODEPTHTEST) && (!isbmodel || !sv_cullentities_nevercullbmodels.integer || sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE))
894 // entity has survived every check so far, check if visible
895 ed = PRVM_EDICT_NUM(s->number);
897 // if not touching a visible leaf
898 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
900 if (ed->priv.server->pvs_numclusters < 0)
902 // entity too big for clusters list
903 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
905 sv_writeentitiestoclient_culled_pvs++;
912 // check cached clusters list
913 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
914 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
916 if (i == ed->priv.server->pvs_numclusters)
918 sv_writeentitiestoclient_culled_pvs++;
924 // or not seen by random tracelines
925 if (sv_cullentities_trace.integer && !isbmodel)
927 int samples = s->specialvisibilityradius ? sv_cullentities_trace_samples_extra.integer : sv_cullentities_trace_samples.integer;
928 float enlarge = sv_cullentities_trace_enlarge.value;
930 qboolean visible = TRUE;
934 if(Mod_CanSeeBox_Trace(samples, enlarge, sv.worldmodel, sv_writeentitiestoclient_testeye, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
935 break; // directly visible from the server's view
937 if(sv_cullentities_trace_prediction.integer)
941 // get player velocity
942 float predtime = bound(0, host_client->ping, 0.2); // / 2
943 // sorry, no wallhacking by high ping please, and at 200ms
944 // ping a FPS is annoying to play anyway and a player is
945 // likely to have changed his direction
946 VectorMA(sv_writeentitiestoclient_testeye, predtime, host_client->edict->fields.server->velocity, predeye);
947 if(sv.worldmodel->brush.TraceLineOfSight(sv.worldmodel, sv_writeentitiestoclient_testeye, predeye)) // must be able to go there...
949 if(Mod_CanSeeBox_Trace(samples, enlarge, sv.worldmodel, predeye, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
950 break; // directly visible from the predicted view
954 //Con_DPrintf("Trying to walk into solid in a pingtime... not predicting for culling\n");
958 // when we get here, we can't see the entity
964 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + sv_cullentities_trace_delay.value;
966 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
968 sv_writeentitiestoclient_culled_trace++;
975 // this just marks it for sending
976 // FIXME: it would be more efficient to send here, but the entity
977 // compressor isn't that flexible
978 sv_writeentitiestoclient_visibleentities++;
979 sententities[s->number] = sententitiesmark;
982 entity_state_t sendstates[MAX_EDICTS];
983 extern int csqc_clientnum;
985 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg)
987 int i, numsendstates;
990 // if there isn't enough space to accomplish anything, skip it
991 if (msg->cursize + 25 > msg->maxsize)
994 sv_writeentitiestoclient_client = client;
996 sv_writeentitiestoclient_culled_pvs = 0;
997 sv_writeentitiestoclient_culled_trace = 0;
998 sv_writeentitiestoclient_visibleentities = 0;
999 sv_writeentitiestoclient_totalentities = 0;
1001 // find the client's PVS
1002 // the real place being tested from
1003 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
1004 sv_writeentitiestoclient_pvsbytes = 0;
1005 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
1006 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
1008 sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
1009 csqc_clientnum = sv_writeentitiestoclient_clentnum - 1;
1013 for (i = 0;i < numsendentities;i++)
1014 SV_MarkWriteEntityStateToClient(sendentities + i);
1017 for (i = 0;i < numsendentities;i++)
1019 if (sententities[sendentities[i].number] == sententitiesmark)
1021 s = &sendstates[numsendstates++];
1022 *s = sendentities[i];
1023 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
1024 s->flags |= RENDER_EXTERIORMODEL;
1028 if (sv_cullentities_stats.integer)
1029 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);
1031 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
1033 if (client->entitydatabase5)
1034 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, client->movesequence);
1035 else if (client->entitydatabase4)
1037 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
1038 Protocol_WriteStatsReliable();
1040 else if (client->entitydatabase)
1042 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
1043 Protocol_WriteStatsReliable();
1047 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
1048 Protocol_WriteStatsReliable();
1058 void SV_CleanupEnts (void)
1063 ent = PRVM_NEXT_EDICT(prog->edicts);
1064 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
1065 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
1070 SV_WriteClientdataToMessage
1074 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1078 prvm_edict_t *other;
1084 float *statsf = (float *)stats;
1085 extern cvar_t slowmo;
1088 // send a damage message
1090 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
1092 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
1093 MSG_WriteByte (msg, svc_damage);
1094 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
1095 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
1096 for (i=0 ; i<3 ; i++)
1097 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
1099 ent->fields.server->dmg_take = 0;
1100 ent->fields.server->dmg_save = 0;
1104 // send the current viewpos offset from the view entity
1106 SV_SetIdealPitch (); // how much to look up / down ideally
1108 // a fixangle might get lost in a dropped packet. Oh well.
1109 if(ent->fields.server->fixangle)
1111 // angle fixing was requested by global thinking code...
1112 // so store the current angles for later use
1113 memcpy(host_client->fixangle_angles, ent->fields.server->angles, sizeof(host_client->fixangle_angles));
1114 host_client->fixangle_angles_set = TRUE;
1116 // and clear fixangle for the next frame
1117 ent->fields.server->fixangle = 0;
1120 if (host_client->fixangle_angles_set)
1122 MSG_WriteByte (msg, svc_setangle);
1123 for (i=0 ; i < 3 ; i++)
1124 MSG_WriteAngle (msg, host_client->fixangle_angles[i], sv.protocol);
1125 host_client->fixangle_angles_set = FALSE;
1128 // stuff the sigil bits into the high bits of items for sbar, or else
1130 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.items2);
1131 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1132 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1134 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1136 VectorClear(punchvector);
1137 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.punchvector)))
1138 VectorCopy(val->vector, punchvector);
1140 // cache weapon model name and index in client struct to save time
1141 // (this search can be almost 1% of cpu time!)
1142 s = PRVM_GetString(ent->fields.server->weaponmodel);
1143 if (strcmp(s, client->weaponmodel))
1145 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1146 client->weaponmodelindex = SV_ModelIndex(s, 1);
1150 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewzoom)))
1151 viewzoom = (int)(val->_float * 255.0f);
1157 if ((int)ent->fields.server->flags & FL_ONGROUND)
1158 bits |= SU_ONGROUND;
1159 if (ent->fields.server->waterlevel >= 2)
1161 if (ent->fields.server->idealpitch)
1162 bits |= SU_IDEALPITCH;
1164 for (i=0 ; i<3 ; i++)
1166 if (ent->fields.server->punchangle[i])
1167 bits |= (SU_PUNCH1<<i);
1168 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1170 bits |= (SU_PUNCHVEC1<<i);
1171 if (ent->fields.server->velocity[i])
1172 bits |= (SU_VELOCITY1<<i);
1175 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1176 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1177 stats[STAT_ITEMS] = items;
1178 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1179 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1180 stats[STAT_WEAPON] = client->weaponmodelindex;
1181 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1182 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1183 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1184 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1185 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1186 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1187 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1188 stats[STAT_VIEWZOOM] = viewzoom;
1189 stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1190 stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1191 // the QC bumps these itself by sending svc_'s, so we have to keep them
1192 // zero or they'll be corrected by the engine
1193 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1194 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1196 // movement settings for prediction
1197 statsf[STAT_MOVEVARS_TICRATE] = sys_ticrate.value;
1198 statsf[STAT_MOVEVARS_TIMESCALE] = slowmo.value;
1199 statsf[STAT_MOVEVARS_GRAVITY] = sv_gravity.value;
1200 statsf[STAT_MOVEVARS_STOPSPEED] = sv_stopspeed.value;
1201 statsf[STAT_MOVEVARS_MAXSPEED] = sv_maxspeed.value;
1202 statsf[STAT_MOVEVARS_SPECTATORMAXSPEED] = sv_maxspeed.value; // FIXME: QW has a separate cvar for this
1203 statsf[STAT_MOVEVARS_ACCELERATE] = sv_accelerate.value;
1204 statsf[STAT_MOVEVARS_AIRACCELERATE] = sv_airaccelerate.value >= 0 ? sv_airaccelerate.value : sv_accelerate.value;
1205 statsf[STAT_MOVEVARS_WATERACCELERATE] = sv_wateraccelerate.value >= 0 ? sv_wateraccelerate.value : sv_accelerate.value;
1206 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.gravity);
1207 statsf[STAT_MOVEVARS_ENTGRAVITY] = val ? val->_float : 1.0f;
1208 statsf[STAT_MOVEVARS_JUMPVELOCITY] = sv_jumpvelocity.value;
1209 statsf[STAT_MOVEVARS_EDGEFRICTION] = sv_edgefriction.value;
1210 statsf[STAT_MOVEVARS_MAXAIRSPEED] = sv_maxairspeed.value;
1211 statsf[STAT_MOVEVARS_STEPHEIGHT] = sv_stepheight.value;
1212 statsf[STAT_MOVEVARS_AIRACCEL_QW] = sv_airaccel_qw.value;
1213 statsf[STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION] = sv_airaccel_sideways_friction.value;
1215 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)
1217 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1219 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1220 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1222 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1223 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1224 if (viewzoom != 255)
1225 bits |= SU_VIEWZOOM;
1230 if (bits >= 16777216)
1234 MSG_WriteByte (msg, svc_clientdata);
1235 MSG_WriteShort (msg, bits);
1236 if (bits & SU_EXTEND1)
1237 MSG_WriteByte(msg, bits >> 16);
1238 if (bits & SU_EXTEND2)
1239 MSG_WriteByte(msg, bits >> 24);
1241 if (bits & SU_VIEWHEIGHT)
1242 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1244 if (bits & SU_IDEALPITCH)
1245 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1247 for (i=0 ; i<3 ; i++)
1249 if (bits & (SU_PUNCH1<<i))
1251 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1252 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1254 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1256 if (bits & (SU_PUNCHVEC1<<i))
1258 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1259 MSG_WriteCoord16i(msg, punchvector[i]);
1261 MSG_WriteCoord32f(msg, punchvector[i]);
1263 if (bits & (SU_VELOCITY1<<i))
1265 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1266 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1268 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1272 if (bits & SU_ITEMS)
1273 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1275 if (sv.protocol == PROTOCOL_DARKPLACES5)
1277 if (bits & SU_WEAPONFRAME)
1278 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1279 if (bits & SU_ARMOR)
1280 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1281 if (bits & SU_WEAPON)
1282 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1283 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1284 MSG_WriteShort (msg, stats[STAT_AMMO]);
1285 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1286 MSG_WriteShort (msg, stats[STAT_NAILS]);
1287 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1288 MSG_WriteShort (msg, stats[STAT_CELLS]);
1289 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1290 if (bits & SU_VIEWZOOM)
1291 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1293 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)
1295 if (bits & SU_WEAPONFRAME)
1296 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1297 if (bits & SU_ARMOR)
1298 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1299 if (bits & SU_WEAPON)
1300 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1301 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1302 MSG_WriteByte (msg, stats[STAT_AMMO]);
1303 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1304 MSG_WriteByte (msg, stats[STAT_NAILS]);
1305 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1306 MSG_WriteByte (msg, stats[STAT_CELLS]);
1307 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1309 for (i = 0;i < 32;i++)
1310 if (stats[STAT_WEAPON] & (1<<i))
1312 MSG_WriteByte (msg, i);
1315 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1316 if (bits & SU_VIEWZOOM)
1318 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1319 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1321 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1326 void SV_FlushBroadcastMessages(void)
1330 if (sv.datagram.cursize <= 0)
1332 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1334 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])))
1336 SZ_Write(&client->unreliablemsg, sv.datagram.data, sv.datagram.cursize);
1337 client->unreliablemsg_splitpoint[client->unreliablemsg_splitpoints++] = client->unreliablemsg.cursize;
1339 SZ_Clear(&sv.datagram);
1342 void SV_WriteUnreliableMessages(client_t *client, sizebuf_t *msg)
1344 // scan the splitpoints to find out how many we can fit in
1345 int numsegments, j, split;
1346 if (!client->unreliablemsg_splitpoints)
1348 // always accept the first one if it's within 1400 bytes, this ensures
1349 // that very big datagrams which are over the rate limit still get
1350 // through, just to keep it working
1351 if (msg->cursize + client->unreliablemsg_splitpoint[0] > msg->maxsize && msg->maxsize < 1400)
1354 msg->maxsize = 1400;
1357 for (numsegments = 0;numsegments < client->unreliablemsg_splitpoints;numsegments++)
1358 if (msg->cursize + client->unreliablemsg_splitpoint[numsegments] > msg->maxsize)
1360 if (numsegments > 0)
1362 // some will fit, so add the ones that will fit
1363 split = client->unreliablemsg_splitpoint[numsegments-1];
1364 // note this discards ones that were accepted by the segments scan but
1365 // can not fit, such as a really huge first one that will never ever
1366 // fit in a packet...
1367 if (msg->cursize + split <= msg->maxsize)
1368 SZ_Write(msg, client->unreliablemsg.data, split);
1369 // remove the part we sent, keeping any remaining data
1370 client->unreliablemsg.cursize -= split;
1371 if (client->unreliablemsg.cursize > 0)
1372 memmove(client->unreliablemsg.data, client->unreliablemsg.data + split, client->unreliablemsg.cursize);
1373 // adjust remaining splitpoints
1374 client->unreliablemsg_splitpoints -= numsegments;
1375 for (j = 0;j < client->unreliablemsg_splitpoints;j++)
1376 client->unreliablemsg_splitpoint[j] = client->unreliablemsg_splitpoint[numsegments + j] - split;
1381 =======================
1382 SV_SendClientDatagram
1383 =======================
1385 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1386 void SV_SendClientDatagram (client_t *client)
1388 int clientrate, maxrate, maxsize, maxsize2, downloadsize;
1390 int stats[MAX_CL_STATS];
1392 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1393 maxrate = max(NET_MINRATE, sv_maxrate.integer);
1394 if (sv_maxrate.integer != maxrate)
1395 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1396 // clientrate determines the 'cleartime' of a packet
1397 // (how long to wait before sending another, based on this packet's size)
1398 clientrate = bound(NET_MINRATE, client->rate, maxrate);
1400 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1402 // for good singleplayer, send huge packets and never limit frequency
1403 clientrate = 1000000000;
1404 maxsize = sizeof(sv_sendclientdatagram_buf);
1405 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1407 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)
1409 // no packet size limit support on older protocols because DP1-4 kick
1410 // the client off if they overflow, and quake protocol shows less than
1411 // the full entity set if rate limited
1417 // DP5 and later protocols support packet size limiting which is a
1418 // better method than limiting packet frequency as QW does
1420 // this rate limiting does not understand sys_ticrate 0
1421 // (but no one should be running that on a server!)
1422 maxsize = (int)(clientrate * sys_ticrate.value);
1423 maxsize = bound(100, maxsize, 1400);
1427 // while downloading, limit entity updates to half the packet
1428 // (any leftover space will be used for downloading)
1429 if (host_client->download_file)
1432 msg.data = sv_sendclientdatagram_buf;
1433 msg.maxsize = maxsize;
1436 // obey rate limit by limiting packet frequency if the packet size
1438 // (usually this is caused by reliable messages)
1439 if (!NetConn_CanSend(client->netconnection))
1441 // send the datagram
1442 //NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate);
1445 else if (host_client->spawned)
1447 MSG_WriteByte (&msg, svc_time);
1448 MSG_WriteFloat (&msg, sv.time);
1450 // add the client specific data to the datagram
1451 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1452 // now update the stats[] array using any registered custom fields
1453 VM_SV_UpdateCustomStats (client, client->edict, &msg, stats);
1454 // set host_client->statsdeltabits
1455 Protocol_UpdateClientStats (stats);
1457 // add as many queued unreliable messages (effects) as we can fit
1458 // limit effects to half of the remaining space
1459 msg.maxsize -= (msg.maxsize - msg.cursize) / 2;
1460 if (client->unreliablemsg.cursize)
1461 SV_WriteUnreliableMessages (client, &msg);
1463 msg.maxsize = maxsize;
1465 // now write as many entities as we can fit, and also sends stats
1466 SV_WriteEntitiesToClient (client, client->edict, &msg);
1468 else if (realtime > client->keepalivetime)
1470 // the player isn't totally in the game yet
1471 // send small keepalive messages if too much time has passed
1472 msg.maxsize = maxsize2;
1473 client->keepalivetime = realtime + 5;
1474 MSG_WriteChar (&msg, svc_nop);
1477 msg.maxsize = maxsize2;
1479 // if a download is active, see if there is room to fit some download data
1481 downloadsize = maxsize * 2 - msg.cursize - 7;
1482 if (host_client->download_file && host_client->download_started && downloadsize > 0)
1484 fs_offset_t downloadstart;
1485 unsigned char data[1400];
1486 downloadstart = FS_Tell(host_client->download_file);
1487 downloadsize = min(downloadsize, (int)sizeof(data));
1488 downloadsize = FS_Read(host_client->download_file, data, downloadsize);
1489 // note this sends empty messages if at the end of the file, which is
1490 // necessary to keep the packet loss logic working
1491 // (the last blocks may be lost and need to be re-sent, and that will
1492 // only occur if the client acks the empty end messages, revealing
1493 // a gap in the download progress, causing the last blocks to be
1495 MSG_WriteChar (&msg, svc_downloaddata);
1496 MSG_WriteLong (&msg, downloadstart);
1497 MSG_WriteShort (&msg, downloadsize);
1498 if (downloadsize > 0)
1499 SZ_Write (&msg, data, downloadsize);
1502 // send the datagram
1503 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate);
1507 =======================
1508 SV_UpdateToReliableMessages
1509 =======================
1511 void SV_UpdateToReliableMessages (void)
1520 // check for changes to be sent over the reliable streams
1521 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1523 // update the host_client fields we care about according to the entity fields
1524 host_client->edict = PRVM_EDICT_NUM(i+1);
1527 name = PRVM_GetString(host_client->edict->fields.server->netname);
1530 // always point the string back at host_client->name to keep it safe
1531 strlcpy (host_client->name, name, sizeof (host_client->name));
1532 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1533 if (strcmp(host_client->old_name, host_client->name))
1535 if (host_client->spawned)
1536 SV_BroadcastPrintf("%s^%i changed name to %s\n", host_client->old_name, STRING_COLOR_DEFAULT, host_client->name);
1537 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1538 // send notification to all clients
1539 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1540 MSG_WriteByte (&sv.reliable_datagram, i);
1541 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1544 // DP_SV_CLIENTCOLORS
1545 // this is always found (since it's added by the progs loader)
1546 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
1547 host_client->colors = (int)val->_float;
1548 if (host_client->old_colors != host_client->colors)
1550 host_client->old_colors = host_client->colors;
1551 // send notification to all clients
1552 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1553 MSG_WriteByte (&sv.reliable_datagram, i);
1554 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1557 // NEXUIZ_PLAYERMODEL
1558 if( prog->fieldoffsets.playermodel >= 0 ) {
1559 model = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string);
1562 // always point the string back at host_client->name to keep it safe
1563 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1564 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1567 // NEXUIZ_PLAYERSKIN
1568 if( prog->fieldoffsets.playerskin >= 0 ) {
1569 skin = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string);
1572 // always point the string back at host_client->name to keep it safe
1573 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1574 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1578 host_client->frags = (int)host_client->edict->fields.server->frags;
1579 if (host_client->old_frags != host_client->frags)
1581 host_client->old_frags = host_client->frags;
1582 // send notification to all clients
1583 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1584 MSG_WriteByte (&sv.reliable_datagram, i);
1585 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1589 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1590 if (client->netconnection)
1591 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1593 SZ_Clear (&sv.reliable_datagram);
1598 =======================
1599 SV_SendClientMessages
1600 =======================
1602 void SV_SendClientMessages (void)
1604 int i, prepared = false;
1606 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1607 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1609 SV_FlushBroadcastMessages();
1611 // update frags, names, etc
1612 SV_UpdateToReliableMessages();
1614 // build individual updates
1615 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1617 if (!host_client->active)
1619 if (!host_client->netconnection)
1622 if (host_client->netconnection->message.overflowed)
1624 SV_DropClient (true); // if the message couldn't send, kick off
1631 // only prepare entities once per frame
1632 SV_PrepareEntitiesForSending();
1634 SV_SendClientDatagram (host_client);
1637 // clear muzzle flashes
1641 void SV_StartDownload_f(void)
1643 if (host_client->download_file)
1644 host_client->download_started = true;
1647 void SV_Download_f(void)
1649 const char *whichpack, *whichpack2, *extension;
1651 if (Cmd_Argc() != 2)
1653 SV_ClientPrintf("usage: download <filename>\n");
1657 if (FS_CheckNastyPath(Cmd_Argv(1), false))
1659 SV_ClientPrintf("Download rejected: nasty filename \"%s\"\n", Cmd_Argv(1));
1663 if (host_client->download_file)
1665 // at this point we'll assume the previous download should be aborted
1666 Con_DPrintf("Download of %s aborted by %s starting a new download\n", host_client->download_name, host_client->name);
1667 Host_ClientCommands("\nstopdownload\n");
1669 // close the file and reset variables
1670 FS_Close(host_client->download_file);
1671 host_client->download_file = NULL;
1672 host_client->download_name[0] = 0;
1673 host_client->download_expectedposition = 0;
1674 host_client->download_started = false;
1677 if (!sv_allowdownloads.integer)
1679 SV_ClientPrintf("Downloads are disabled on this server\n");
1680 Host_ClientCommands("\nstopdownload\n");
1684 strlcpy(host_client->download_name, Cmd_Argv(1), sizeof(host_client->download_name));
1685 extension = FS_FileExtension(host_client->download_name);
1687 // host_client is asking to download a specified file
1688 if (developer.integer >= 100)
1689 Con_Printf("Download request for %s by %s\n", host_client->download_name, host_client->name);
1691 if (!FS_FileExists(host_client->download_name))
1693 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);
1694 Host_ClientCommands("\nstopdownload\n");
1698 // check if the user is trying to download part of registered Quake(r)
1699 whichpack = FS_WhichPack(host_client->download_name);
1700 whichpack2 = FS_WhichPack("gfx/pop.lmp");
1701 if ((whichpack && whichpack2 && !strcasecmp(whichpack, whichpack2)) || FS_IsRegisteredQuakePack(host_client->download_name))
1703 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);
1704 Host_ClientCommands("\nstopdownload\n");
1708 // check if the server has forbidden archive downloads entirely
1709 if (!sv_allowdownloads_inarchive.integer)
1711 whichpack = FS_WhichPack(host_client->download_name);
1714 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);
1715 Host_ClientCommands("\nstopdownload\n");
1720 if (!sv_allowdownloads_config.integer)
1722 if (!strcasecmp(extension, "cfg"))
1724 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);
1725 Host_ClientCommands("\nstopdownload\n");
1730 if (!sv_allowdownloads_dlcache.integer)
1732 if (!strncasecmp(host_client->download_name, "dlcache/", 8))
1734 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);
1735 Host_ClientCommands("\nstopdownload\n");
1740 if (!sv_allowdownloads_archive.integer)
1742 if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
1744 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);
1745 Host_ClientCommands("\nstopdownload\n");
1750 host_client->download_file = FS_Open(host_client->download_name, "rb", true, false);
1751 if (!host_client->download_file)
1753 SV_ClientPrintf("Download rejected: server could not open the file \"%s\"\n", host_client->download_name);
1754 Host_ClientCommands("\nstopdownload\n");
1758 if (FS_FileSize(host_client->download_file) > 1<<30)
1760 SV_ClientPrintf("Download rejected: file \"%s\" is very large\n", host_client->download_name);
1761 Host_ClientCommands("\nstopdownload\n");
1762 FS_Close(host_client->download_file);
1763 host_client->download_file = NULL;
1767 Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
1769 Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name);
1771 host_client->download_expectedposition = 0;
1772 host_client->download_started = false;
1774 // the rest of the download process is handled in SV_SendClientDatagram
1775 // and other code dealing with svc_downloaddata and clc_ackdownloaddata
1777 // no svc_downloaddata messages will be sent until sv_startdownload is
1778 // sent by the client
1782 ==============================================================================
1786 ==============================================================================
1795 int SV_ModelIndex(const char *s, int precachemode)
1797 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1798 char filename[MAX_QPATH];
1802 //if (precachemode == 2)
1804 strlcpy(filename, s, sizeof(filename));
1805 for (i = 2;i < limit;i++)
1807 if (!sv.model_precache[i][0])
1811 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))
1813 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1816 if (precachemode == 1)
1817 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1818 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1819 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1820 if (sv.state != ss_loading)
1822 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1823 MSG_WriteShort(&sv.reliable_datagram, i);
1824 MSG_WriteString(&sv.reliable_datagram, filename);
1828 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1831 if (!strcmp(sv.model_precache[i], filename))
1834 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1844 int SV_SoundIndex(const char *s, int precachemode)
1846 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1847 char filename[MAX_QPATH];
1851 //if (precachemode == 2)
1853 strlcpy(filename, s, sizeof(filename));
1854 for (i = 1;i < limit;i++)
1856 if (!sv.sound_precache[i][0])
1860 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))
1862 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1865 if (precachemode == 1)
1866 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1867 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1868 if (sv.state != ss_loading)
1870 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1871 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1872 MSG_WriteString(&sv.reliable_datagram, filename);
1876 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1879 if (!strcmp(sv.sound_precache[i], filename))
1882 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1886 // MUST match effectnameindex_t in client.h
1887 static const char *standardeffectnames[EFFECT_TOTAL] =
1895 "TE_SUPERSPIKEQUAD",
1911 "TE_TEI_BIGEXPLOSION",
1929 SV_ParticleEffectIndex
1933 int SV_ParticleEffectIndex(const char *name)
1935 int i, argc, linenumber, effectnameindex;
1936 fs_offset_t filesize;
1937 unsigned char *filedata;
1938 const char *text, *textstart, *textend;
1939 char argv[16][1024];
1940 if (!sv.particleeffectnamesloaded)
1942 sv.particleeffectnamesloaded = true;
1943 memset(sv.particleeffectname, 0, sizeof(sv.particleeffectname));
1944 for (i = 0;i < EFFECT_TOTAL;i++)
1945 strlcpy(sv.particleeffectname[i], standardeffectnames[i], sizeof(sv.particleeffectname[i]));
1946 filedata = FS_LoadFile("effectinfo.txt", tempmempool, true, &filesize);
1949 textstart = (const char *)filedata;
1950 textend = (const char *)filedata + filesize;
1952 for (linenumber = 1;;linenumber++)
1957 if (!COM_ParseToken(&text, true) || !strcmp(com_token, "\n"))
1961 strlcpy(argv[argc], com_token, sizeof(argv[argc]));
1965 if (com_token[0] == 0)
1966 break; // if the loop exited and it's not a \n, it's EOF
1969 if (!strcmp(argv[0], "effect"))
1973 for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME;effectnameindex++)
1975 if (sv.particleeffectname[effectnameindex][0])
1977 if (!strcmp(sv.particleeffectname[effectnameindex], argv[1]))
1982 strlcpy(sv.particleeffectname[effectnameindex], argv[1], sizeof(sv.particleeffectname[effectnameindex]));
1986 // if we run out of names, abort
1987 if (effectnameindex == SV_MAX_PARTICLEEFFECTNAME)
1989 Con_Printf("effectinfo.txt:%i: too many effects!\n", linenumber);
1998 // search for the name
1999 for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME && sv.particleeffectname[effectnameindex][0];effectnameindex++)
2000 if (!strcmp(sv.particleeffectname[effectnameindex], name))
2001 return effectnameindex;
2002 // return 0 if we couldn't find it
2012 void SV_CreateBaseline (void)
2014 int i, entnum, large;
2015 prvm_edict_t *svent;
2017 // LordHavoc: clear *all* states (note just active ones)
2018 for (entnum = 0;entnum < prog->max_edicts;entnum++)
2020 // get the current server version
2021 svent = PRVM_EDICT_NUM(entnum);
2023 // LordHavoc: always clear state values, whether the entity is in use or not
2024 svent->priv.server->baseline = defaultstate;
2026 if (svent->priv.server->free)
2028 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
2031 // create entity baseline
2032 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
2033 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
2034 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
2035 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
2036 if (entnum > 0 && entnum <= svs.maxclients)
2038 svent->priv.server->baseline.colormap = entnum;
2039 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
2043 svent->priv.server->baseline.colormap = 0;
2044 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
2048 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
2051 // add to the message
2053 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
2055 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
2056 MSG_WriteShort (&sv.signon, entnum);
2060 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
2061 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
2065 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
2066 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
2068 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
2069 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
2070 for (i=0 ; i<3 ; i++)
2072 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
2073 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
2083 Grabs the current state of each client for saving across the
2084 transition to another level
2087 void SV_SaveSpawnparms (void)
2091 svs.serverflags = (int)prog->globals.server->serverflags;
2093 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2095 if (!host_client->active)
2098 // call the progs to get default spawn parms for the new client
2099 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2100 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
2101 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
2102 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
2106 void SV_IncreaseEdicts(void)
2110 int oldmax_edicts = prog->max_edicts;
2111 void *oldedictsengineprivate = prog->edictprivate;
2112 void *oldedictsfields = prog->edictsfields;
2113 void *oldmoved_edicts = sv.moved_edicts;
2115 if (prog->max_edicts >= MAX_EDICTS)
2118 // links don't survive the transition, so unlink everything
2119 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2121 if (!ent->priv.server->free)
2122 SV_UnlinkEdict(prog->edicts + i);
2123 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
2125 World_Clear(&sv.world);
2127 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
2128 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
2129 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
2130 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2132 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
2133 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
2135 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2137 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
2138 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
2139 // link every entity except world
2140 if (!ent->priv.server->free)
2141 SV_LinkEdict(ent, false);
2144 PR_Free(oldedictsengineprivate);
2145 PR_Free(oldedictsfields);
2146 PR_Free(oldmoved_edicts);
2153 This is called at the start of each level
2156 extern float scr_centertime_off;
2158 void SV_SpawnServer (const char *server)
2163 model_t *worldmodel;
2164 char modelname[sizeof(sv.modelname)];
2166 Con_DPrintf("SpawnServer: %s\n", server);
2168 if (cls.state != ca_dedicated)
2169 SCR_BeginLoadingPlaque();
2171 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
2172 worldmodel = Mod_ForName(modelname, false, true, true);
2173 if (!worldmodel || !worldmodel->TraceBox)
2175 Con_Printf("Couldn't load map %s\n", modelname);
2179 // let's not have any servers with no name
2180 if (hostname.string[0] == 0)
2181 Cvar_Set ("hostname", "UNNAMED");
2182 scr_centertime_off = 0;
2184 svs.changelevel_issued = false; // now safe to issue another
2186 // make the map a required file for clients
2187 Curl_ClearRequirements();
2188 Curl_RequireFile(modelname);
2191 // tell all connected clients that we are going to a new level
2196 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
2198 if (client->netconnection)
2200 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
2201 MSG_WriteString(&client->netconnection->message, "reconnect\n");
2208 NetConn_OpenServerPorts(true);
2212 // make cvars consistant
2215 Cvar_SetValue ("deathmatch", 0);
2216 // LordHavoc: it can be useful to have skills outside the range 0-3...
2217 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
2218 //Cvar_SetValue ("skill", (float)current_skill);
2219 current_skill = (int)(skill.value + 0.5);
2222 // set up the new server
2224 memset (&sv, 0, sizeof(sv));
2225 // if running a local client, make sure it doesn't try to access the last
2226 // level's data which is no longer valiud
2229 if(*sv_random_seed.string)
2231 srand(sv_random_seed.integer);
2232 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);
2239 strlcpy (sv.name, server, sizeof (sv.name));
2241 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
2242 if (sv.protocol == PROTOCOL_UNKNOWN)
2245 Protocol_Names(buffer, sizeof(buffer));
2246 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
2247 sv.protocol = PROTOCOL_QUAKE;
2252 // load progs to get entity field count
2253 //PR_LoadProgs ( sv_progs.string );
2255 // allocate server memory
2256 /*// start out with just enough room for clients and a reasonable estimate of entities
2257 prog->max_edicts = max(svs.maxclients + 1, 512);
2258 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
2260 // prvm_edict_t structures (hidden from progs)
2261 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
2262 // engine private structures (hidden from progs)
2263 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
2264 // progs fields, often accessed by server
2265 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
2266 // used by PushMove to move back pushed entities
2267 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2268 /*for (i = 0;i < prog->max_edicts;i++)
2270 ent = prog->edicts + i;
2271 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
2272 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
2275 // reset client csqc entity versions right away.
2276 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2277 EntityFrameCSQC_InitClientVersions(i, true);
2279 sv.datagram.maxsize = sizeof(sv.datagram_buf);
2280 sv.datagram.cursize = 0;
2281 sv.datagram.data = sv.datagram_buf;
2283 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
2284 sv.reliable_datagram.cursize = 0;
2285 sv.reliable_datagram.data = sv.reliable_datagram_buf;
2287 sv.signon.maxsize = sizeof(sv.signon_buf);
2288 sv.signon.cursize = 0;
2289 sv.signon.data = sv.signon_buf;
2291 // leave slots at start for clients only
2292 //prog->num_edicts = svs.maxclients+1;
2294 sv.state = ss_loading;
2295 prog->allowworldwrites = true;
2298 prog->globals.server->time = sv.time = 1.0;
2301 worldmodel->used = true;
2303 strlcpy (sv.name, server, sizeof (sv.name));
2304 strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
2305 sv.worldmodel = worldmodel;
2306 sv.models[1] = sv.worldmodel;
2309 // clear world interaction links
2311 VectorCopy(sv.worldmodel->normalmins, sv.world.areagrid_mins);
2312 VectorCopy(sv.worldmodel->normalmaxs, sv.world.areagrid_maxs);
2313 World_Clear(&sv.world);
2315 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
2317 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
2318 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
2319 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
2321 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
2322 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
2326 // load the rest of the entities
2328 // AK possible hack since num_edicts is still 0
2329 ent = PRVM_EDICT_NUM(0);
2330 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
2331 ent->priv.server->free = false;
2332 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
2333 ent->fields.server->modelindex = 1; // world model
2334 ent->fields.server->solid = SOLID_BSP;
2335 ent->fields.server->movetype = MOVETYPE_PUSH;
2336 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->mins);
2337 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->maxs);
2338 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->absmin);
2339 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->absmax);
2342 prog->globals.server->coop = coop.integer;
2344 prog->globals.server->deathmatch = deathmatch.integer;
2346 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
2348 // serverflags are for cross level information (sigils)
2349 prog->globals.server->serverflags = svs.serverflags;
2351 // we need to reset the spawned flag on all connected clients here so that
2352 // their thinks don't run during startup (before PutClientInServer)
2353 // we also need to set up the client entities now
2354 // and we need to set the ->edict pointers to point into the progs edicts
2355 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2357 host_client->spawned = false;
2358 host_client->edict = PRVM_EDICT_NUM(i + 1);
2359 PRVM_ED_ClearEdict(host_client->edict);
2362 // load replacement entity file if found
2363 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
2365 Con_Printf("Loaded maps/%s.ent\n", sv.name);
2366 PRVM_ED_LoadFromFile (entities);
2370 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
2373 // LordHavoc: clear world angles (to fix e3m3.bsp)
2374 VectorClear(prog->edicts->fields.server->angles);
2376 // all setup is completed, any further precache statements are errors
2377 sv.state = ss_active;
2378 prog->allowworldwrites = false;
2380 // run two frames to allow everything to settle
2381 for (i = 0;i < 2;i++)
2389 // create a baseline for more efficient communications
2390 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
2391 SV_CreateBaseline ();
2393 // send serverinfo to all connected clients, and set up botclients coming back from a level change
2394 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2396 if (!host_client->active)
2398 if (host_client->netconnection)
2399 SV_SendServerinfo(host_client);
2403 // if client is a botclient coming from a level change, we need to
2404 // set up client info that normally requires networking
2406 // copy spawn parms out of the client_t
2407 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
2408 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
2410 // call the spawn function
2411 host_client->clientconnectcalled = true;
2412 prog->globals.server->time = sv.time;
2413 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2414 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
2415 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
2416 host_client->spawned = true;
2420 Con_DPrint("Server spawned.\n");
2421 NetConn_Heartbeat (2);
2426 /////////////////////////////////////////////////////
2429 void SV_VM_CB_BeginIncreaseEdicts(void)
2434 PRVM_Free( sv.moved_edicts );
2435 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2437 // links don't survive the transition, so unlink everything
2438 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2440 if (!ent->priv.server->free)
2441 World_UnlinkEdict(prog->edicts + i);
2442 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
2444 World_Clear(&sv.world);
2447 void SV_VM_CB_EndIncreaseEdicts(void)
2452 // link every entity except world
2453 for (i = 1, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2454 if (!ent->priv.server->free)
2455 SV_LinkEdict(ent, false);
2458 void SV_VM_CB_InitEdict(prvm_edict_t *e)
2460 // LordHavoc: for consistency set these here
2461 int num = PRVM_NUM_FOR_EDICT(e) - 1;
2463 e->priv.server->move = false; // don't move on first frame
2465 if (num >= 0 && num < svs.maxclients)
2468 // set colormap and team on newly created player entity
2469 e->fields.server->colormap = num + 1;
2470 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
2471 // set netname/clientcolors back to client values so that
2472 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
2474 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
2475 if ((val = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.clientcolors)))
2476 val->_float = svs.clients[num].colors;
2477 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
2478 if( prog->fieldoffsets.playermodel >= 0 )
2479 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
2480 if( prog->fieldoffsets.playerskin >= 0 )
2481 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
2482 // Assign netaddress (IP Address, etc)
2483 if(prog->fieldoffsets.netaddress >= 0)
2484 { // Valid Field; Process
2485 if(svs.clients[num].netconnection != NULL)
2486 {// Valid Address; Assign
2487 // Acquire Readable Address
2488 LHNETADDRESS_ToString(&svs.clients[num].netconnection->peeraddress, svs.clients[num].netaddress, sizeof(svs.clients[num].netaddress), false);
2489 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.netaddress)->string = PRVM_SetEngineString(svs.clients[num].netaddress);
2493 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.netaddress)->string = PRVM_SetEngineString("null/botclient");
2498 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
2500 World_UnlinkEdict(ed); // unlink from world bsp
2502 ed->fields.server->model = 0;
2503 ed->fields.server->takedamage = 0;
2504 ed->fields.server->modelindex = 0;
2505 ed->fields.server->colormap = 0;
2506 ed->fields.server->skin = 0;
2507 ed->fields.server->frame = 0;
2508 VectorClear(ed->fields.server->origin);
2509 VectorClear(ed->fields.server->angles);
2510 ed->fields.server->nextthink = -1;
2511 ed->fields.server->solid = 0;
2514 void SV_VM_CB_CountEdicts(void)
2518 int active, models, solid, step;
2520 active = models = solid = step = 0;
2521 for (i=0 ; i<prog->num_edicts ; i++)
2523 ent = PRVM_EDICT_NUM(i);
2524 if (ent->priv.server->free)
2527 if (ent->fields.server->solid)
2529 if (ent->fields.server->model)
2531 if (ent->fields.server->movetype == MOVETYPE_STEP)
2535 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2536 Con_Printf("active :%3i\n", active);
2537 Con_Printf("view :%3i\n", models);
2538 Con_Printf("touch :%3i\n", solid);
2539 Con_Printf("step :%3i\n", step);
2542 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2544 // remove things from different skill levels or deathmatch
2545 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2547 if (deathmatch.integer)
2549 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2554 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2555 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2556 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2564 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)"};
2565 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2566 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2567 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2568 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2569 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2570 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2571 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2572 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2573 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2574 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2575 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2576 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2577 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2578 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2579 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2580 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2581 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2582 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2583 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2584 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2585 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2586 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2587 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2588 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2589 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2590 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2591 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2592 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2593 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2594 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2595 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2596 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2598 void SV_VM_Init(void)
2600 Cvar_RegisterVariable (&pr_checkextension);
2601 Cvar_RegisterVariable (&nomonsters);
2602 Cvar_RegisterVariable (&gamecfg);
2603 Cvar_RegisterVariable (&scratch1);
2604 Cvar_RegisterVariable (&scratch2);
2605 Cvar_RegisterVariable (&scratch3);
2606 Cvar_RegisterVariable (&scratch4);
2607 Cvar_RegisterVariable (&savedgamecfg);
2608 Cvar_RegisterVariable (&saved1);
2609 Cvar_RegisterVariable (&saved2);
2610 Cvar_RegisterVariable (&saved3);
2611 Cvar_RegisterVariable (&saved4);
2612 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2613 if (gamemode == GAME_NEHAHRA)
2615 Cvar_RegisterVariable (&nehx00);
2616 Cvar_RegisterVariable (&nehx01);
2617 Cvar_RegisterVariable (&nehx02);
2618 Cvar_RegisterVariable (&nehx03);
2619 Cvar_RegisterVariable (&nehx04);
2620 Cvar_RegisterVariable (&nehx05);
2621 Cvar_RegisterVariable (&nehx06);
2622 Cvar_RegisterVariable (&nehx07);
2623 Cvar_RegisterVariable (&nehx08);
2624 Cvar_RegisterVariable (&nehx09);
2625 Cvar_RegisterVariable (&nehx10);
2626 Cvar_RegisterVariable (&nehx11);
2627 Cvar_RegisterVariable (&nehx12);
2628 Cvar_RegisterVariable (&nehx13);
2629 Cvar_RegisterVariable (&nehx14);
2630 Cvar_RegisterVariable (&nehx15);
2631 Cvar_RegisterVariable (&nehx16);
2632 Cvar_RegisterVariable (&nehx17);
2633 Cvar_RegisterVariable (&nehx18);
2634 Cvar_RegisterVariable (&nehx19);
2636 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2639 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2641 prvm_required_field_t reqfields[] =
2643 {ev_entity, "cursor_trace_ent"},
2644 {ev_entity, "drawonlytoclient"},
2645 {ev_entity, "exteriormodeltoclient"},
2646 {ev_entity, "nodrawtoclient"},
2647 {ev_entity, "tag_entity"},
2648 {ev_entity, "viewmodelforclient"},
2649 {ev_float, "Version"},
2650 {ev_float, "alpha"},
2651 {ev_float, "ammo_cells1"},
2652 {ev_float, "ammo_lava_nails"},
2653 {ev_float, "ammo_multi_rockets"},
2654 {ev_float, "ammo_nails1"},
2655 {ev_float, "ammo_plasma"},
2656 {ev_float, "ammo_rockets1"},
2657 {ev_float, "ammo_shells1"},
2658 {ev_float, "button3"},
2659 {ev_float, "button4"},
2660 {ev_float, "button5"},
2661 {ev_float, "button6"},
2662 {ev_float, "button7"},
2663 {ev_float, "button8"},
2664 {ev_float, "button9"},
2665 {ev_float, "button10"},
2666 {ev_float, "button11"},
2667 {ev_float, "button12"},
2668 {ev_float, "button13"},
2669 {ev_float, "button14"},
2670 {ev_float, "button15"},
2671 {ev_float, "button16"},
2672 {ev_float, "buttonchat"},
2673 {ev_float, "buttonuse"},
2674 {ev_float, "clientcolors"},
2675 {ev_float, "cursor_active"},
2676 {ev_float, "disableclientprediction"},
2677 {ev_float, "fullbright"},
2678 {ev_float, "glow_color"},
2679 {ev_float, "glow_size"},
2680 {ev_float, "glow_trail"},
2681 {ev_float, "gravity"},
2682 {ev_float, "idealpitch"},
2683 {ev_float, "items2"},
2684 {ev_float, "light_lev"},
2685 {ev_float, "modelflags"},
2686 {ev_float, "pflags"},
2688 {ev_float, "pitch_speed"},
2689 {ev_float, "pmodel"},
2690 {ev_float, "renderamt"}, // HalfLife support
2691 {ev_float, "rendermode"}, // HalfLife support
2692 {ev_float, "scale"},
2693 {ev_float, "style"},
2694 {ev_float, "tag_index"},
2695 {ev_float, "viewzoom"},
2696 {ev_function, "SendEntity"},
2697 {ev_function, "contentstransition"}, // DRESK - Support for Entity Contents Transition Event
2698 {ev_function, "customizeentityforclient"},
2699 {ev_string, "netaddress"},
2700 {ev_string, "playermodel"},
2701 {ev_string, "playerskin"},
2702 {ev_vector, "color"},
2703 {ev_vector, "colormod"},
2704 {ev_vector, "cursor_screen"},
2705 {ev_vector, "cursor_trace_endpos"},
2706 {ev_vector, "cursor_trace_start"},
2707 {ev_vector, "movement"},
2708 {ev_vector, "punchvector"},
2711 void SV_VM_Setup(void)
2713 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
2714 extern cvar_t csqc_progcrc;
2715 extern cvar_t csqc_progsize;
2716 size_t csprogsdatasize;
2718 PRVM_InitProg( PRVM_SERVERPROG );
2720 // allocate the mempools
2721 // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
2722 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2723 prog->builtins = vm_sv_builtins;
2724 prog->numbuiltins = vm_sv_numbuiltins;
2725 prog->headercrc = PROGHEADER_CRC;
2726 prog->max_edicts = 512;
2727 prog->limit_edicts = MAX_EDICTS;
2728 prog->reserved_edicts = svs.maxclients;
2729 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2730 prog->name = "server";
2731 prog->extensionstring = vm_sv_extensions;
2732 prog->loadintoworld = true;
2734 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2735 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2736 prog->init_edict = SV_VM_CB_InitEdict;
2737 prog->free_edict = SV_VM_CB_FreeEdict;
2738 prog->count_edicts = SV_VM_CB_CountEdicts;
2739 prog->load_edict = SV_VM_CB_LoadEdict;
2740 prog->init_cmd = VM_SV_Cmd_Init;
2741 prog->reset_cmd = VM_SV_Cmd_Reset;
2742 prog->error_cmd = Host_Error;
2744 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2745 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields, 0, NULL );
2747 // some mods compiled with scrambling compilers lack certain critical
2748 // global names and field names such as "self" and "time" and "nextthink"
2749 // so we have to set these offsets manually, matching the entvars_t
2750 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, angles);
2751 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, chain);
2752 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, classname);
2753 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, frame);
2754 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, groundentity);
2755 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ideal_yaw);
2756 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, nextthink);
2757 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, think);
2758 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, yaw_speed);
2759 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, self);
2760 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, time);
2761 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_forward);
2762 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_right);
2763 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_up);
2764 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_allsolid);
2765 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_startsolid);
2766 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_fraction);
2767 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inwater);
2768 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inopen);
2769 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_endpos);
2770 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_normal);
2771 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_dist);
2772 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_ent);
2773 // OP_STATE is always supported on server (due to entvars_t)
2774 prog->flag |= PRVM_OP_STATE;
2776 VM_CustomStats_Clear();//[515]: csqc
2777 EntityFrameCSQC_ClearVersions();//[515]: csqc
2781 // 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
2782 sv.csqc_progname[0] = 0;
2783 sv.csqc_progcrc = FS_CRCFile(csqc_progname.string, &csprogsdatasize);
2784 sv.csqc_progsize = csprogsdatasize;
2785 if (sv.csqc_progsize > 0)
2787 strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
2788 Con_DPrintf("server detected csqc progs file \"%s\" with size %i and crc %i\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
2792 void SV_VM_Begin(void)
2795 PRVM_SetProg( PRVM_SERVERPROG );
2797 prog->globals.server->time = (float) sv.time;
2800 void SV_VM_End(void)