2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 // sv_main.c -- server main program
28 void VM_CustomStats_Clear (void);
29 void EntityFrameCSQC_ClearVersions (void);
30 void EntityFrameCSQC_InitClientVersions (int client, qboolean clear);
31 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats);
32 void EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int numstates, const entity_state_t *states);
35 // select which protocol to host, this is fed to Protocol_EnumForName
36 cvar_t sv_protocolname = {0, "sv_protocolname", "DP7", "selects network protocol to host for (values include QUAKE, QUAKEDP, NEHAHRAMOVIE, DP1 and up)"};
37 cvar_t sv_ratelimitlocalplayer = {0, "sv_ratelimitlocalplayer", "0", "whether to apply rate limiting to the local player in a listen server (only useful for testing)"};
38 cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "10000", "upper limit on client rate cvar, should reflect your network connection quality"};
39 cvar_t sv_allowdownloads = {0, "sv_allowdownloads", "1", "whether to allow clients to download files from the server (does not affect http downloads)"};
40 cvar_t sv_allowdownloads_inarchive = {0, "sv_allowdownloads_inarchive", "0", "whether to allow downloads from archives (pak/pk3)"};
41 cvar_t sv_allowdownloads_archive = {0, "sv_allowdownloads_archive", "0", "whether to allow downloads of archives (pak/pk3)"};
42 cvar_t sv_allowdownloads_config = {0, "sv_allowdownloads_config", "0", "whether to allow downloads of config files (cfg)"};
43 cvar_t sv_allowdownloads_dlcache = {0, "sv_allowdownloads_dlcache", "0", "whether to allow downloads of dlcache files (dlcache/)"};
45 extern cvar_t sv_random_seed;
47 static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"}; // fast but loose
48 static cvar_t sv_cullentities_trace = {0, "sv_cullentities_trace", "0", "somewhat slow but very tight culling of hidden entities, minimizes network traffic and makes wallhack cheats useless"}; // tends to get false negatives, uses a timeout to keep entities visible a short time after becoming hidden
49 static cvar_t sv_cullentities_trace_samples = {0, "sv_cullentities_trace_samples", "1", "number of samples to test for entity culling"};
50 static cvar_t sv_cullentities_trace_samples_extra = {0, "sv_cullentities_trace_samples_extra", "2", "number of samples to test for entity culling when the entity affects its surroundings by e.g. dlight"};
51 static cvar_t sv_cullentities_trace_enlarge = {0, "sv_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
52 static cvar_t sv_cullentities_trace_delay = {0, "sv_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
53 static cvar_t sv_cullentities_trace_prediction = {0, "sv_cullentities_trace_prediction", "1", "also trace from the predicted player position"};
54 static cvar_t sv_cullentities_nevercullbmodels = {0, "sv_cullentities_nevercullbmodels", "0", "if enabled the clients are always notified of moving doors and lifts and other submodels of world (warning: eats a lot of network bandwidth on some levels!)"};
55 static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
56 static cvar_t sv_entpatch = {0, "sv_entpatch", "1", "enables loading of .ent files to override entities in the bsp (for example Threewave CTF server pack contains .ent patch files enabling play of CTF on id1 maps)"};
58 cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebouncedownslopes", "1", "prevents MOVETYPE_BOUNCE (grenades) from getting stuck when fired down a downward sloping surface"};
59 cvar_t sv_gameplayfix_noairborncorpse = {0, "sv_gameplayfix_noairborncorpse", "1", "causes entities (corpses) sitting ontop of moving entities (players) to fall when the moving entity (player) is no longer supporting them"};
60 cvar_t sv_gameplayfix_stepdown = {0, "sv_gameplayfix_stepdown", "0", "attempts to step down stairs, not just up them (prevents the familiar thud..thud..thud.. when running down stairs and slopes)"};
61 cvar_t sv_gameplayfix_stepwhilejumping = {0, "sv_gameplayfix_stepwhilejumping", "1", "applies step-up onto a ledge even while airborn, useful if you would otherwise just-miss the floor when running across small areas with gaps (for instance running across the moving platforms in dm2, or jumping to the megahealth and red armor in dm2 rather than using the bridge)"};
62 cvar_t sv_gameplayfix_swiminbmodels = {0, "sv_gameplayfix_swiminbmodels", "1", "causes pointcontents (used to determine if you are in a liquid) to check bmodel entities as well as the world model, so you can swim around in (possibly moving) water bmodel entities"};
63 cvar_t sv_gameplayfix_setmodelrealbox = {0, "sv_gameplayfix_setmodelrealbox", "1", "fixes a bug in Quake that made setmodel always set the entity box to ('-16 -16 -16', '16 16 16') rather than properly checking the model box, breaks some poorly coded mods"};
64 cvar_t sv_gameplayfix_blowupfallenzombies = {0, "sv_gameplayfix_blowupfallenzombies", "1", "causes findradius to detect SOLID_NOT entities such as zombies and corpses on the floor, allowing splash damage to apply to them"};
65 cvar_t sv_gameplayfix_findradiusdistancetobox = {0, "sv_gameplayfix_findradiusdistancetobox", "1", "causes findradius to check the distance to the corner of a box rather than the center of the box, makes findradius detect bmodels such as very large doors that would otherwise be unaffected by splash damage"};
66 cvar_t sv_gameplayfix_qwplayerphysics = {0, "sv_gameplayfix_qwplayerphysics", "1", "changes water jumping to make it easier to get out of water, and prevents friction on landing when bunnyhopping"};
67 cvar_t sv_gameplayfix_upwardvelocityclearsongroundflag = {0, "sv_gameplayfix_upwardvelocityclearsongroundflag", "1", "prevents monsters, items, and most other objects from being stuck to the floor when pushed around by damage, and other situations in mods"};
68 cvar_t sv_gameplayfix_droptofloorstartsolid = {0, "sv_gameplayfix_droptofloorstartsolid", "1", "prevents items and monsters that start in a solid area from falling out of the level (makes droptofloor treat trace_startsolid as an acceptable outcome)"};
70 cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
72 // TODO: move these cvars here
73 extern cvar_t sv_clmovement_enable;
74 extern cvar_t sv_clmovement_minping;
75 extern cvar_t sv_clmovement_minping_disabletime;
76 extern cvar_t sv_clmovement_waitforinput;
81 mempool_t *sv_mempool = NULL;
83 //============================================================================
85 extern void SV_Phys_Init (void);
86 static void SV_SaveEntFile_f(void);
87 static void SV_StartDownload_f(void);
88 static void SV_Download_f(void);
90 void SV_AreaStats_f(void)
92 World_PrintAreaStats(&sv.world, "server");
102 // init the csqc progs cvars, since they are updated/used by the server code
103 // TODO: fix this since this is a quick hack to make some of [515]'s broken code run ;) [9/13/2006 Black]
104 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
105 extern cvar_t csqc_progcrc;
106 extern cvar_t csqc_progsize;
107 Cvar_RegisterVariable (&csqc_progname);
108 Cvar_RegisterVariable (&csqc_progcrc);
109 Cvar_RegisterVariable (&csqc_progsize);
111 Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
112 Cmd_AddCommand("sv_areastats", SV_AreaStats_f, "prints statistics on entity culling during collision traces");
113 Cmd_AddCommand_WithClientCommand("sv_startdownload", NULL, SV_StartDownload_f, "begins sending a file to the client (network protocol use only)");
114 Cmd_AddCommand_WithClientCommand("download", NULL, SV_Download_f, "downloads a specified file from the server");
115 Cvar_RegisterVariable (&sv_maxvelocity);
116 Cvar_RegisterVariable (&sv_gravity);
117 Cvar_RegisterVariable (&sv_friction);
118 Cvar_RegisterVariable (&sv_waterfriction);
119 Cvar_RegisterVariable (&sv_edgefriction);
120 Cvar_RegisterVariable (&sv_stopspeed);
121 Cvar_RegisterVariable (&sv_maxspeed);
122 Cvar_RegisterVariable (&sv_maxairspeed);
123 Cvar_RegisterVariable (&sv_accelerate);
124 Cvar_RegisterVariable (&sv_airaccelerate);
125 Cvar_RegisterVariable (&sv_wateraccelerate);
126 Cvar_RegisterVariable (&sv_clmovement_enable);
127 Cvar_RegisterVariable (&sv_clmovement_minping);
128 Cvar_RegisterVariable (&sv_clmovement_minping_disabletime);
129 Cvar_RegisterVariable (&sv_clmovement_waitforinput);
130 Cvar_RegisterVariable (&sv_idealpitchscale);
131 Cvar_RegisterVariable (&sv_aim);
132 Cvar_RegisterVariable (&sv_nostep);
133 Cvar_RegisterVariable (&sv_cullentities_pvs);
134 Cvar_RegisterVariable (&sv_cullentities_trace);
135 Cvar_RegisterVariable (&sv_cullentities_trace_samples);
136 Cvar_RegisterVariable (&sv_cullentities_trace_samples_extra);
137 Cvar_RegisterVariable (&sv_cullentities_trace_enlarge);
138 Cvar_RegisterVariable (&sv_cullentities_trace_delay);
139 Cvar_RegisterVariable (&sv_cullentities_trace_prediction);
140 Cvar_RegisterVariable (&sv_cullentities_nevercullbmodels);
141 Cvar_RegisterVariable (&sv_cullentities_stats);
142 Cvar_RegisterVariable (&sv_entpatch);
143 Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
144 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
145 Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
146 Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
147 Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
148 Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
149 Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
150 Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
151 Cvar_RegisterVariable (&sv_gameplayfix_qwplayerphysics);
152 Cvar_RegisterVariable (&sv_gameplayfix_upwardvelocityclearsongroundflag);
153 Cvar_RegisterVariable (&sv_gameplayfix_droptofloorstartsolid);
154 Cvar_RegisterVariable (&sv_protocolname);
155 Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
156 Cvar_RegisterVariable (&sv_maxrate);
157 Cvar_RegisterVariable (&sv_allowdownloads);
158 Cvar_RegisterVariable (&sv_allowdownloads_inarchive);
159 Cvar_RegisterVariable (&sv_allowdownloads_archive);
160 Cvar_RegisterVariable (&sv_allowdownloads_config);
161 Cvar_RegisterVariable (&sv_allowdownloads_dlcache);
162 Cvar_RegisterVariable (&sv_progs);
167 sv_mempool = Mem_AllocPool("server", 0, NULL);
170 static void SV_SaveEntFile_f(void)
172 char basename[MAX_QPATH];
173 if (!sv.active || !sv.worldmodel)
175 Con_Print("Not running a server\n");
178 FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
179 FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
184 =============================================================================
188 =============================================================================
195 Make sure the event gets sent to all clients
198 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
202 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
204 MSG_WriteByte (&sv.datagram, svc_particle);
205 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
206 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
207 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
208 for (i=0 ; i<3 ; i++)
209 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
210 MSG_WriteByte (&sv.datagram, count);
211 MSG_WriteByte (&sv.datagram, color);
212 SV_FlushBroadcastMessages();
219 Make sure the event gets sent to all clients
222 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
224 if (modelindex >= 256 || startframe >= 256)
226 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
228 MSG_WriteByte (&sv.datagram, svc_effect2);
229 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
230 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
231 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
232 MSG_WriteShort (&sv.datagram, modelindex);
233 MSG_WriteShort (&sv.datagram, startframe);
234 MSG_WriteByte (&sv.datagram, framecount);
235 MSG_WriteByte (&sv.datagram, framerate);
239 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
241 MSG_WriteByte (&sv.datagram, svc_effect);
242 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
243 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
244 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
245 MSG_WriteByte (&sv.datagram, modelindex);
246 MSG_WriteByte (&sv.datagram, startframe);
247 MSG_WriteByte (&sv.datagram, framecount);
248 MSG_WriteByte (&sv.datagram, framerate);
250 SV_FlushBroadcastMessages();
257 Each entity can have eight independant sound sources, like voice,
260 Channel 0 is an auto-allocate channel, the others override anything
261 already running on that entity/channel pair.
263 An attenuation of 0 will play full volume everywhere in the level.
264 Larger attenuations will drop off. (max 4 attenuation)
268 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
270 int sound_num, field_mask, i, ent;
272 if (volume < 0 || volume > 255)
274 Con_Printf ("SV_StartSound: volume = %i\n", volume);
278 if (attenuation < 0 || attenuation > 4)
280 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
284 if (channel < 0 || channel > 7)
286 Con_Printf ("SV_StartSound: channel = %i\n", channel);
290 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
293 // find precache number for sound
294 sound_num = SV_SoundIndex(sample, 1);
298 ent = PRVM_NUM_FOR_EDICT(entity);
301 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
302 field_mask |= SND_VOLUME;
303 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
304 field_mask |= SND_ATTENUATION;
306 field_mask |= SND_LARGEENTITY;
307 if (sound_num >= 256 || channel >= 8)
308 field_mask |= SND_LARGESOUND;
310 // directed messages go only to the entity they are targeted on
311 MSG_WriteByte (&sv.datagram, svc_sound);
312 MSG_WriteByte (&sv.datagram, field_mask);
313 if (field_mask & SND_VOLUME)
314 MSG_WriteByte (&sv.datagram, volume);
315 if (field_mask & SND_ATTENUATION)
316 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
317 if (field_mask & SND_LARGEENTITY)
319 MSG_WriteShort (&sv.datagram, ent);
320 MSG_WriteByte (&sv.datagram, channel);
323 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
324 if (field_mask & SND_LARGESOUND)
325 MSG_WriteShort (&sv.datagram, sound_num);
327 MSG_WriteByte (&sv.datagram, sound_num);
328 for (i = 0;i < 3;i++)
329 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
330 SV_FlushBroadcastMessages();
334 ==============================================================================
338 ==============================================================================
345 Sends the first message from the server to a connected client.
346 This will be sent on the initial connection and upon each server load.
349 void SV_SendServerinfo (client_t *client)
354 // we know that this client has a netconnection and thus is not a bot
356 // edicts get reallocated on level changes, so we need to update it here
357 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
359 // clear cached stuff that depends on the level
360 client->weaponmodel[0] = 0;
361 client->weaponmodelindex = 0;
363 // LordHavoc: clear entityframe tracking
364 client->latestframenum = 0;
366 if (client->entitydatabase)
367 EntityFrame_FreeDatabase(client->entitydatabase);
368 if (client->entitydatabase4)
369 EntityFrame4_FreeDatabase(client->entitydatabase4);
370 if (client->entitydatabase5)
371 EntityFrame5_FreeDatabase(client->entitydatabase5);
373 memset(client->stats, 0, sizeof(client->stats));
374 memset(client->statsdeltabits, 0, sizeof(client->statsdeltabits));
376 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
378 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
379 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
380 else if (sv.protocol == PROTOCOL_DARKPLACES4)
381 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
383 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
386 SZ_Clear (&client->netconnection->message);
387 MSG_WriteByte (&client->netconnection->message, svc_print);
388 dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
389 MSG_WriteString (&client->netconnection->message,message);
391 //[515]: init csprogs according to version of svprogs, check the crc, etc.
392 if (sv.csqc_progname[0])
395 Con_DPrintf("sending csqc info to client (\"%s\" with size %i and crc %i)\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
396 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
397 MSG_WriteString (&client->netconnection->message, va("csqc_progname %s\n", sv.csqc_progname));
398 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
399 MSG_WriteString (&client->netconnection->message, va("csqc_progsize %i\n", sv.csqc_progsize));
400 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
401 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", sv.csqc_progcrc));
402 //[515]: init stufftext string (it is sent before svc_serverinfo)
403 val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.SV_InitCmd);
406 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
407 MSG_WriteString (&client->netconnection->message, va("%s\n", PRVM_GetString(val->string)));
411 if (sv_allowdownloads.integer)
413 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
414 MSG_WriteString (&client->netconnection->message, "cl_serverextension_download 1");
417 // send at this time so it's guaranteed to get executed at the right time
421 host_client = client;
422 Curl_SendRequirements();
426 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
427 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
428 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
430 if (!coop.integer && deathmatch.integer)
431 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
433 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
435 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
437 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
438 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
439 MSG_WriteByte (&client->netconnection->message, 0);
441 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
442 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
443 MSG_WriteByte (&client->netconnection->message, 0);
446 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
447 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
448 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
451 MSG_WriteByte (&client->netconnection->message, svc_setview);
452 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
454 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
455 MSG_WriteByte (&client->netconnection->message, 1);
457 client->spawned = false; // need prespawn, spawn, etc
459 // clear movement info until client enters the new level properly
460 memset(&client->cmd, 0, sizeof(client->cmd));
461 client->movesequence = 0;
462 #ifdef NUM_PING_TIMES
463 for (i = 0;i < NUM_PING_TIMES;i++)
464 client->ping_times[i] = 0;
465 client->num_pings = 0;
474 Initializes a client_t for a new net connection. This will only be called
475 once for a player each game, not once for each level change.
478 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
482 float spawn_parms[NUM_SPAWN_PARMS];
484 client = svs.clients + clientnum;
486 if(netconnection)//[515]: bots don't play with csqc =)
487 EntityFrameCSQC_InitClientVersions(clientnum, false);
489 // set up the client_t
491 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
492 memset (client, 0, sizeof(*client));
493 client->active = true;
494 client->netconnection = netconnection;
496 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
498 strlcpy(client->name, "unconnected", sizeof(client->name));
499 strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
500 client->spawned = false;
501 client->edict = PRVM_EDICT_NUM(clientnum+1);
502 if (client->netconnection)
503 client->netconnection->message.allowoverflow = true; // we can catch it
504 // prepare the unreliable message buffer
505 client->unreliablemsg.data = client->unreliablemsg_data;
506 client->unreliablemsg.maxsize = sizeof(client->unreliablemsg_data);
507 // updated by receiving "rate" command from client
508 client->rate = NET_MINRATE;
509 // no limits for local player
510 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
511 client->rate = 1000000000;
512 client->connecttime = realtime;
515 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
518 // call the progs to get default spawn parms for the new client
519 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
520 prog->globals.server->self = 0;
521 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
522 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
523 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
525 // set up the entity for this client (including .colormap, .team, etc)
526 PRVM_ED_ClearEdict(client->edict);
529 // don't call SendServerinfo for a fresh botclient because its fields have
530 // not been set up by the qc yet
531 if (client->netconnection)
532 SV_SendServerinfo (client);
534 client->spawned = true;
539 ===============================================================================
543 ===============================================================================
547 =============================================================================
549 The PVS must include a small area around the client to allow head bobbing
550 or other small motion on the client side. Otherwise, a bob might cause an
551 entity that should be visible to not show up, especially when the bob
554 =============================================================================
557 int sv_writeentitiestoclient_pvsbytes;
558 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
560 static int numsendentities;
561 static entity_state_t sendentities[MAX_EDICTS];
562 static entity_state_t *sendentitiesindex[MAX_EDICTS];
564 static int sententitiesmark = 0;
565 static int sententities[MAX_EDICTS];
566 static int sententitiesconsideration[MAX_EDICTS];
567 static int sv_writeentitiestoclient_culled_pvs;
568 static int sv_writeentitiestoclient_culled_trace;
569 static int sv_writeentitiestoclient_visibleentities;
570 static int sv_writeentitiestoclient_totalentities;
571 //static entity_frame_t sv_writeentitiestoclient_entityframe;
572 static int sv_writeentitiestoclient_clentnum;
573 static vec3_t sv_writeentitiestoclient_testeye;
574 static client_t *sv_writeentitiestoclient_client;
576 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
579 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
580 unsigned int customizeentityforclient;
582 vec3_t cullmins, cullmaxs;
586 // EF_NODRAW prevents sending for any reason except for your own
587 // client, so we must keep all clients in this superset
588 effects = (unsigned)ent->fields.server->effects;
590 // we can omit invisible entities with no effects that are not clients
591 // LordHavoc: this could kill tags attached to an invisible entity, I
592 // just hope we never have to support that case
593 i = (int)ent->fields.server->modelindex;
594 modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
597 i = (int)(PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_size)->_float * 0.25f);
598 glowsize = (unsigned char)bound(0, i, 255);
599 if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_trail)->_float)
600 flags |= RENDER_GLOWTRAIL;
602 f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[0]*256;
603 light[0] = (unsigned short)bound(0, f, 65535);
604 f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[1]*256;
605 light[1] = (unsigned short)bound(0, f, 65535);
606 f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[2]*256;
607 light[2] = (unsigned short)bound(0, f, 65535);
608 f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.light_lev)->_float;
609 light[3] = (unsigned short)bound(0, f, 65535);
610 lightstyle = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.style)->_float;
611 lightpflags = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.pflags)->_float;
613 if (gamemode == GAME_TENEBRAE)
615 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
619 lightpflags |= PFLAGS_FULLDYNAMIC;
621 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
625 light[0] = (int)(0.2*256);
626 light[1] = (int)(1.0*256);
627 light[2] = (int)(0.2*256);
629 lightpflags |= PFLAGS_FULLDYNAMIC;
633 specialvisibilityradius = 0;
634 if (lightpflags & PFLAGS_FULLDYNAMIC)
635 specialvisibilityradius = max(specialvisibilityradius, light[3]);
637 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
638 if (flags & RENDER_GLOWTRAIL)
639 specialvisibilityradius = max(specialvisibilityradius, 100);
640 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
642 if (effects & EF_BRIGHTFIELD)
643 specialvisibilityradius = max(specialvisibilityradius, 80);
644 if (effects & EF_MUZZLEFLASH)
645 specialvisibilityradius = max(specialvisibilityradius, 100);
646 if (effects & EF_BRIGHTLIGHT)
647 specialvisibilityradius = max(specialvisibilityradius, 400);
648 if (effects & EF_DIMLIGHT)
649 specialvisibilityradius = max(specialvisibilityradius, 200);
650 if (effects & EF_RED)
651 specialvisibilityradius = max(specialvisibilityradius, 200);
652 if (effects & EF_BLUE)
653 specialvisibilityradius = max(specialvisibilityradius, 200);
654 if (effects & EF_FLAME)
655 specialvisibilityradius = max(specialvisibilityradius, 250);
656 if (effects & EF_STARDUST)
657 specialvisibilityradius = max(specialvisibilityradius, 100);
660 // early culling checks
661 // (final culling is done by SV_MarkWriteEntityStateToClient)
662 customizeentityforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.customizeentityforclient)->function;
663 if (!customizeentityforclient)
665 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
667 // this 2 billion unit check is actually to detect NAN origins
668 // (we really don't want to send those)
669 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
677 VectorCopy(ent->fields.server->origin, cs->origin);
678 VectorCopy(ent->fields.server->angles, cs->angles);
680 cs->effects = effects;
681 cs->colormap = (unsigned)ent->fields.server->colormap;
682 cs->modelindex = modelindex;
683 cs->skin = (unsigned)ent->fields.server->skin;
684 cs->frame = (unsigned)ent->fields.server->frame;
685 cs->viewmodelforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)->edict;
686 cs->exteriormodelforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.exteriormodeltoclient)->edict;
687 cs->nodrawtoclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.nodrawtoclient)->edict;
688 cs->drawonlytoclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.drawonlytoclient)->edict;
689 cs->customizeentityforclient = customizeentityforclient;
690 cs->tagentity = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)->edict;
691 cs->tagindex = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float;
692 cs->glowsize = glowsize;
694 // don't need to init cs->colormod because the defaultstate did that for us
695 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
696 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod);
697 if (val->vector[0] || val->vector[1] || val->vector[2])
699 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
700 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
701 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
704 cs->modelindex = modelindex;
707 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)->_float * 255.0f);
711 cs->alpha = (unsigned char)bound(0, i, 255);
714 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderamt)->_float);
718 cs->alpha = (unsigned char)bound(0, i, 255);
722 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)->_float * 16.0f);
726 cs->scale = (unsigned char)bound(0, i, 255);
730 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_color)->_float);
732 cs->glowcolor = (int)f;
734 if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.fullbright)->_float)
735 cs->effects |= EF_FULLBRIGHT;
737 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.modelflags);
738 if (val && val->_float)
739 cs->effects |= ((unsigned int)val->_float & 0xff) << 24;
741 if (ent->fields.server->movetype == MOVETYPE_STEP)
742 cs->flags |= RENDER_STEP;
743 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)
744 cs->flags |= RENDER_LOWPRECISION;
745 if (ent->fields.server->colormap >= 1024)
746 cs->flags |= RENDER_COLORMAPPED;
747 if (cs->viewmodelforclient)
748 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
750 cs->light[0] = light[0];
751 cs->light[1] = light[1];
752 cs->light[2] = light[2];
753 cs->light[3] = light[3];
754 cs->lightstyle = lightstyle;
755 cs->lightpflags = lightpflags;
757 cs->specialvisibilityradius = specialvisibilityradius;
759 // calculate the visible box of this entity (don't use the physics box
760 // as that is often smaller than a model, and would not count
761 // specialvisibilityradius)
762 if ((model = sv.models[modelindex]))
764 float scale = cs->scale * (1.0f / 16.0f);
765 if (cs->angles[0] || cs->angles[2]) // pitch and roll
767 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
768 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
770 else if (cs->angles[1])
772 VectorMA(cs->origin, scale, model->yawmins, cullmins);
773 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
777 VectorMA(cs->origin, scale, model->normalmins, cullmins);
778 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
783 // if there is no model (or it could not be loaded), use the physics box
784 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
785 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
787 if (specialvisibilityradius)
789 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
790 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
791 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
792 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
793 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
794 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
796 // calculate center of bbox for network prioritization purposes
797 VectorMAM(0.5f, cullmins, 0.5f, cullmaxs, cs->netcenter);
798 // if culling box has moved, update pvs cluster links
799 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
801 VectorCopy(cullmins, ent->priv.server->cullmins);
802 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
803 // a value of -1 for pvs_numclusters indicates that the links are not
804 // cached, and should be re-tested each time, this is the case if the
805 // culling box touches too many pvs clusters to store, or if the world
806 // model does not support FindBoxClusters
807 ent->priv.server->pvs_numclusters = -1;
808 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
810 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
811 if (i <= MAX_ENTITYCLUSTERS)
812 ent->priv.server->pvs_numclusters = i;
819 void SV_PrepareEntitiesForSending(void)
823 // send all entities that touch the pvs
825 sendentitiesindex[0] = NULL;
826 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
827 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
829 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
831 sendentitiesindex[e] = sendentities + numsendentities;
837 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
842 if (sententitiesconsideration[s->number] == sententitiesmark)
844 sententitiesconsideration[s->number] = sententitiesmark;
845 sv_writeentitiestoclient_totalentities++;
847 if (s->customizeentityforclient)
849 prog->globals.server->self = s->number;
850 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
851 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
852 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
856 // never reject player
857 if (s->number != sv_writeentitiestoclient_clentnum)
859 // check various rejection conditions
860 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
862 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
864 if (s->effects & EF_NODRAW)
866 // LordHavoc: only send entities with a model or important effects
867 if (!s->modelindex && s->specialvisibilityradius == 0)
870 isbmodel = (model = sv.models[s->modelindex]) != NULL && model->name[0] == '*';
871 // viewmodels don't have visibility checking
872 if (s->viewmodelforclient)
874 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
877 else if (s->tagentity)
879 // tag attached entities simply check their parent
880 if (!sendentitiesindex[s->tagentity])
882 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
883 if (sententities[s->tagentity] != sententitiesmark)
886 // always send world submodels in newer protocols because they don't
887 // generate much traffic (in old protocols they hog bandwidth)
888 // but only if sv_cullentities_alwayssendbmodels is on
889 else if (!(s->effects & EF_NODEPTHTEST) && (!isbmodel || !sv_cullentities_nevercullbmodels.integer || sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE))
891 // entity has survived every check so far, check if visible
892 ed = PRVM_EDICT_NUM(s->number);
894 // if not touching a visible leaf
895 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
897 if (ed->priv.server->pvs_numclusters < 0)
899 // entity too big for clusters list
900 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
902 sv_writeentitiestoclient_culled_pvs++;
909 // check cached clusters list
910 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
911 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
913 if (i == ed->priv.server->pvs_numclusters)
915 sv_writeentitiestoclient_culled_pvs++;
921 // or not seen by random tracelines
922 if (sv_cullentities_trace.integer && !isbmodel)
924 int samples = s->specialvisibilityradius ? sv_cullentities_trace_samples_extra.integer : sv_cullentities_trace_samples.integer;
925 float enlarge = sv_cullentities_trace_enlarge.value;
927 qboolean visible = TRUE;
931 if(Mod_CanSeeBox_Trace(samples, enlarge, sv.worldmodel, sv_writeentitiestoclient_testeye, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
932 break; // directly visible from the server's view
934 if(sv_cullentities_trace_prediction.integer)
938 // get player velocity
939 float predtime = bound(0, host_client->ping, 0.2); // / 2
940 // sorry, no wallhacking by high ping please, and at 200ms
941 // ping a FPS is annoying to play anyway and a player is
942 // likely to have changed his direction
943 VectorMA(sv_writeentitiestoclient_testeye, predtime, host_client->edict->fields.server->velocity, predeye);
944 if(sv.worldmodel->brush.TraceLineOfSight(sv.worldmodel, sv_writeentitiestoclient_testeye, predeye)) // must be able to go there...
946 if(Mod_CanSeeBox_Trace(samples, enlarge, sv.worldmodel, predeye, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
947 break; // directly visible from the predicted view
951 //Con_DPrintf("Trying to walk into solid in a pingtime... not predicting for culling\n");
955 // when we get here, we can't see the entity
961 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + sv_cullentities_trace_delay.value;
963 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
965 sv_writeentitiestoclient_culled_trace++;
972 // this just marks it for sending
973 // FIXME: it would be more efficient to send here, but the entity
974 // compressor isn't that flexible
975 sv_writeentitiestoclient_visibleentities++;
976 sententities[s->number] = sententitiesmark;
979 entity_state_t sendstates[MAX_EDICTS];
980 extern int csqc_clientnum;
982 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg)
984 int i, numsendstates;
987 // if there isn't enough space to accomplish anything, skip it
988 if (msg->cursize + 25 > msg->maxsize)
991 sv_writeentitiestoclient_client = client;
993 sv_writeentitiestoclient_culled_pvs = 0;
994 sv_writeentitiestoclient_culled_trace = 0;
995 sv_writeentitiestoclient_visibleentities = 0;
996 sv_writeentitiestoclient_totalentities = 0;
998 // find the client's PVS
999 // the real place being tested from
1000 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
1001 sv_writeentitiestoclient_pvsbytes = 0;
1002 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
1003 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
1005 sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
1006 csqc_clientnum = sv_writeentitiestoclient_clentnum - 1;
1010 for (i = 0;i < numsendentities;i++)
1011 SV_MarkWriteEntityStateToClient(sendentities + i);
1014 for (i = 0;i < numsendentities;i++)
1016 if (sententities[sendentities[i].number] == sententitiesmark)
1018 s = &sendstates[numsendstates++];
1019 *s = sendentities[i];
1020 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
1021 s->flags |= RENDER_EXTERIORMODEL;
1025 if (sv_cullentities_stats.integer)
1026 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);
1028 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
1030 if (client->entitydatabase5)
1031 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, client->movesequence);
1032 else if (client->entitydatabase4)
1034 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
1035 Protocol_WriteStatsReliable();
1037 else if (client->entitydatabase)
1039 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
1040 Protocol_WriteStatsReliable();
1044 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
1045 Protocol_WriteStatsReliable();
1055 void SV_CleanupEnts (void)
1060 ent = PRVM_NEXT_EDICT(prog->edicts);
1061 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
1062 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
1067 SV_WriteClientdataToMessage
1071 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1075 prvm_edict_t *other;
1083 // send a damage message
1085 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
1087 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
1088 MSG_WriteByte (msg, svc_damage);
1089 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
1090 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
1091 for (i=0 ; i<3 ; i++)
1092 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
1094 ent->fields.server->dmg_take = 0;
1095 ent->fields.server->dmg_save = 0;
1099 // send the current viewpos offset from the view entity
1101 SV_SetIdealPitch (); // how much to look up / down ideally
1103 // a fixangle might get lost in a dropped packet. Oh well.
1104 if(ent->fields.server->fixangle)
1106 // angle fixing was requested by global thinking code...
1107 // so store the current angles for later use
1108 memcpy(host_client->fixangle_angles, ent->fields.server->angles, sizeof(host_client->fixangle_angles));
1109 host_client->fixangle_angles_set = TRUE;
1111 // and clear fixangle for the next frame
1112 ent->fields.server->fixangle = 0;
1115 if (host_client->fixangle_angles_set)
1117 MSG_WriteByte (msg, svc_setangle);
1118 for (i=0 ; i < 3 ; i++)
1119 MSG_WriteAngle (msg, host_client->fixangle_angles[i], sv.protocol);
1120 host_client->fixangle_angles_set = FALSE;
1123 // stuff the sigil bits into the high bits of items for sbar, or else
1125 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.items2);
1126 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1127 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1129 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1131 VectorClear(punchvector);
1132 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.punchvector)))
1133 VectorCopy(val->vector, punchvector);
1135 // cache weapon model name and index in client struct to save time
1136 // (this search can be almost 1% of cpu time!)
1137 s = PRVM_GetString(ent->fields.server->weaponmodel);
1138 if (strcmp(s, client->weaponmodel))
1140 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1141 client->weaponmodelindex = SV_ModelIndex(s, 1);
1145 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewzoom)))
1146 viewzoom = (int)(val->_float * 255.0f);
1152 if ((int)ent->fields.server->flags & FL_ONGROUND)
1153 bits |= SU_ONGROUND;
1154 if (ent->fields.server->waterlevel >= 2)
1156 if (ent->fields.server->idealpitch)
1157 bits |= SU_IDEALPITCH;
1159 for (i=0 ; i<3 ; i++)
1161 if (ent->fields.server->punchangle[i])
1162 bits |= (SU_PUNCH1<<i);
1163 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1165 bits |= (SU_PUNCHVEC1<<i);
1166 if (ent->fields.server->velocity[i])
1167 bits |= (SU_VELOCITY1<<i);
1170 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1171 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1172 stats[STAT_ITEMS] = items;
1173 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1174 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1175 stats[STAT_WEAPON] = client->weaponmodelindex;
1176 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1177 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1178 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1179 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1180 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1181 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1182 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1183 stats[STAT_VIEWZOOM] = viewzoom;
1184 stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1185 stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1186 // the QC bumps these itself by sending svc_'s, so we have to keep them
1187 // zero or they'll be corrected by the engine
1188 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1189 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1191 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)
1193 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1195 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1196 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1198 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1199 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1200 if (viewzoom != 255)
1201 bits |= SU_VIEWZOOM;
1206 if (bits >= 16777216)
1210 MSG_WriteByte (msg, svc_clientdata);
1211 MSG_WriteShort (msg, bits);
1212 if (bits & SU_EXTEND1)
1213 MSG_WriteByte(msg, bits >> 16);
1214 if (bits & SU_EXTEND2)
1215 MSG_WriteByte(msg, bits >> 24);
1217 if (bits & SU_VIEWHEIGHT)
1218 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1220 if (bits & SU_IDEALPITCH)
1221 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1223 for (i=0 ; i<3 ; i++)
1225 if (bits & (SU_PUNCH1<<i))
1227 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1228 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1230 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1232 if (bits & (SU_PUNCHVEC1<<i))
1234 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1235 MSG_WriteCoord16i(msg, punchvector[i]);
1237 MSG_WriteCoord32f(msg, punchvector[i]);
1239 if (bits & (SU_VELOCITY1<<i))
1241 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1242 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1244 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1248 if (bits & SU_ITEMS)
1249 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1251 if (sv.protocol == PROTOCOL_DARKPLACES5)
1253 if (bits & SU_WEAPONFRAME)
1254 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1255 if (bits & SU_ARMOR)
1256 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1257 if (bits & SU_WEAPON)
1258 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1259 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1260 MSG_WriteShort (msg, stats[STAT_AMMO]);
1261 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1262 MSG_WriteShort (msg, stats[STAT_NAILS]);
1263 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1264 MSG_WriteShort (msg, stats[STAT_CELLS]);
1265 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1266 if (bits & SU_VIEWZOOM)
1267 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1269 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)
1271 if (bits & SU_WEAPONFRAME)
1272 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1273 if (bits & SU_ARMOR)
1274 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1275 if (bits & SU_WEAPON)
1276 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1277 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1278 MSG_WriteByte (msg, stats[STAT_AMMO]);
1279 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1280 MSG_WriteByte (msg, stats[STAT_NAILS]);
1281 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1282 MSG_WriteByte (msg, stats[STAT_CELLS]);
1283 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1285 for (i = 0;i < 32;i++)
1286 if (stats[STAT_WEAPON] & (1<<i))
1288 MSG_WriteByte (msg, i);
1291 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1292 if (bits & SU_VIEWZOOM)
1294 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1295 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1297 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1302 void SV_FlushBroadcastMessages(void)
1306 if (sv.datagram.cursize <= 0)
1308 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1310 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])))
1312 SZ_Write(&client->unreliablemsg, sv.datagram.data, sv.datagram.cursize);
1313 client->unreliablemsg_splitpoint[client->unreliablemsg_splitpoints++] = client->unreliablemsg.cursize;
1315 SZ_Clear(&sv.datagram);
1318 void SV_WriteUnreliableMessages(client_t *client, sizebuf_t *msg)
1320 // scan the splitpoints to find out how many we can fit in
1321 int numsegments, j, split;
1322 if (!client->unreliablemsg_splitpoints)
1324 // always accept the first one if it's within 1400 bytes, this ensures
1325 // that very big datagrams which are over the rate limit still get
1326 // through, just to keep it working
1327 if (msg->cursize + client->unreliablemsg_splitpoint[0] > msg->maxsize && msg->maxsize < 1400)
1330 msg->maxsize = 1400;
1333 for (numsegments = 0;numsegments < client->unreliablemsg_splitpoints;numsegments++)
1334 if (msg->cursize + client->unreliablemsg_splitpoint[numsegments] > msg->maxsize)
1336 if (numsegments > 0)
1338 // some will fit, so add the ones that will fit
1339 split = client->unreliablemsg_splitpoint[numsegments-1];
1340 // note this discards ones that were accepted by the segments scan but
1341 // can not fit, such as a really huge first one that will never ever
1342 // fit in a packet...
1343 if (msg->cursize + split <= msg->maxsize)
1344 SZ_Write(msg, client->unreliablemsg.data, split);
1345 // remove the part we sent, keeping any remaining data
1346 client->unreliablemsg.cursize -= split;
1347 if (client->unreliablemsg.cursize > 0)
1348 memmove(client->unreliablemsg.data, client->unreliablemsg.data + split, client->unreliablemsg.cursize);
1349 // adjust remaining splitpoints
1350 client->unreliablemsg_splitpoints -= numsegments;
1351 for (j = 0;j < client->unreliablemsg_splitpoints;j++)
1352 client->unreliablemsg_splitpoint[j] = client->unreliablemsg_splitpoint[numsegments + j] - split;
1357 =======================
1358 SV_SendClientDatagram
1359 =======================
1361 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1362 void SV_SendClientDatagram (client_t *client)
1364 int clientrate, maxrate, maxsize, maxsize2, downloadsize;
1366 int stats[MAX_CL_STATS];
1368 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1369 maxrate = max(NET_MINRATE, sv_maxrate.integer);
1370 if (sv_maxrate.integer != maxrate)
1371 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1372 // clientrate determines the 'cleartime' of a packet
1373 // (how long to wait before sending another, based on this packet's size)
1374 clientrate = bound(NET_MINRATE, client->rate, maxrate);
1376 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1378 // for good singleplayer, send huge packets and never limit frequency
1379 clientrate = 1000000000;
1380 maxsize = sizeof(sv_sendclientdatagram_buf);
1381 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1383 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)
1385 // no packet size limit support on older protocols because DP1-4 kick
1386 // the client off if they overflow, and quake protocol shows less than
1387 // the full entity set if rate limited
1393 // DP5 and later protocols support packet size limiting which is a
1394 // better method than limiting packet frequency as QW does
1396 // this rate limiting does not understand sys_ticrate 0
1397 // (but no one should be running that on a server!)
1398 maxsize = (int)(clientrate * sys_ticrate.value);
1399 maxsize = bound(100, maxsize, 1400);
1403 // while downloading, limit entity updates to half the packet
1404 // (any leftover space will be used for downloading)
1405 if (host_client->download_file)
1408 msg.data = sv_sendclientdatagram_buf;
1409 msg.maxsize = maxsize;
1412 // obey rate limit by limiting packet frequency if the packet size
1414 // (usually this is caused by reliable messages)
1415 if (!NetConn_CanSend(client->netconnection))
1417 // send the datagram
1418 //NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate);
1421 else if (host_client->spawned)
1423 MSG_WriteByte (&msg, svc_time);
1424 MSG_WriteFloat (&msg, sv.time);
1426 // add the client specific data to the datagram
1427 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1428 // now update the stats[] array using any registered custom fields
1429 VM_SV_UpdateCustomStats (client, client->edict, &msg, stats);
1430 // set host_client->statsdeltabits
1431 Protocol_UpdateClientStats (stats);
1433 // add as many queued unreliable messages (effects) as we can fit
1434 // limit effects to half of the remaining space
1435 msg.maxsize -= (msg.maxsize - msg.cursize) / 2;
1436 if (client->unreliablemsg.cursize)
1437 SV_WriteUnreliableMessages (client, &msg);
1439 msg.maxsize = maxsize;
1441 // now write as many entities as we can fit, and also sends stats
1442 SV_WriteEntitiesToClient (client, client->edict, &msg);
1444 else if (realtime > client->keepalivetime)
1446 // the player isn't totally in the game yet
1447 // send small keepalive messages if too much time has passed
1448 msg.maxsize = maxsize2;
1449 client->keepalivetime = realtime + 5;
1450 MSG_WriteChar (&msg, svc_nop);
1453 msg.maxsize = maxsize2;
1455 // if a download is active, see if there is room to fit some download data
1457 downloadsize = maxsize * 2 - msg.cursize - 7;
1458 if (host_client->download_file && host_client->download_started && downloadsize > 0)
1460 fs_offset_t downloadstart;
1461 unsigned char data[1400];
1462 downloadstart = FS_Tell(host_client->download_file);
1463 downloadsize = min(downloadsize, (int)sizeof(data));
1464 downloadsize = FS_Read(host_client->download_file, data, downloadsize);
1465 // note this sends empty messages if at the end of the file, which is
1466 // necessary to keep the packet loss logic working
1467 // (the last blocks may be lost and need to be re-sent, and that will
1468 // only occur if the client acks the empty end messages, revealing
1469 // a gap in the download progress, causing the last blocks to be
1471 MSG_WriteChar (&msg, svc_downloaddata);
1472 MSG_WriteLong (&msg, downloadstart);
1473 MSG_WriteShort (&msg, downloadsize);
1474 if (downloadsize > 0)
1475 SZ_Write (&msg, data, downloadsize);
1478 // send the datagram
1479 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate);
1483 =======================
1484 SV_UpdateToReliableMessages
1485 =======================
1487 void SV_UpdateToReliableMessages (void)
1496 // check for changes to be sent over the reliable streams
1497 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1499 // update the host_client fields we care about according to the entity fields
1500 host_client->edict = PRVM_EDICT_NUM(i+1);
1503 name = PRVM_GetString(host_client->edict->fields.server->netname);
1506 // always point the string back at host_client->name to keep it safe
1507 strlcpy (host_client->name, name, sizeof (host_client->name));
1508 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1509 if (strcmp(host_client->old_name, host_client->name))
1511 if (host_client->spawned)
1512 SV_BroadcastPrintf("%s^%i changed name to %s\n", host_client->old_name, STRING_COLOR_DEFAULT, host_client->name);
1513 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1514 // send notification to all clients
1515 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1516 MSG_WriteByte (&sv.reliable_datagram, i);
1517 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1520 // DP_SV_CLIENTCOLORS
1521 // this is always found (since it's added by the progs loader)
1522 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
1523 host_client->colors = (int)val->_float;
1524 if (host_client->old_colors != host_client->colors)
1526 host_client->old_colors = host_client->colors;
1527 // send notification to all clients
1528 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1529 MSG_WriteByte (&sv.reliable_datagram, i);
1530 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1533 // NEXUIZ_PLAYERMODEL
1534 if( prog->fieldoffsets.playermodel >= 0 ) {
1535 model = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string);
1538 // always point the string back at host_client->name to keep it safe
1539 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1540 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1543 // NEXUIZ_PLAYERSKIN
1544 if( prog->fieldoffsets.playerskin >= 0 ) {
1545 skin = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string);
1548 // always point the string back at host_client->name to keep it safe
1549 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1550 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1554 host_client->frags = (int)host_client->edict->fields.server->frags;
1555 if (host_client->old_frags != host_client->frags)
1557 host_client->old_frags = host_client->frags;
1558 // send notification to all clients
1559 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1560 MSG_WriteByte (&sv.reliable_datagram, i);
1561 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1565 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1566 if (client->netconnection)
1567 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1569 SZ_Clear (&sv.reliable_datagram);
1574 =======================
1575 SV_SendClientMessages
1576 =======================
1578 void SV_SendClientMessages (void)
1580 int i, prepared = false;
1582 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1583 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1585 SV_FlushBroadcastMessages();
1587 // update frags, names, etc
1588 SV_UpdateToReliableMessages();
1590 // build individual updates
1591 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1593 if (!host_client->active)
1595 if (!host_client->netconnection)
1598 if (host_client->netconnection->message.overflowed)
1600 SV_DropClient (true); // if the message couldn't send, kick off
1607 // only prepare entities once per frame
1608 SV_PrepareEntitiesForSending();
1610 SV_SendClientDatagram (host_client);
1613 // clear muzzle flashes
1617 void SV_StartDownload_f(void)
1619 if (host_client->download_file)
1620 host_client->download_started = true;
1623 void SV_Download_f(void)
1625 const char *whichpack, *whichpack2, *extension;
1627 if (Cmd_Argc() != 2)
1629 SV_ClientPrintf("usage: download <filename>\n");
1633 if (FS_CheckNastyPath(Cmd_Argv(1), false))
1635 SV_ClientPrintf("Download rejected: nasty filename \"%s\"\n", Cmd_Argv(1));
1639 if (host_client->download_file)
1641 // at this point we'll assume the previous download should be aborted
1642 Con_DPrintf("Download of %s aborted by %s starting a new download\n", host_client->download_name, host_client->name);
1643 Host_ClientCommands("\nstopdownload\n");
1645 // close the file and reset variables
1646 FS_Close(host_client->download_file);
1647 host_client->download_file = NULL;
1648 host_client->download_name[0] = 0;
1649 host_client->download_expectedposition = 0;
1650 host_client->download_started = false;
1653 if (!sv_allowdownloads.integer)
1655 SV_ClientPrintf("Downloads are disabled on this server\n");
1656 Host_ClientCommands("\nstopdownload\n");
1660 strlcpy(host_client->download_name, Cmd_Argv(1), sizeof(host_client->download_name));
1661 extension = FS_FileExtension(host_client->download_name);
1663 // host_client is asking to download a specified file
1664 if (developer.integer >= 100)
1665 Con_Printf("Download request for %s by %s\n", host_client->download_name, host_client->name);
1667 if (!FS_FileExists(host_client->download_name))
1669 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);
1670 Host_ClientCommands("\nstopdownload\n");
1674 // check if the user is trying to download part of registered Quake(r)
1675 whichpack = FS_WhichPack(host_client->download_name);
1676 whichpack2 = FS_WhichPack("gfx/pop.lmp");
1677 if ((whichpack && whichpack2 && !strcasecmp(whichpack, whichpack2)) || FS_IsRegisteredQuakePack(host_client->download_name))
1679 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);
1680 Host_ClientCommands("\nstopdownload\n");
1684 // check if the server has forbidden archive downloads entirely
1685 if (!sv_allowdownloads_inarchive.integer)
1687 whichpack = FS_WhichPack(host_client->download_name);
1690 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);
1691 Host_ClientCommands("\nstopdownload\n");
1696 if (!sv_allowdownloads_config.integer)
1698 if (!strcasecmp(extension, "cfg"))
1700 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);
1701 Host_ClientCommands("\nstopdownload\n");
1706 if (!sv_allowdownloads_dlcache.integer)
1708 if (!strncasecmp(host_client->download_name, "dlcache/", 8))
1710 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);
1711 Host_ClientCommands("\nstopdownload\n");
1716 if (!sv_allowdownloads_archive.integer)
1718 if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
1720 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);
1721 Host_ClientCommands("\nstopdownload\n");
1726 host_client->download_file = FS_Open(host_client->download_name, "rb", true, false);
1727 if (!host_client->download_file)
1729 SV_ClientPrintf("Download rejected: server could not open the file \"%s\"\n", host_client->download_name);
1730 Host_ClientCommands("\nstopdownload\n");
1734 if (FS_FileSize(host_client->download_file) > 1<<30)
1736 SV_ClientPrintf("Download rejected: file \"%s\" is very large\n", host_client->download_name);
1737 Host_ClientCommands("\nstopdownload\n");
1738 FS_Close(host_client->download_file);
1739 host_client->download_file = NULL;
1743 Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
1745 Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name);
1747 host_client->download_expectedposition = 0;
1748 host_client->download_started = false;
1750 // the rest of the download process is handled in SV_SendClientDatagram
1751 // and other code dealing with svc_downloaddata and clc_ackdownloaddata
1753 // no svc_downloaddata messages will be sent until sv_startdownload is
1754 // sent by the client
1758 ==============================================================================
1762 ==============================================================================
1771 int SV_ModelIndex(const char *s, int precachemode)
1773 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1774 char filename[MAX_QPATH];
1778 //if (precachemode == 2)
1780 strlcpy(filename, s, sizeof(filename));
1781 for (i = 2;i < limit;i++)
1783 if (!sv.model_precache[i][0])
1787 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))
1789 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1792 if (precachemode == 1)
1793 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1794 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1795 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1796 if (sv.state != ss_loading)
1798 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1799 MSG_WriteShort(&sv.reliable_datagram, i);
1800 MSG_WriteString(&sv.reliable_datagram, filename);
1804 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1807 if (!strcmp(sv.model_precache[i], filename))
1810 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1820 int SV_SoundIndex(const char *s, int precachemode)
1822 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1823 char filename[MAX_QPATH];
1827 //if (precachemode == 2)
1829 strlcpy(filename, s, sizeof(filename));
1830 for (i = 1;i < limit;i++)
1832 if (!sv.sound_precache[i][0])
1836 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))
1838 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1841 if (precachemode == 1)
1842 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1843 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1844 if (sv.state != ss_loading)
1846 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1847 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1848 MSG_WriteString(&sv.reliable_datagram, filename);
1852 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1855 if (!strcmp(sv.sound_precache[i], filename))
1858 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1862 // MUST match effectnameindex_t in client.h
1863 static const char *standardeffectnames[EFFECT_TOTAL] =
1871 "TE_SUPERSPIKEQUAD",
1887 "TE_TEI_BIGEXPLOSION",
1905 SV_ParticleEffectIndex
1909 int SV_ParticleEffectIndex(const char *name)
1911 int i, argc, linenumber, effectnameindex;
1912 fs_offset_t filesize;
1913 unsigned char *filedata;
1914 const char *text, *textstart, *textend;
1915 char argv[16][1024];
1916 if (!sv.particleeffectnamesloaded)
1918 sv.particleeffectnamesloaded = true;
1919 memset(sv.particleeffectname, 0, sizeof(sv.particleeffectname));
1920 for (i = 0;i < EFFECT_TOTAL;i++)
1921 strlcpy(sv.particleeffectname[i], standardeffectnames[i], sizeof(sv.particleeffectname[i]));
1922 filedata = FS_LoadFile("effectinfo.txt", tempmempool, true, &filesize);
1925 textstart = (const char *)filedata;
1926 textend = (const char *)filedata + filesize;
1928 for (linenumber = 1;;linenumber++)
1933 if (!COM_ParseToken(&text, true) || !strcmp(com_token, "\n"))
1937 strlcpy(argv[argc], com_token, sizeof(argv[argc]));
1941 if (com_token[0] == 0)
1942 break; // if the loop exited and it's not a \n, it's EOF
1945 if (!strcmp(argv[0], "effect"))
1949 for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME;effectnameindex++)
1951 if (sv.particleeffectname[effectnameindex][0])
1953 if (!strcmp(sv.particleeffectname[effectnameindex], argv[1]))
1958 strlcpy(sv.particleeffectname[effectnameindex], argv[1], sizeof(sv.particleeffectname[effectnameindex]));
1962 // if we run out of names, abort
1963 if (effectnameindex == SV_MAX_PARTICLEEFFECTNAME)
1965 Con_Printf("effectinfo.txt:%i: too many effects!\n", linenumber);
1974 // search for the name
1975 for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME && sv.particleeffectname[effectnameindex][0];effectnameindex++)
1976 if (!strcmp(sv.particleeffectname[effectnameindex], name))
1977 return effectnameindex;
1978 // return 0 if we couldn't find it
1988 void SV_CreateBaseline (void)
1990 int i, entnum, large;
1991 prvm_edict_t *svent;
1993 // LordHavoc: clear *all* states (note just active ones)
1994 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1996 // get the current server version
1997 svent = PRVM_EDICT_NUM(entnum);
1999 // LordHavoc: always clear state values, whether the entity is in use or not
2000 svent->priv.server->baseline = defaultstate;
2002 if (svent->priv.server->free)
2004 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
2007 // create entity baseline
2008 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
2009 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
2010 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
2011 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
2012 if (entnum > 0 && entnum <= svs.maxclients)
2014 svent->priv.server->baseline.colormap = entnum;
2015 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
2019 svent->priv.server->baseline.colormap = 0;
2020 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
2024 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
2027 // add to the message
2029 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
2031 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
2032 MSG_WriteShort (&sv.signon, entnum);
2036 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
2037 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
2041 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
2042 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
2044 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
2045 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
2046 for (i=0 ; i<3 ; i++)
2048 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
2049 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
2059 Grabs the current state of each client for saving across the
2060 transition to another level
2063 void SV_SaveSpawnparms (void)
2067 svs.serverflags = (int)prog->globals.server->serverflags;
2069 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2071 if (!host_client->active)
2074 // call the progs to get default spawn parms for the new client
2075 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2076 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
2077 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
2078 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
2082 void SV_IncreaseEdicts(void)
2086 int oldmax_edicts = prog->max_edicts;
2087 void *oldedictsengineprivate = prog->edictprivate;
2088 void *oldedictsfields = prog->edictsfields;
2089 void *oldmoved_edicts = sv.moved_edicts;
2091 if (prog->max_edicts >= MAX_EDICTS)
2094 // links don't survive the transition, so unlink everything
2095 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2097 if (!ent->priv.server->free)
2098 SV_UnlinkEdict(prog->edicts + i);
2099 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
2101 World_Clear(&sv.world);
2103 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
2104 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
2105 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
2106 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2108 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
2109 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
2111 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2113 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
2114 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
2115 // link every entity except world
2116 if (!ent->priv.server->free)
2117 SV_LinkEdict(ent, false);
2120 PR_Free(oldedictsengineprivate);
2121 PR_Free(oldedictsfields);
2122 PR_Free(oldmoved_edicts);
2129 This is called at the start of each level
2132 extern float scr_centertime_off;
2134 void SV_SpawnServer (const char *server)
2139 model_t *worldmodel;
2140 char modelname[sizeof(sv.modelname)];
2142 Con_DPrintf("SpawnServer: %s\n", server);
2144 if (cls.state != ca_dedicated)
2145 SCR_BeginLoadingPlaque();
2147 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
2148 worldmodel = Mod_ForName(modelname, false, true, true);
2149 if (!worldmodel || !worldmodel->TraceBox)
2151 Con_Printf("Couldn't load map %s\n", modelname);
2155 // let's not have any servers with no name
2156 if (hostname.string[0] == 0)
2157 Cvar_Set ("hostname", "UNNAMED");
2158 scr_centertime_off = 0;
2160 svs.changelevel_issued = false; // now safe to issue another
2162 // make the map a required file for clients
2163 Curl_ClearRequirements();
2164 Curl_RequireFile(modelname);
2167 // tell all connected clients that we are going to a new level
2172 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
2174 if (client->netconnection)
2176 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
2177 MSG_WriteString(&client->netconnection->message, "reconnect\n");
2184 NetConn_OpenServerPorts(true);
2188 // make cvars consistant
2191 Cvar_SetValue ("deathmatch", 0);
2192 // LordHavoc: it can be useful to have skills outside the range 0-3...
2193 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
2194 //Cvar_SetValue ("skill", (float)current_skill);
2195 current_skill = (int)(skill.value + 0.5);
2198 // set up the new server
2200 memset (&sv, 0, sizeof(sv));
2201 // if running a local client, make sure it doesn't try to access the last
2202 // level's data which is no longer valiud
2205 if(*sv_random_seed.string)
2207 srand(sv_random_seed.integer);
2208 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);
2215 strlcpy (sv.name, server, sizeof (sv.name));
2217 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
2218 if (sv.protocol == PROTOCOL_UNKNOWN)
2221 Protocol_Names(buffer, sizeof(buffer));
2222 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
2223 sv.protocol = PROTOCOL_QUAKE;
2228 // load progs to get entity field count
2229 //PR_LoadProgs ( sv_progs.string );
2231 // allocate server memory
2232 /*// start out with just enough room for clients and a reasonable estimate of entities
2233 prog->max_edicts = max(svs.maxclients + 1, 512);
2234 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
2236 // prvm_edict_t structures (hidden from progs)
2237 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
2238 // engine private structures (hidden from progs)
2239 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
2240 // progs fields, often accessed by server
2241 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
2242 // used by PushMove to move back pushed entities
2243 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2244 /*for (i = 0;i < prog->max_edicts;i++)
2246 ent = prog->edicts + i;
2247 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
2248 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
2251 // reset client csqc entity versions right away.
2252 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2253 EntityFrameCSQC_InitClientVersions(i, true);
2255 sv.datagram.maxsize = sizeof(sv.datagram_buf);
2256 sv.datagram.cursize = 0;
2257 sv.datagram.data = sv.datagram_buf;
2259 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
2260 sv.reliable_datagram.cursize = 0;
2261 sv.reliable_datagram.data = sv.reliable_datagram_buf;
2263 sv.signon.maxsize = sizeof(sv.signon_buf);
2264 sv.signon.cursize = 0;
2265 sv.signon.data = sv.signon_buf;
2267 // leave slots at start for clients only
2268 //prog->num_edicts = svs.maxclients+1;
2270 sv.state = ss_loading;
2271 prog->allowworldwrites = true;
2274 prog->globals.server->time = sv.time = 1.0;
2277 worldmodel->used = true;
2279 strlcpy (sv.name, server, sizeof (sv.name));
2280 strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
2281 sv.worldmodel = worldmodel;
2282 sv.models[1] = sv.worldmodel;
2285 // clear world interaction links
2287 VectorCopy(sv.worldmodel->normalmins, sv.world.areagrid_mins);
2288 VectorCopy(sv.worldmodel->normalmaxs, sv.world.areagrid_maxs);
2289 World_Clear(&sv.world);
2291 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
2293 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
2294 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
2295 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
2297 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
2298 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
2302 // load the rest of the entities
2304 // AK possible hack since num_edicts is still 0
2305 ent = PRVM_EDICT_NUM(0);
2306 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
2307 ent->priv.server->free = false;
2308 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
2309 ent->fields.server->modelindex = 1; // world model
2310 ent->fields.server->solid = SOLID_BSP;
2311 ent->fields.server->movetype = MOVETYPE_PUSH;
2312 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->mins);
2313 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->maxs);
2314 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->absmin);
2315 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->absmax);
2318 prog->globals.server->coop = coop.integer;
2320 prog->globals.server->deathmatch = deathmatch.integer;
2322 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
2324 // serverflags are for cross level information (sigils)
2325 prog->globals.server->serverflags = svs.serverflags;
2327 // we need to reset the spawned flag on all connected clients here so that
2328 // their thinks don't run during startup (before PutClientInServer)
2329 // we also need to set up the client entities now
2330 // and we need to set the ->edict pointers to point into the progs edicts
2331 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2333 host_client->spawned = false;
2334 host_client->edict = PRVM_EDICT_NUM(i + 1);
2335 PRVM_ED_ClearEdict(host_client->edict);
2338 // load replacement entity file if found
2339 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
2341 Con_Printf("Loaded maps/%s.ent\n", sv.name);
2342 PRVM_ED_LoadFromFile (entities);
2346 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
2349 // LordHavoc: clear world angles (to fix e3m3.bsp)
2350 VectorClear(prog->edicts->fields.server->angles);
2352 // all setup is completed, any further precache statements are errors
2353 sv.state = ss_active;
2354 prog->allowworldwrites = false;
2356 // run two frames to allow everything to settle
2357 for (i = 0;i < 2;i++)
2365 // create a baseline for more efficient communications
2366 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
2367 SV_CreateBaseline ();
2369 // send serverinfo to all connected clients, and set up botclients coming back from a level change
2370 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2372 if (!host_client->active)
2374 if (host_client->netconnection)
2375 SV_SendServerinfo(host_client);
2379 // if client is a botclient coming from a level change, we need to
2380 // set up client info that normally requires networking
2382 // copy spawn parms out of the client_t
2383 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
2384 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
2386 // call the spawn function
2387 host_client->clientconnectcalled = true;
2388 prog->globals.server->time = sv.time;
2389 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2390 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
2391 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
2392 host_client->spawned = true;
2396 Con_DPrint("Server spawned.\n");
2397 NetConn_Heartbeat (2);
2402 /////////////////////////////////////////////////////
2405 void SV_VM_CB_BeginIncreaseEdicts(void)
2410 PRVM_Free( sv.moved_edicts );
2411 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2413 // links don't survive the transition, so unlink everything
2414 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2416 if (!ent->priv.server->free)
2417 World_UnlinkEdict(prog->edicts + i);
2418 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
2420 World_Clear(&sv.world);
2423 void SV_VM_CB_EndIncreaseEdicts(void)
2428 // link every entity except world
2429 for (i = 1, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2430 if (!ent->priv.server->free)
2431 SV_LinkEdict(ent, false);
2434 void SV_VM_CB_InitEdict(prvm_edict_t *e)
2436 // LordHavoc: for consistency set these here
2437 int num = PRVM_NUM_FOR_EDICT(e) - 1;
2439 e->priv.server->move = false; // don't move on first frame
2441 if (num >= 0 && num < svs.maxclients)
2444 // set colormap and team on newly created player entity
2445 e->fields.server->colormap = num + 1;
2446 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
2447 // set netname/clientcolors back to client values so that
2448 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
2450 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
2451 if ((val = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.clientcolors)))
2452 val->_float = svs.clients[num].colors;
2453 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
2454 if( prog->fieldoffsets.playermodel >= 0 )
2455 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
2456 if( prog->fieldoffsets.playerskin >= 0 )
2457 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
2458 // Assign netaddress (IP Address, etc)
2459 if(prog->fieldoffsets.netaddress >= 0)
2460 { // Valid Field; Process
2461 if(svs.clients[num].netconnection != NULL)
2462 {// Valid Address; Assign
2463 // Acquire Readable Address
2464 LHNETADDRESS_ToString(&svs.clients[num].netconnection->peeraddress, svs.clients[num].netaddress, sizeof(svs.clients[num].netaddress), false);
2465 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.netaddress)->string = PRVM_SetEngineString(svs.clients[num].netaddress);
2469 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.netaddress)->string = PRVM_SetEngineString("null/botclient");
2474 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
2476 World_UnlinkEdict(ed); // unlink from world bsp
2478 ed->fields.server->model = 0;
2479 ed->fields.server->takedamage = 0;
2480 ed->fields.server->modelindex = 0;
2481 ed->fields.server->colormap = 0;
2482 ed->fields.server->skin = 0;
2483 ed->fields.server->frame = 0;
2484 VectorClear(ed->fields.server->origin);
2485 VectorClear(ed->fields.server->angles);
2486 ed->fields.server->nextthink = -1;
2487 ed->fields.server->solid = 0;
2490 void SV_VM_CB_CountEdicts(void)
2494 int active, models, solid, step;
2496 active = models = solid = step = 0;
2497 for (i=0 ; i<prog->num_edicts ; i++)
2499 ent = PRVM_EDICT_NUM(i);
2500 if (ent->priv.server->free)
2503 if (ent->fields.server->solid)
2505 if (ent->fields.server->model)
2507 if (ent->fields.server->movetype == MOVETYPE_STEP)
2511 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2512 Con_Printf("active :%3i\n", active);
2513 Con_Printf("view :%3i\n", models);
2514 Con_Printf("touch :%3i\n", solid);
2515 Con_Printf("step :%3i\n", step);
2518 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2520 // remove things from different skill levels or deathmatch
2521 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2523 if (deathmatch.integer)
2525 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2530 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2531 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2532 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2540 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)"};
2541 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2542 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2543 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2544 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2545 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2546 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2547 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2548 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2549 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2550 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2551 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2552 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2553 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2554 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2555 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2556 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2557 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2558 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2559 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2560 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2561 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2562 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2563 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2564 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2565 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2566 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2567 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2568 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2569 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2570 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2571 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2572 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2574 void SV_VM_Init(void)
2576 Cvar_RegisterVariable (&pr_checkextension);
2577 Cvar_RegisterVariable (&nomonsters);
2578 Cvar_RegisterVariable (&gamecfg);
2579 Cvar_RegisterVariable (&scratch1);
2580 Cvar_RegisterVariable (&scratch2);
2581 Cvar_RegisterVariable (&scratch3);
2582 Cvar_RegisterVariable (&scratch4);
2583 Cvar_RegisterVariable (&savedgamecfg);
2584 Cvar_RegisterVariable (&saved1);
2585 Cvar_RegisterVariable (&saved2);
2586 Cvar_RegisterVariable (&saved3);
2587 Cvar_RegisterVariable (&saved4);
2588 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2589 if (gamemode == GAME_NEHAHRA)
2591 Cvar_RegisterVariable (&nehx00);
2592 Cvar_RegisterVariable (&nehx01);
2593 Cvar_RegisterVariable (&nehx02);
2594 Cvar_RegisterVariable (&nehx03);
2595 Cvar_RegisterVariable (&nehx04);
2596 Cvar_RegisterVariable (&nehx05);
2597 Cvar_RegisterVariable (&nehx06);
2598 Cvar_RegisterVariable (&nehx07);
2599 Cvar_RegisterVariable (&nehx08);
2600 Cvar_RegisterVariable (&nehx09);
2601 Cvar_RegisterVariable (&nehx10);
2602 Cvar_RegisterVariable (&nehx11);
2603 Cvar_RegisterVariable (&nehx12);
2604 Cvar_RegisterVariable (&nehx13);
2605 Cvar_RegisterVariable (&nehx14);
2606 Cvar_RegisterVariable (&nehx15);
2607 Cvar_RegisterVariable (&nehx16);
2608 Cvar_RegisterVariable (&nehx17);
2609 Cvar_RegisterVariable (&nehx18);
2610 Cvar_RegisterVariable (&nehx19);
2612 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2615 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2617 prvm_required_field_t reqfields[] =
2619 {ev_entity, "cursor_trace_ent"},
2620 {ev_entity, "drawonlytoclient"},
2621 {ev_entity, "exteriormodeltoclient"},
2622 {ev_entity, "nodrawtoclient"},
2623 {ev_entity, "tag_entity"},
2624 {ev_entity, "viewmodelforclient"},
2625 {ev_float, "Version"},
2626 {ev_float, "alpha"},
2627 {ev_float, "ammo_cells1"},
2628 {ev_float, "ammo_lava_nails"},
2629 {ev_float, "ammo_multi_rockets"},
2630 {ev_float, "ammo_nails1"},
2631 {ev_float, "ammo_plasma"},
2632 {ev_float, "ammo_rockets1"},
2633 {ev_float, "ammo_shells1"},
2634 {ev_float, "button3"},
2635 {ev_float, "button4"},
2636 {ev_float, "button5"},
2637 {ev_float, "button6"},
2638 {ev_float, "button7"},
2639 {ev_float, "button8"},
2640 {ev_float, "button9"},
2641 {ev_float, "button10"},
2642 {ev_float, "button11"},
2643 {ev_float, "button12"},
2644 {ev_float, "button13"},
2645 {ev_float, "button14"},
2646 {ev_float, "button15"},
2647 {ev_float, "button16"},
2648 {ev_float, "buttonchat"},
2649 {ev_float, "buttonuse"},
2650 {ev_float, "clientcolors"},
2651 {ev_float, "cursor_active"},
2652 {ev_float, "disableclientprediction"},
2653 {ev_float, "fullbright"},
2654 {ev_float, "glow_color"},
2655 {ev_float, "glow_size"},
2656 {ev_float, "glow_trail"},
2657 {ev_float, "gravity"},
2658 {ev_float, "idealpitch"},
2659 {ev_float, "items2"},
2660 {ev_float, "light_lev"},
2661 {ev_float, "modelflags"},
2662 {ev_float, "pflags"},
2664 {ev_float, "pitch_speed"},
2665 {ev_float, "pmodel"},
2666 {ev_float, "renderamt"}, // HalfLife support
2667 {ev_float, "rendermode"}, // HalfLife support
2668 {ev_float, "scale"},
2669 {ev_float, "style"},
2670 {ev_float, "tag_index"},
2671 {ev_float, "viewzoom"},
2672 {ev_function, "SendEntity"},
2673 {ev_function, "contentstransition"}, // DRESK - Support for Entity Contents Transition Event
2674 {ev_function, "customizeentityforclient"},
2675 {ev_string, "netaddress"},
2676 {ev_string, "playermodel"},
2677 {ev_string, "playerskin"},
2678 {ev_vector, "color"},
2679 {ev_vector, "colormod"},
2680 {ev_vector, "cursor_screen"},
2681 {ev_vector, "cursor_trace_endpos"},
2682 {ev_vector, "cursor_trace_start"},
2683 {ev_vector, "movement"},
2684 {ev_vector, "punchvector"},
2687 void SV_VM_Setup(void)
2689 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
2690 extern cvar_t csqc_progcrc;
2691 extern cvar_t csqc_progsize;
2692 size_t csprogsdatasize;
2694 PRVM_InitProg( PRVM_SERVERPROG );
2696 // allocate the mempools
2697 // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
2698 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2699 prog->builtins = vm_sv_builtins;
2700 prog->numbuiltins = vm_sv_numbuiltins;
2701 prog->headercrc = PROGHEADER_CRC;
2702 prog->max_edicts = 512;
2703 prog->limit_edicts = MAX_EDICTS;
2704 prog->reserved_edicts = svs.maxclients;
2705 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2706 prog->name = "server";
2707 prog->extensionstring = vm_sv_extensions;
2708 prog->loadintoworld = true;
2710 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2711 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2712 prog->init_edict = SV_VM_CB_InitEdict;
2713 prog->free_edict = SV_VM_CB_FreeEdict;
2714 prog->count_edicts = SV_VM_CB_CountEdicts;
2715 prog->load_edict = SV_VM_CB_LoadEdict;
2716 prog->init_cmd = VM_SV_Cmd_Init;
2717 prog->reset_cmd = VM_SV_Cmd_Reset;
2718 prog->error_cmd = Host_Error;
2720 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2721 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields, 0, NULL );
2723 // some mods compiled with scrambling compilers lack certain critical
2724 // global names and field names such as "self" and "time" and "nextthink"
2725 // so we have to set these offsets manually, matching the entvars_t
2726 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, angles);
2727 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, chain);
2728 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, classname);
2729 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, frame);
2730 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, groundentity);
2731 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ideal_yaw);
2732 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, nextthink);
2733 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, think);
2734 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, yaw_speed);
2735 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, self);
2736 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, time);
2737 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_forward);
2738 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_right);
2739 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_up);
2740 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_allsolid);
2741 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_startsolid);
2742 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_fraction);
2743 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inwater);
2744 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inopen);
2745 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_endpos);
2746 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_normal);
2747 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_dist);
2748 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_ent);
2749 // OP_STATE is always supported on server (due to entvars_t)
2750 prog->flag |= PRVM_OP_STATE;
2752 VM_CustomStats_Clear();//[515]: csqc
2753 EntityFrameCSQC_ClearVersions();//[515]: csqc
2757 // 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
2758 sv.csqc_progname[0] = 0;
2759 sv.csqc_progcrc = FS_CRCFile(csqc_progname.string, &csprogsdatasize);
2760 sv.csqc_progsize = csprogsdatasize;
2761 if (sv.csqc_progsize > 0)
2763 strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
2764 Con_DPrintf("server detected csqc progs file \"%s\" with size %i and crc %i\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
2768 void SV_VM_Begin(void)
2771 PRVM_SetProg( PRVM_SERVERPROG );
2773 prog->globals.server->time = (float) sv.time;
2776 void SV_VM_End(void)