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_AutoSentStats_Clear (void);
29 void EntityFrameCSQC_ClearVersions (void);
30 void EntityFrameCSQC_InitClientVersions (int client, qboolean clear);
31 void VM_SV_WriteAutoSentStats (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);
218 Make sure the event gets sent to all clients
221 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
223 if (modelindex >= 256 || startframe >= 256)
225 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
227 MSG_WriteByte (&sv.datagram, svc_effect2);
228 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
229 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
230 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
231 MSG_WriteShort (&sv.datagram, modelindex);
232 MSG_WriteShort (&sv.datagram, startframe);
233 MSG_WriteByte (&sv.datagram, framecount);
234 MSG_WriteByte (&sv.datagram, framerate);
238 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
240 MSG_WriteByte (&sv.datagram, svc_effect);
241 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
242 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
243 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
244 MSG_WriteByte (&sv.datagram, modelindex);
245 MSG_WriteByte (&sv.datagram, startframe);
246 MSG_WriteByte (&sv.datagram, framecount);
247 MSG_WriteByte (&sv.datagram, framerate);
255 Each entity can have eight independant sound sources, like voice,
258 Channel 0 is an auto-allocate channel, the others override anything
259 already running on that entity/channel pair.
261 An attenuation of 0 will play full volume everywhere in the level.
262 Larger attenuations will drop off. (max 4 attenuation)
266 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
268 int sound_num, field_mask, i, ent;
270 if (volume < 0 || volume > 255)
272 Con_Printf ("SV_StartSound: volume = %i\n", volume);
276 if (attenuation < 0 || attenuation > 4)
278 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
282 if (channel < 0 || channel > 7)
284 Con_Printf ("SV_StartSound: channel = %i\n", channel);
288 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
291 // find precache number for sound
292 sound_num = SV_SoundIndex(sample, 1);
296 ent = PRVM_NUM_FOR_EDICT(entity);
299 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
300 field_mask |= SND_VOLUME;
301 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
302 field_mask |= SND_ATTENUATION;
304 field_mask |= SND_LARGEENTITY;
305 if (sound_num >= 256 || channel >= 8)
306 field_mask |= SND_LARGESOUND;
308 // directed messages go only to the entity they are targeted on
309 MSG_WriteByte (&sv.datagram, svc_sound);
310 MSG_WriteByte (&sv.datagram, field_mask);
311 if (field_mask & SND_VOLUME)
312 MSG_WriteByte (&sv.datagram, volume);
313 if (field_mask & SND_ATTENUATION)
314 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
315 if (field_mask & SND_LARGEENTITY)
317 MSG_WriteShort (&sv.datagram, ent);
318 MSG_WriteByte (&sv.datagram, channel);
321 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
322 if (field_mask & SND_LARGESOUND)
323 MSG_WriteShort (&sv.datagram, sound_num);
325 MSG_WriteByte (&sv.datagram, sound_num);
326 for (i = 0;i < 3;i++)
327 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
331 ==============================================================================
335 ==============================================================================
342 Sends the first message from the server to a connected client.
343 This will be sent on the initial connection and upon each server load.
346 void SV_SendServerinfo (client_t *client)
351 // we know that this client has a netconnection and thus is not a bot
353 // edicts get reallocated on level changes, so we need to update it here
354 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
356 // clear cached stuff that depends on the level
357 client->weaponmodel[0] = 0;
358 client->weaponmodelindex = 0;
360 // LordHavoc: clear entityframe tracking
361 client->latestframenum = 0;
363 if (client->entitydatabase)
364 EntityFrame_FreeDatabase(client->entitydatabase);
365 if (client->entitydatabase4)
366 EntityFrame4_FreeDatabase(client->entitydatabase4);
367 if (client->entitydatabase5)
368 EntityFrame5_FreeDatabase(client->entitydatabase5);
370 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
372 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
373 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
374 else if (sv.protocol == PROTOCOL_DARKPLACES4)
375 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
377 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
380 SZ_Clear (&client->netconnection->message);
381 MSG_WriteByte (&client->netconnection->message, svc_print);
382 dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
383 MSG_WriteString (&client->netconnection->message,message);
385 //[515]: init csprogs according to version of svprogs, check the crc, etc.
386 if (sv.csqc_progname[0])
389 Con_DPrintf("sending csqc info to client (\"%s\" with size %i and crc %i)\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
390 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
391 MSG_WriteString (&client->netconnection->message, va("csqc_progname %s\n", sv.csqc_progname));
392 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
393 MSG_WriteString (&client->netconnection->message, va("csqc_progsize %i\n", sv.csqc_progsize));
394 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
395 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", sv.csqc_progcrc));
396 //[515]: init stufftext string (it is sent before svc_serverinfo)
397 val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.SV_InitCmd);
400 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
401 MSG_WriteString (&client->netconnection->message, va("%s\n", PRVM_GetString(val->string)));
405 if (sv_allowdownloads.integer)
407 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
408 MSG_WriteString (&client->netconnection->message, "cl_serverextension_download 1");
411 // send at this time so it's guaranteed to get executed at the right time
415 host_client = client;
416 Curl_SendRequirements();
420 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
421 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
422 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
424 if (!coop.integer && deathmatch.integer)
425 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
427 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
429 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
431 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
432 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
433 MSG_WriteByte (&client->netconnection->message, 0);
435 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
436 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
437 MSG_WriteByte (&client->netconnection->message, 0);
440 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
441 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
442 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
445 MSG_WriteByte (&client->netconnection->message, svc_setview);
446 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
448 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
449 MSG_WriteByte (&client->netconnection->message, 1);
451 client->spawned = false; // need prespawn, spawn, etc
453 // clear movement info until client enters the new level properly
454 memset(&client->cmd, 0, sizeof(client->cmd));
455 client->movesequence = 0;
456 #ifdef NUM_PING_TIMES
457 for (i = 0;i < NUM_PING_TIMES;i++)
458 client->ping_times[i] = 0;
459 client->num_pings = 0;
468 Initializes a client_t for a new net connection. This will only be called
469 once for a player each game, not once for each level change.
472 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
476 float spawn_parms[NUM_SPAWN_PARMS];
478 client = svs.clients + clientnum;
480 if(netconnection)//[515]: bots don't play with csqc =)
481 EntityFrameCSQC_InitClientVersions(clientnum, false);
483 // set up the client_t
485 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
486 memset (client, 0, sizeof(*client));
487 client->active = true;
488 client->netconnection = netconnection;
490 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
492 strlcpy(client->name, "unconnected", sizeof(client->name));
493 strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
494 client->spawned = false;
495 client->edict = PRVM_EDICT_NUM(clientnum+1);
496 if (client->netconnection)
497 client->netconnection->message.allowoverflow = true; // we can catch it
498 // updated by receiving "rate" command from client
499 client->rate = NET_MINRATE;
500 // no limits for local player
501 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
502 client->rate = 1000000000;
503 client->connecttime = realtime;
506 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
509 // call the progs to get default spawn parms for the new client
510 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
511 prog->globals.server->self = 0;
512 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
513 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
514 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
516 // set up the entity for this client (including .colormap, .team, etc)
517 PRVM_ED_ClearEdict(client->edict);
520 // don't call SendServerinfo for a fresh botclient because its fields have
521 // not been set up by the qc yet
522 if (client->netconnection)
523 SV_SendServerinfo (client);
525 client->spawned = true;
530 ===============================================================================
534 ===============================================================================
543 void SV_ClearDatagram (void)
545 SZ_Clear (&sv.datagram);
549 =============================================================================
551 The PVS must include a small area around the client to allow head bobbing
552 or other small motion on the client side. Otherwise, a bob might cause an
553 entity that should be visible to not show up, especially when the bob
556 =============================================================================
559 int sv_writeentitiestoclient_pvsbytes;
560 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
562 static int numsendentities;
563 static entity_state_t sendentities[MAX_EDICTS];
564 static entity_state_t *sendentitiesindex[MAX_EDICTS];
566 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
569 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
570 unsigned int customizeentityforclient;
572 vec3_t cullmins, cullmaxs;
576 // EF_NODRAW prevents sending for any reason except for your own
577 // client, so we must keep all clients in this superset
578 effects = (unsigned)ent->fields.server->effects;
580 // we can omit invisible entities with no effects that are not clients
581 // LordHavoc: this could kill tags attached to an invisible entity, I
582 // just hope we never have to support that case
583 i = (int)ent->fields.server->modelindex;
584 modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
587 i = (int)(PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_size)->_float * 0.25f);
588 glowsize = (unsigned char)bound(0, i, 255);
589 if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_trail)->_float)
590 flags |= RENDER_GLOWTRAIL;
592 f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[0]*256;
593 light[0] = (unsigned short)bound(0, f, 65535);
594 f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[1]*256;
595 light[1] = (unsigned short)bound(0, f, 65535);
596 f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[2]*256;
597 light[2] = (unsigned short)bound(0, f, 65535);
598 f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.light_lev)->_float;
599 light[3] = (unsigned short)bound(0, f, 65535);
600 lightstyle = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.style)->_float;
601 lightpflags = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.pflags)->_float;
603 if (gamemode == GAME_TENEBRAE)
605 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
609 lightpflags |= PFLAGS_FULLDYNAMIC;
611 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
615 light[0] = (int)(0.2*256);
616 light[1] = (int)(1.0*256);
617 light[2] = (int)(0.2*256);
619 lightpflags |= PFLAGS_FULLDYNAMIC;
623 specialvisibilityradius = 0;
624 if (lightpflags & PFLAGS_FULLDYNAMIC)
625 specialvisibilityradius = max(specialvisibilityradius, light[3]);
627 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
628 if (flags & RENDER_GLOWTRAIL)
629 specialvisibilityradius = max(specialvisibilityradius, 100);
630 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
632 if (effects & EF_BRIGHTFIELD)
633 specialvisibilityradius = max(specialvisibilityradius, 80);
634 if (effects & EF_MUZZLEFLASH)
635 specialvisibilityradius = max(specialvisibilityradius, 100);
636 if (effects & EF_BRIGHTLIGHT)
637 specialvisibilityradius = max(specialvisibilityradius, 400);
638 if (effects & EF_DIMLIGHT)
639 specialvisibilityradius = max(specialvisibilityradius, 200);
640 if (effects & EF_RED)
641 specialvisibilityradius = max(specialvisibilityradius, 200);
642 if (effects & EF_BLUE)
643 specialvisibilityradius = max(specialvisibilityradius, 200);
644 if (effects & EF_FLAME)
645 specialvisibilityradius = max(specialvisibilityradius, 250);
646 if (effects & EF_STARDUST)
647 specialvisibilityradius = max(specialvisibilityradius, 100);
650 // early culling checks
651 // (final culling is done by SV_MarkWriteEntityStateToClient)
652 customizeentityforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.customizeentityforclient)->function;
653 if (!customizeentityforclient)
655 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
657 // this 2 billion unit check is actually to detect NAN origins
658 // (we really don't want to send those)
659 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
667 VectorCopy(ent->fields.server->origin, cs->origin);
668 VectorCopy(ent->fields.server->angles, cs->angles);
670 cs->effects = effects;
671 cs->colormap = (unsigned)ent->fields.server->colormap;
672 cs->modelindex = modelindex;
673 cs->skin = (unsigned)ent->fields.server->skin;
674 cs->frame = (unsigned)ent->fields.server->frame;
675 cs->viewmodelforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)->edict;
676 cs->exteriormodelforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.exteriormodeltoclient)->edict;
677 cs->nodrawtoclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.nodrawtoclient)->edict;
678 cs->drawonlytoclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.drawonlytoclient)->edict;
679 cs->customizeentityforclient = customizeentityforclient;
680 cs->tagentity = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)->edict;
681 cs->tagindex = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float;
682 cs->glowsize = glowsize;
684 // don't need to init cs->colormod because the defaultstate did that for us
685 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
686 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod);
687 if (val->vector[0] || val->vector[1] || val->vector[2])
689 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
690 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
691 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
694 cs->modelindex = modelindex;
697 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)->_float * 255.0f);
701 cs->alpha = (unsigned char)bound(0, i, 255);
704 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderamt)->_float);
708 cs->alpha = (unsigned char)bound(0, i, 255);
712 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)->_float * 16.0f);
716 cs->scale = (unsigned char)bound(0, i, 255);
720 f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_color)->_float);
722 cs->glowcolor = (int)f;
724 if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.fullbright)->_float)
725 cs->effects |= EF_FULLBRIGHT;
727 if (ent->fields.server->movetype == MOVETYPE_STEP)
728 cs->flags |= RENDER_STEP;
729 if ((cs->effects & EF_LOWPRECISION) && cs->origin[0] >= -32768 && cs->origin[1] >= -32768 && cs->origin[2] >= -32768 && cs->origin[0] <= 32767 && cs->origin[1] <= 32767 && cs->origin[2] <= 32767)
730 cs->flags |= RENDER_LOWPRECISION;
731 if (ent->fields.server->colormap >= 1024)
732 cs->flags |= RENDER_COLORMAPPED;
733 if (cs->viewmodelforclient)
734 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
736 cs->light[0] = light[0];
737 cs->light[1] = light[1];
738 cs->light[2] = light[2];
739 cs->light[3] = light[3];
740 cs->lightstyle = lightstyle;
741 cs->lightpflags = lightpflags;
743 cs->specialvisibilityradius = specialvisibilityradius;
745 // calculate the visible box of this entity (don't use the physics box
746 // as that is often smaller than a model, and would not count
747 // specialvisibilityradius)
748 if ((model = sv.models[modelindex]))
750 float scale = cs->scale * (1.0f / 16.0f);
751 if (cs->angles[0] || cs->angles[2]) // pitch and roll
753 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
754 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
756 else if (cs->angles[1])
758 VectorMA(cs->origin, scale, model->yawmins, cullmins);
759 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
763 VectorMA(cs->origin, scale, model->normalmins, cullmins);
764 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
769 // if there is no model (or it could not be loaded), use the physics box
770 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
771 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
773 if (specialvisibilityradius)
775 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
776 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
777 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
778 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
779 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
780 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
782 // calculate center of bbox for network prioritization purposes
783 VectorMAM(0.5f, cullmins, 0.5f, cullmaxs, cs->netcenter);
784 // if culling box has moved, update pvs cluster links
785 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
787 VectorCopy(cullmins, ent->priv.server->cullmins);
788 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
789 // a value of -1 for pvs_numclusters indicates that the links are not
790 // cached, and should be re-tested each time, this is the case if the
791 // culling box touches too many pvs clusters to store, or if the world
792 // model does not support FindBoxClusters
793 ent->priv.server->pvs_numclusters = -1;
794 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
796 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
797 if (i <= MAX_ENTITYCLUSTERS)
798 ent->priv.server->pvs_numclusters = i;
805 void SV_PrepareEntitiesForSending(void)
809 // send all entities that touch the pvs
811 sendentitiesindex[0] = NULL;
812 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
813 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
815 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
817 sendentitiesindex[e] = sendentities + numsendentities;
823 static int sententitiesmark = 0;
824 static int sententities[MAX_EDICTS];
825 static int sententitiesconsideration[MAX_EDICTS];
826 static int sv_writeentitiestoclient_culled_pvs;
827 static int sv_writeentitiestoclient_culled_trace;
828 static int sv_writeentitiestoclient_visibleentities;
829 static int sv_writeentitiestoclient_totalentities;
830 //static entity_frame_t sv_writeentitiestoclient_entityframe;
831 static int sv_writeentitiestoclient_clentnum;
832 static vec3_t sv_writeentitiestoclient_testeye;
833 static client_t *sv_writeentitiestoclient_client;
835 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
840 if (sententitiesconsideration[s->number] == sententitiesmark)
842 sententitiesconsideration[s->number] = sententitiesmark;
843 sv_writeentitiestoclient_totalentities++;
845 if (s->customizeentityforclient)
847 prog->globals.server->self = s->number;
848 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
849 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
850 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
854 // never reject player
855 if (s->number != sv_writeentitiestoclient_clentnum)
857 // check various rejection conditions
858 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
860 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
862 if (s->effects & EF_NODRAW)
864 // LordHavoc: only send entities with a model or important effects
865 if (!s->modelindex && s->specialvisibilityradius == 0)
868 isbmodel = (model = sv.models[s->modelindex]) != NULL && model->name[0] == '*';
869 // viewmodels don't have visibility checking
870 if (s->viewmodelforclient)
872 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
875 else if (s->tagentity)
877 // tag attached entities simply check their parent
878 if (!sendentitiesindex[s->tagentity])
880 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
881 if (sententities[s->tagentity] != sententitiesmark)
884 // always send world submodels in newer protocols because they don't
885 // generate much traffic (in old protocols they hog bandwidth)
886 // but only if sv_cullentities_alwayssendbmodels is on
887 else if (!(s->effects & EF_NODEPTHTEST) && (!isbmodel || !sv_cullentities_nevercullbmodels.integer || sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE))
889 // entity has survived every check so far, check if visible
890 ed = PRVM_EDICT_NUM(s->number);
892 // if not touching a visible leaf
893 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
895 if (ed->priv.server->pvs_numclusters < 0)
897 // entity too big for clusters list
898 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
900 sv_writeentitiestoclient_culled_pvs++;
907 // check cached clusters list
908 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
909 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
911 if (i == ed->priv.server->pvs_numclusters)
913 sv_writeentitiestoclient_culled_pvs++;
919 // or not seen by random tracelines
920 if (sv_cullentities_trace.integer && !isbmodel)
922 int samples = s->specialvisibilityradius ? sv_cullentities_trace_samples_extra.integer : sv_cullentities_trace_samples.integer;
923 float enlarge = sv_cullentities_trace_enlarge.value;
925 qboolean visible = TRUE;
929 if(Mod_CanSeeBox_Trace(samples, enlarge, sv.worldmodel, sv_writeentitiestoclient_testeye, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
930 break; // directly visible from the server's view
932 if(sv_cullentities_trace_prediction.integer)
936 // get player velocity
937 float predtime = bound(0, host_client->ping, 0.2); // / 2
938 // sorry, no wallhacking by high ping please, and at 200ms
939 // ping a FPS is annoying to play anyway and a player is
940 // likely to have changed his direction
941 VectorMA(sv_writeentitiestoclient_testeye, predtime, host_client->edict->fields.server->velocity, predeye);
942 if(sv.worldmodel->brush.TraceLineOfSight(sv.worldmodel, sv_writeentitiestoclient_testeye, predeye)) // must be able to go there...
944 if(Mod_CanSeeBox_Trace(samples, enlarge, sv.worldmodel, predeye, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
945 break; // directly visible from the predicted view
949 //Con_DPrintf("Trying to walk into solid in a pingtime... not predicting for culling\n");
953 // when we get here, we can't see the entity
959 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + sv_cullentities_trace_delay.value;
961 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
963 sv_writeentitiestoclient_culled_trace++;
970 // this just marks it for sending
971 // FIXME: it would be more efficient to send here, but the entity
972 // compressor isn't that flexible
973 sv_writeentitiestoclient_visibleentities++;
974 sententities[s->number] = sententitiesmark;
977 entity_state_t sendstates[MAX_EDICTS];
978 extern int csqc_clent;
980 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
982 int i, numsendstates;
985 // if there isn't enough space to accomplish anything, skip it
986 if (msg->cursize + 25 > msg->maxsize)
989 sv_writeentitiestoclient_client = client;
991 sv_writeentitiestoclient_culled_pvs = 0;
992 sv_writeentitiestoclient_culled_trace = 0;
993 sv_writeentitiestoclient_visibleentities = 0;
994 sv_writeentitiestoclient_totalentities = 0;
996 // find the client's PVS
997 // the real place being tested from
998 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
999 sv_writeentitiestoclient_pvsbytes = 0;
1000 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
1001 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
1003 csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
1007 for (i = 0;i < numsendentities;i++)
1008 SV_MarkWriteEntityStateToClient(sendentities + i);
1011 for (i = 0;i < numsendentities;i++)
1013 if (sententities[sendentities[i].number] == sententitiesmark)
1015 s = &sendstates[numsendstates++];
1016 *s = sendentities[i];
1017 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
1018 s->flags |= RENDER_EXTERIORMODEL;
1022 if (sv_cullentities_stats.integer)
1023 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);
1025 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
1027 if (client->entitydatabase5)
1028 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
1029 else if (client->entitydatabase4)
1030 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
1031 else if (client->entitydatabase)
1032 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
1034 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
1043 void SV_CleanupEnts (void)
1048 ent = PRVM_NEXT_EDICT(prog->edicts);
1049 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
1050 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
1055 SV_WriteClientdataToMessage
1059 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1063 prvm_edict_t *other;
1071 // send a damage message
1073 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
1075 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
1076 MSG_WriteByte (msg, svc_damage);
1077 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
1078 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
1079 for (i=0 ; i<3 ; i++)
1080 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
1082 ent->fields.server->dmg_take = 0;
1083 ent->fields.server->dmg_save = 0;
1087 // send the current viewpos offset from the view entity
1089 SV_SetIdealPitch (); // how much to look up / down ideally
1091 // a fixangle might get lost in a dropped packet. Oh well.
1092 if ( ent->fields.server->fixangle )
1094 MSG_WriteByte (msg, svc_setangle);
1095 for (i=0 ; i < 3 ; i++)
1096 MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
1097 ent->fields.server->fixangle = 0;
1100 // stuff the sigil bits into the high bits of items for sbar, or else
1102 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.items2);
1103 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1104 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1106 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1108 VectorClear(punchvector);
1109 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.punchvector)))
1110 VectorCopy(val->vector, punchvector);
1112 // cache weapon model name and index in client struct to save time
1113 // (this search can be almost 1% of cpu time!)
1114 s = PRVM_GetString(ent->fields.server->weaponmodel);
1115 if (strcmp(s, client->weaponmodel))
1117 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1118 client->weaponmodelindex = SV_ModelIndex(s, 1);
1122 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewzoom)))
1123 viewzoom = (int)(val->_float * 255.0f);
1129 if ((int)ent->fields.server->flags & FL_ONGROUND)
1130 bits |= SU_ONGROUND;
1131 if (ent->fields.server->waterlevel >= 2)
1133 if (ent->fields.server->idealpitch)
1134 bits |= SU_IDEALPITCH;
1136 for (i=0 ; i<3 ; i++)
1138 if (ent->fields.server->punchangle[i])
1139 bits |= (SU_PUNCH1<<i);
1140 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1142 bits |= (SU_PUNCHVEC1<<i);
1143 if (ent->fields.server->velocity[i])
1144 bits |= (SU_VELOCITY1<<i);
1147 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1148 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1149 stats[STAT_ITEMS] = items;
1150 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1151 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1152 stats[STAT_WEAPON] = client->weaponmodelindex;
1153 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1154 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1155 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1156 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1157 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1158 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1159 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1160 stats[STAT_VIEWZOOM] = viewzoom;
1161 stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1162 stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1163 // the QC bumps these itself by sending svc_'s, so we have to keep them
1164 // zero or they'll be corrected by the engine
1165 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1166 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1168 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)
1170 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1172 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1173 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1175 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1176 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1177 if (viewzoom != 255)
1178 bits |= SU_VIEWZOOM;
1183 if (bits >= 16777216)
1187 MSG_WriteByte (msg, svc_clientdata);
1188 MSG_WriteShort (msg, bits);
1189 if (bits & SU_EXTEND1)
1190 MSG_WriteByte(msg, bits >> 16);
1191 if (bits & SU_EXTEND2)
1192 MSG_WriteByte(msg, bits >> 24);
1194 if (bits & SU_VIEWHEIGHT)
1195 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1197 if (bits & SU_IDEALPITCH)
1198 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1200 for (i=0 ; i<3 ; i++)
1202 if (bits & (SU_PUNCH1<<i))
1204 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1205 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1207 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1209 if (bits & (SU_PUNCHVEC1<<i))
1211 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1212 MSG_WriteCoord16i(msg, punchvector[i]);
1214 MSG_WriteCoord32f(msg, punchvector[i]);
1216 if (bits & (SU_VELOCITY1<<i))
1218 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1219 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1221 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1225 if (bits & SU_ITEMS)
1226 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1228 if (sv.protocol == PROTOCOL_DARKPLACES5)
1230 if (bits & SU_WEAPONFRAME)
1231 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1232 if (bits & SU_ARMOR)
1233 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1234 if (bits & SU_WEAPON)
1235 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1236 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1237 MSG_WriteShort (msg, stats[STAT_AMMO]);
1238 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1239 MSG_WriteShort (msg, stats[STAT_NAILS]);
1240 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1241 MSG_WriteShort (msg, stats[STAT_CELLS]);
1242 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1243 if (bits & SU_VIEWZOOM)
1244 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1246 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)
1248 if (bits & SU_WEAPONFRAME)
1249 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1250 if (bits & SU_ARMOR)
1251 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1252 if (bits & SU_WEAPON)
1253 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1254 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1255 MSG_WriteByte (msg, stats[STAT_AMMO]);
1256 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1257 MSG_WriteByte (msg, stats[STAT_NAILS]);
1258 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1259 MSG_WriteByte (msg, stats[STAT_CELLS]);
1260 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1262 for (i = 0;i < 32;i++)
1263 if (stats[STAT_WEAPON] & (1<<i))
1265 MSG_WriteByte (msg, i);
1268 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1269 if (bits & SU_VIEWZOOM)
1271 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1272 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1274 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1280 =======================
1281 SV_SendClientDatagram
1282 =======================
1284 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1285 void SV_SendClientDatagram (client_t *client)
1287 int rate, maxrate, maxsize, maxsize2, downloadsize;
1289 int stats[MAX_CL_STATS];
1291 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1293 // for good singleplayer, send huge packets
1294 maxsize = sizeof(sv_sendclientdatagram_buf);
1295 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1297 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)
1299 // no rate limiting support on older protocols because dp protocols
1300 // 1-4 kick the client off if they overflow, and quake protocol shows
1301 // less than the full entity set if rate limited
1307 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1308 maxrate = max(NET_MINRATE, sv_maxrate.integer);
1309 if (sv_maxrate.integer != maxrate)
1310 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1312 // this rate limiting does not understand sys_ticrate 0
1313 // (but no one should be running that on a server!)
1314 rate = bound(NET_MINRATE, client->rate, maxrate);
1315 rate = (int)(rate * sys_ticrate.value);
1316 maxsize = bound(50, rate, 1400);
1320 // while downloading, limit entity updates to half the packet
1321 // (any leftover space will be used for downloading)
1322 if (host_client->download_file)
1325 msg.data = sv_sendclientdatagram_buf;
1326 msg.maxsize = maxsize;
1329 if (host_client->spawned)
1331 MSG_WriteByte (&msg, svc_time);
1332 MSG_WriteFloat (&msg, sv.time);
1334 // add the client specific data to the datagram
1335 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1336 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1337 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1339 // expand packet size to allow effects to go over the rate limit
1340 // (dropping them is FAR too ugly)
1341 msg.maxsize = maxsize2;
1343 // copy the server datagram if there is space
1344 // FIXME: put in delayed queue of effects to send
1345 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1346 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1348 else if (realtime > client->keepalivetime)
1350 // the player isn't totally in the game yet
1351 // send small keepalive messages if too much time has passed
1352 msg.maxsize = maxsize2;
1353 client->keepalivetime = realtime + 5;
1354 MSG_WriteChar (&msg, svc_nop);
1357 msg.maxsize = maxsize2;
1359 // if a download is active, see if there is room to fit some download data
1361 downloadsize = maxsize * 2 - msg.cursize - 7;
1362 if (host_client->download_file && host_client->download_started && downloadsize > 0)
1364 fs_offset_t downloadstart;
1365 unsigned char data[1400];
1366 downloadstart = FS_Tell(host_client->download_file);
1367 downloadsize = min(downloadsize, (int)sizeof(data));
1368 downloadsize = FS_Read(host_client->download_file, data, downloadsize);
1369 // note this sends empty messages if at the end of the file, which is
1370 // necessary to keep the packet loss logic working
1371 // (the last blocks may be lost and need to be re-sent, and that will
1372 // only occur if the client acks the empty end messages, revealing
1373 // a gap in the download progress, causing the last blocks to be
1375 MSG_WriteChar (&msg, svc_downloaddata);
1376 MSG_WriteLong (&msg, downloadstart);
1377 MSG_WriteShort (&msg, downloadsize);
1378 if (downloadsize > 0)
1379 SZ_Write (&msg, data, downloadsize);
1382 // send the datagram
1383 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1387 =======================
1388 SV_UpdateToReliableMessages
1389 =======================
1391 void SV_UpdateToReliableMessages (void)
1400 // check for changes to be sent over the reliable streams
1401 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1403 // update the host_client fields we care about according to the entity fields
1404 host_client->edict = PRVM_EDICT_NUM(i+1);
1407 name = PRVM_GetString(host_client->edict->fields.server->netname);
1410 // always point the string back at host_client->name to keep it safe
1411 strlcpy (host_client->name, name, sizeof (host_client->name));
1412 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1413 if (strcmp(host_client->old_name, host_client->name))
1415 if (host_client->spawned)
1416 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1417 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1418 // send notification to all clients
1419 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1420 MSG_WriteByte (&sv.reliable_datagram, i);
1421 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1424 // DP_SV_CLIENTCOLORS
1425 // this is always found (since it's added by the progs loader)
1426 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
1427 host_client->colors = (int)val->_float;
1428 if (host_client->old_colors != host_client->colors)
1430 host_client->old_colors = host_client->colors;
1431 // send notification to all clients
1432 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1433 MSG_WriteByte (&sv.reliable_datagram, i);
1434 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1437 // NEXUIZ_PLAYERMODEL
1438 if( prog->fieldoffsets.playermodel >= 0 ) {
1439 model = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string);
1442 // always point the string back at host_client->name to keep it safe
1443 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1444 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1447 // NEXUIZ_PLAYERSKIN
1448 if( prog->fieldoffsets.playerskin >= 0 ) {
1449 skin = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string);
1452 // always point the string back at host_client->name to keep it safe
1453 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1454 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1458 host_client->frags = (int)host_client->edict->fields.server->frags;
1459 if (host_client->old_frags != host_client->frags)
1461 host_client->old_frags = host_client->frags;
1462 // send notification to all clients
1463 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1464 MSG_WriteByte (&sv.reliable_datagram, i);
1465 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1469 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1470 if (client->netconnection)
1471 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1473 SZ_Clear (&sv.reliable_datagram);
1478 =======================
1479 SV_SendClientMessages
1480 =======================
1482 void SV_SendClientMessages (void)
1484 int i, prepared = false;
1486 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1487 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1489 // update frags, names, etc
1490 SV_UpdateToReliableMessages();
1492 // build individual updates
1493 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1495 if (!host_client->active)
1497 if (!host_client->netconnection)
1500 if (host_client->netconnection->message.overflowed)
1502 SV_DropClient (true); // if the message couldn't send, kick off
1509 // only prepare entities once per frame
1510 SV_PrepareEntitiesForSending();
1512 SV_SendClientDatagram (host_client);
1515 // clear muzzle flashes
1519 void SV_StartDownload_f(void)
1521 if (host_client->download_file)
1522 host_client->download_started = true;
1525 void SV_Download_f(void)
1527 const char *whichpack, *whichpack2, *extension;
1529 if (Cmd_Argc() != 2)
1531 SV_ClientPrintf("usage: download <filename>\n");
1535 if (FS_CheckNastyPath(Cmd_Argv(1), false))
1537 SV_ClientPrintf("Download rejected: nasty filename \"%s\"\n", Cmd_Argv(1));
1541 if (host_client->download_file)
1543 // at this point we'll assume the previous download should be aborted
1544 Con_DPrintf("Download of %s aborted by %s starting a new download\n", host_client->download_name, host_client->name);
1545 Host_ClientCommands("\nstopdownload\n");
1547 // close the file and reset variables
1548 FS_Close(host_client->download_file);
1549 host_client->download_file = NULL;
1550 host_client->download_name[0] = 0;
1551 host_client->download_expectedposition = 0;
1552 host_client->download_started = false;
1555 if (!sv_allowdownloads.integer)
1557 SV_ClientPrintf("Downloads are disabled on this server\n");
1558 Host_ClientCommands("\nstopdownload\n");
1562 strlcpy(host_client->download_name, Cmd_Argv(1), sizeof(host_client->download_name));
1563 extension = FS_FileExtension(host_client->download_name);
1565 // host_client is asking to download a specified file
1566 if (developer.integer >= 100)
1567 Con_Printf("Download request for %s by %s\n", host_client->download_name, host_client->name);
1569 if (!FS_FileExists(host_client->download_name))
1571 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);
1572 Host_ClientCommands("\nstopdownload\n");
1576 // check if the user is trying to download part of registered Quake(r)
1577 whichpack = FS_WhichPack(host_client->download_name);
1578 whichpack2 = FS_WhichPack("gfx/pop.lmp");
1579 if ((whichpack && whichpack2 && !strcasecmp(whichpack, whichpack2)) || FS_IsRegisteredQuakePack(host_client->download_name))
1581 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);
1582 Host_ClientCommands("\nstopdownload\n");
1586 // check if the server has forbidden archive downloads entirely
1587 if (!sv_allowdownloads_inarchive.integer)
1589 whichpack = FS_WhichPack(host_client->download_name);
1592 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);
1593 Host_ClientCommands("\nstopdownload\n");
1598 if (!sv_allowdownloads_config.integer)
1600 if (!strcasecmp(extension, "cfg"))
1602 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);
1603 Host_ClientCommands("\nstopdownload\n");
1608 if (!sv_allowdownloads_dlcache.integer)
1610 if (!strncasecmp(host_client->download_name, "dlcache/", 8))
1612 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);
1613 Host_ClientCommands("\nstopdownload\n");
1618 if (!sv_allowdownloads_archive.integer)
1620 if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
1622 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);
1623 Host_ClientCommands("\nstopdownload\n");
1628 host_client->download_file = FS_Open(host_client->download_name, "rb", true, false);
1629 if (!host_client->download_file)
1631 SV_ClientPrintf("Download rejected: server could not open the file \"%s\"\n", host_client->download_name);
1632 Host_ClientCommands("\nstopdownload\n");
1636 if (FS_FileSize(host_client->download_file) > 1<<30)
1638 SV_ClientPrintf("Download rejected: file \"%s\" is very large\n", host_client->download_name);
1639 Host_ClientCommands("\nstopdownload\n");
1640 FS_Close(host_client->download_file);
1641 host_client->download_file = NULL;
1645 Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
1647 Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name);
1649 host_client->download_expectedposition = 0;
1650 host_client->download_started = false;
1652 // the rest of the download process is handled in SV_SendClientDatagram
1653 // and other code dealing with svc_downloaddata and clc_ackdownloaddata
1655 // no svc_downloaddata messages will be sent until sv_startdownload is
1656 // sent by the client
1660 ==============================================================================
1664 ==============================================================================
1673 int SV_ModelIndex(const char *s, int precachemode)
1675 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1676 char filename[MAX_QPATH];
1680 //if (precachemode == 2)
1682 strlcpy(filename, s, sizeof(filename));
1683 for (i = 2;i < limit;i++)
1685 if (!sv.model_precache[i][0])
1689 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))
1691 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1694 if (precachemode == 1)
1695 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1696 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1697 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1698 if (sv.state != ss_loading)
1700 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1701 MSG_WriteShort(&sv.reliable_datagram, i);
1702 MSG_WriteString(&sv.reliable_datagram, filename);
1706 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1709 if (!strcmp(sv.model_precache[i], filename))
1712 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1722 int SV_SoundIndex(const char *s, int precachemode)
1724 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1725 char filename[MAX_QPATH];
1729 //if (precachemode == 2)
1731 strlcpy(filename, s, sizeof(filename));
1732 for (i = 1;i < limit;i++)
1734 if (!sv.sound_precache[i][0])
1738 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))
1740 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1743 if (precachemode == 1)
1744 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1745 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1746 if (sv.state != ss_loading)
1748 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1749 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1750 MSG_WriteString(&sv.reliable_datagram, filename);
1754 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1757 if (!strcmp(sv.sound_precache[i], filename))
1760 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1764 // MUST match effectnameindex_t in client.h
1765 static const char *standardeffectnames[EFFECT_TOTAL] =
1773 "TE_SUPERSPIKEQUAD",
1789 "TE_TEI_BIGEXPLOSION",
1807 SV_ParticleEffectIndex
1811 int SV_ParticleEffectIndex(const char *name)
1813 int i, argc, linenumber, effectnameindex;
1814 fs_offset_t filesize;
1815 unsigned char *filedata;
1816 const char *text, *textstart, *textend;
1817 char argv[16][1024];
1818 if (!sv.particleeffectnamesloaded)
1820 sv.particleeffectnamesloaded = true;
1821 memset(sv.particleeffectname, 0, sizeof(sv.particleeffectname));
1822 for (i = 0;i < EFFECT_TOTAL;i++)
1823 strlcpy(sv.particleeffectname[i], standardeffectnames[i], sizeof(sv.particleeffectname[i]));
1824 filedata = FS_LoadFile("effectinfo.txt", tempmempool, true, &filesize);
1827 textstart = (const char *)filedata;
1828 textend = (const char *)filedata + filesize;
1830 for (linenumber = 1;;linenumber++)
1835 if (!COM_ParseToken(&text, true) || !strcmp(com_token, "\n"))
1839 strlcpy(argv[argc], com_token, sizeof(argv[argc]));
1843 if (com_token[0] == 0)
1844 break; // if the loop exited and it's not a \n, it's EOF
1847 if (!strcmp(argv[0], "effect"))
1851 for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME;effectnameindex++)
1853 if (sv.particleeffectname[effectnameindex][0])
1855 if (!strcmp(sv.particleeffectname[effectnameindex], argv[1]))
1860 strlcpy(sv.particleeffectname[effectnameindex], argv[1], sizeof(sv.particleeffectname[effectnameindex]));
1864 // if we run out of names, abort
1865 if (effectnameindex == SV_MAX_PARTICLEEFFECTNAME)
1867 Con_Printf("effectinfo.txt:%i: too many effects!\n", linenumber);
1876 // search for the name
1877 for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME && sv.particleeffectname[effectnameindex][0];effectnameindex++)
1878 if (!strcmp(sv.particleeffectname[effectnameindex], name))
1879 return effectnameindex;
1880 // return 0 if we couldn't find it
1890 void SV_CreateBaseline (void)
1892 int i, entnum, large;
1893 prvm_edict_t *svent;
1895 // LordHavoc: clear *all* states (note just active ones)
1896 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1898 // get the current server version
1899 svent = PRVM_EDICT_NUM(entnum);
1901 // LordHavoc: always clear state values, whether the entity is in use or not
1902 svent->priv.server->baseline = defaultstate;
1904 if (svent->priv.server->free)
1906 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1909 // create entity baseline
1910 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1911 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1912 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1913 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1914 if (entnum > 0 && entnum <= svs.maxclients)
1916 svent->priv.server->baseline.colormap = entnum;
1917 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1921 svent->priv.server->baseline.colormap = 0;
1922 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1926 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1929 // add to the message
1931 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1933 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1934 MSG_WriteShort (&sv.signon, entnum);
1938 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1939 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1943 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1944 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1946 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1947 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1948 for (i=0 ; i<3 ; i++)
1950 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1951 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1961 Grabs the current state of each client for saving across the
1962 transition to another level
1965 void SV_SaveSpawnparms (void)
1969 svs.serverflags = (int)prog->globals.server->serverflags;
1971 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1973 if (!host_client->active)
1976 // call the progs to get default spawn parms for the new client
1977 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1978 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1979 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1980 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1984 void SV_IncreaseEdicts(void)
1988 int oldmax_edicts = prog->max_edicts;
1989 void *oldedictsengineprivate = prog->edictprivate;
1990 void *oldedictsfields = prog->edictsfields;
1991 void *oldmoved_edicts = sv.moved_edicts;
1993 if (prog->max_edicts >= MAX_EDICTS)
1996 // links don't survive the transition, so unlink everything
1997 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1999 if (!ent->priv.server->free)
2000 SV_UnlinkEdict(prog->edicts + i);
2001 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
2003 World_Clear(&sv.world);
2005 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
2006 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
2007 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
2008 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2010 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
2011 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
2013 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2015 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
2016 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
2017 // link every entity except world
2018 if (!ent->priv.server->free)
2019 SV_LinkEdict(ent, false);
2022 PR_Free(oldedictsengineprivate);
2023 PR_Free(oldedictsfields);
2024 PR_Free(oldmoved_edicts);
2031 This is called at the start of each level
2034 extern float scr_centertime_off;
2036 void SV_SpawnServer (const char *server)
2041 model_t *worldmodel;
2042 char modelname[sizeof(sv.modelname)];
2044 Con_DPrintf("SpawnServer: %s\n", server);
2046 if (cls.state != ca_dedicated)
2047 SCR_BeginLoadingPlaque();
2049 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
2050 worldmodel = Mod_ForName(modelname, false, true, true);
2051 if (!worldmodel || !worldmodel->TraceBox)
2053 Con_Printf("Couldn't load map %s\n", modelname);
2057 // let's not have any servers with no name
2058 if (hostname.string[0] == 0)
2059 Cvar_Set ("hostname", "UNNAMED");
2060 scr_centertime_off = 0;
2062 svs.changelevel_issued = false; // now safe to issue another
2064 // make the map a required file for clients
2065 Curl_ClearRequirements();
2066 Curl_RequireFile(modelname);
2069 // tell all connected clients that we are going to a new level
2074 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
2076 if (client->netconnection)
2078 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
2079 MSG_WriteString(&client->netconnection->message, "reconnect\n");
2086 NetConn_OpenServerPorts(true);
2090 // make cvars consistant
2093 Cvar_SetValue ("deathmatch", 0);
2094 // LordHavoc: it can be useful to have skills outside the range 0-3...
2095 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
2096 //Cvar_SetValue ("skill", (float)current_skill);
2097 current_skill = (int)(skill.value + 0.5);
2100 // set up the new server
2102 memset (&sv, 0, sizeof(sv));
2103 // if running a local client, make sure it doesn't try to access the last
2104 // level's data which is no longer valiud
2107 if(*sv_random_seed.string)
2109 srand(sv_random_seed.integer);
2110 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);
2117 strlcpy (sv.name, server, sizeof (sv.name));
2119 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
2120 if (sv.protocol == PROTOCOL_UNKNOWN)
2123 Protocol_Names(buffer, sizeof(buffer));
2124 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
2125 sv.protocol = PROTOCOL_QUAKE;
2130 // load progs to get entity field count
2131 //PR_LoadProgs ( sv_progs.string );
2133 // allocate server memory
2134 /*// start out with just enough room for clients and a reasonable estimate of entities
2135 prog->max_edicts = max(svs.maxclients + 1, 512);
2136 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
2138 // prvm_edict_t structures (hidden from progs)
2139 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
2140 // engine private structures (hidden from progs)
2141 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
2142 // progs fields, often accessed by server
2143 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
2144 // used by PushMove to move back pushed entities
2145 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2146 /*for (i = 0;i < prog->max_edicts;i++)
2148 ent = prog->edicts + i;
2149 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
2150 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
2153 // reset client csqc entity versions right away.
2154 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2155 EntityFrameCSQC_InitClientVersions(i, true);
2157 sv.datagram.maxsize = sizeof(sv.datagram_buf);
2158 sv.datagram.cursize = 0;
2159 sv.datagram.data = sv.datagram_buf;
2161 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
2162 sv.reliable_datagram.cursize = 0;
2163 sv.reliable_datagram.data = sv.reliable_datagram_buf;
2165 sv.signon.maxsize = sizeof(sv.signon_buf);
2166 sv.signon.cursize = 0;
2167 sv.signon.data = sv.signon_buf;
2169 // leave slots at start for clients only
2170 //prog->num_edicts = svs.maxclients+1;
2172 sv.state = ss_loading;
2173 prog->allowworldwrites = true;
2176 prog->globals.server->time = sv.time = 1.0;
2179 worldmodel->used = true;
2181 strlcpy (sv.name, server, sizeof (sv.name));
2182 strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
2183 sv.worldmodel = worldmodel;
2184 sv.models[1] = sv.worldmodel;
2187 // clear world interaction links
2189 VectorCopy(sv.worldmodel->normalmins, sv.world.areagrid_mins);
2190 VectorCopy(sv.worldmodel->normalmaxs, sv.world.areagrid_maxs);
2191 World_Clear(&sv.world);
2193 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
2195 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
2196 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
2197 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
2199 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
2200 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
2204 // load the rest of the entities
2206 // AK possible hack since num_edicts is still 0
2207 ent = PRVM_EDICT_NUM(0);
2208 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
2209 ent->priv.server->free = false;
2210 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
2211 ent->fields.server->modelindex = 1; // world model
2212 ent->fields.server->solid = SOLID_BSP;
2213 ent->fields.server->movetype = MOVETYPE_PUSH;
2214 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->mins);
2215 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->maxs);
2216 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->absmin);
2217 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->absmax);
2220 prog->globals.server->coop = coop.integer;
2222 prog->globals.server->deathmatch = deathmatch.integer;
2224 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
2226 // serverflags are for cross level information (sigils)
2227 prog->globals.server->serverflags = svs.serverflags;
2229 // we need to reset the spawned flag on all connected clients here so that
2230 // their thinks don't run during startup (before PutClientInServer)
2231 // we also need to set up the client entities now
2232 // and we need to set the ->edict pointers to point into the progs edicts
2233 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2235 host_client->spawned = false;
2236 host_client->edict = PRVM_EDICT_NUM(i + 1);
2237 PRVM_ED_ClearEdict(host_client->edict);
2240 // load replacement entity file if found
2241 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
2243 Con_Printf("Loaded maps/%s.ent\n", sv.name);
2244 PRVM_ED_LoadFromFile (entities);
2248 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
2251 // LordHavoc: clear world angles (to fix e3m3.bsp)
2252 VectorClear(prog->edicts->fields.server->angles);
2254 // all setup is completed, any further precache statements are errors
2255 sv.state = ss_active;
2256 prog->allowworldwrites = false;
2258 // run two frames to allow everything to settle
2259 for (i = 0;i < 2;i++)
2267 // create a baseline for more efficient communications
2268 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
2269 SV_CreateBaseline ();
2271 // send serverinfo to all connected clients, and set up botclients coming back from a level change
2272 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2274 if (!host_client->active)
2276 if (host_client->netconnection)
2277 SV_SendServerinfo(host_client);
2281 // if client is a botclient coming from a level change, we need to
2282 // set up client info that normally requires networking
2284 // copy spawn parms out of the client_t
2285 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
2286 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
2288 // call the spawn function
2289 host_client->clientconnectcalled = true;
2290 prog->globals.server->time = sv.time;
2291 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2292 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
2293 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
2294 host_client->spawned = true;
2298 Con_DPrint("Server spawned.\n");
2299 NetConn_Heartbeat (2);
2304 /////////////////////////////////////////////////////
2307 void SV_VM_CB_BeginIncreaseEdicts(void)
2312 PRVM_Free( sv.moved_edicts );
2313 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2315 // links don't survive the transition, so unlink everything
2316 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2318 if (!ent->priv.server->free)
2319 World_UnlinkEdict(prog->edicts + i);
2320 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
2322 World_Clear(&sv.world);
2325 void SV_VM_CB_EndIncreaseEdicts(void)
2330 // link every entity except world
2331 for (i = 1, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2332 if (!ent->priv.server->free)
2333 SV_LinkEdict(ent, false);
2336 void SV_VM_CB_InitEdict(prvm_edict_t *e)
2338 // LordHavoc: for consistency set these here
2339 int num = PRVM_NUM_FOR_EDICT(e) - 1;
2341 e->priv.server->move = false; // don't move on first frame
2343 if (num >= 0 && num < svs.maxclients)
2346 // set colormap and team on newly created player entity
2347 e->fields.server->colormap = num + 1;
2348 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
2349 // set netname/clientcolors back to client values so that
2350 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
2352 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
2353 if ((val = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.clientcolors)))
2354 val->_float = svs.clients[num].colors;
2355 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
2356 if( prog->fieldoffsets.playermodel >= 0 )
2357 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
2358 if( prog->fieldoffsets.playerskin >= 0 )
2359 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
2363 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
2365 World_UnlinkEdict(ed); // unlink from world bsp
2367 ed->fields.server->model = 0;
2368 ed->fields.server->takedamage = 0;
2369 ed->fields.server->modelindex = 0;
2370 ed->fields.server->colormap = 0;
2371 ed->fields.server->skin = 0;
2372 ed->fields.server->frame = 0;
2373 VectorClear(ed->fields.server->origin);
2374 VectorClear(ed->fields.server->angles);
2375 ed->fields.server->nextthink = -1;
2376 ed->fields.server->solid = 0;
2379 void SV_VM_CB_CountEdicts(void)
2383 int active, models, solid, step;
2385 active = models = solid = step = 0;
2386 for (i=0 ; i<prog->num_edicts ; i++)
2388 ent = PRVM_EDICT_NUM(i);
2389 if (ent->priv.server->free)
2392 if (ent->fields.server->solid)
2394 if (ent->fields.server->model)
2396 if (ent->fields.server->movetype == MOVETYPE_STEP)
2400 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2401 Con_Printf("active :%3i\n", active);
2402 Con_Printf("view :%3i\n", models);
2403 Con_Printf("touch :%3i\n", solid);
2404 Con_Printf("step :%3i\n", step);
2407 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2409 // remove things from different skill levels or deathmatch
2410 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2412 if (deathmatch.integer)
2414 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2419 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2420 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2421 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2429 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)"};
2430 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2431 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2432 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2433 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2434 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2435 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2436 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2437 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2438 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2439 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2440 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2441 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2442 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2443 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2444 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2445 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2446 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2447 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2448 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2449 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2450 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2451 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2452 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2453 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2454 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2455 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2456 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2457 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2458 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2459 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2460 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2461 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2463 void SV_VM_Init(void)
2465 Cvar_RegisterVariable (&pr_checkextension);
2466 Cvar_RegisterVariable (&nomonsters);
2467 Cvar_RegisterVariable (&gamecfg);
2468 Cvar_RegisterVariable (&scratch1);
2469 Cvar_RegisterVariable (&scratch2);
2470 Cvar_RegisterVariable (&scratch3);
2471 Cvar_RegisterVariable (&scratch4);
2472 Cvar_RegisterVariable (&savedgamecfg);
2473 Cvar_RegisterVariable (&saved1);
2474 Cvar_RegisterVariable (&saved2);
2475 Cvar_RegisterVariable (&saved3);
2476 Cvar_RegisterVariable (&saved4);
2477 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2478 if (gamemode == GAME_NEHAHRA)
2480 Cvar_RegisterVariable (&nehx00);
2481 Cvar_RegisterVariable (&nehx01);
2482 Cvar_RegisterVariable (&nehx02);
2483 Cvar_RegisterVariable (&nehx03);
2484 Cvar_RegisterVariable (&nehx04);
2485 Cvar_RegisterVariable (&nehx05);
2486 Cvar_RegisterVariable (&nehx06);
2487 Cvar_RegisterVariable (&nehx07);
2488 Cvar_RegisterVariable (&nehx08);
2489 Cvar_RegisterVariable (&nehx09);
2490 Cvar_RegisterVariable (&nehx10);
2491 Cvar_RegisterVariable (&nehx11);
2492 Cvar_RegisterVariable (&nehx12);
2493 Cvar_RegisterVariable (&nehx13);
2494 Cvar_RegisterVariable (&nehx14);
2495 Cvar_RegisterVariable (&nehx15);
2496 Cvar_RegisterVariable (&nehx16);
2497 Cvar_RegisterVariable (&nehx17);
2498 Cvar_RegisterVariable (&nehx18);
2499 Cvar_RegisterVariable (&nehx19);
2501 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2504 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2506 prvm_required_field_t reqfields[] =
2508 {ev_entity, "cursor_trace_ent"},
2509 {ev_entity, "drawonlytoclient"},
2510 {ev_entity, "exteriormodeltoclient"},
2511 {ev_entity, "nodrawtoclient"},
2512 {ev_entity, "tag_entity"},
2513 {ev_entity, "viewmodelforclient"},
2514 {ev_float, "alpha"},
2515 {ev_float, "ammo_cells1"},
2516 {ev_float, "ammo_lava_nails"},
2517 {ev_float, "ammo_multi_rockets"},
2518 {ev_float, "ammo_nails1"},
2519 {ev_float, "ammo_plasma"},
2520 {ev_float, "ammo_rockets1"},
2521 {ev_float, "ammo_shells1"},
2522 {ev_float, "button3"},
2523 {ev_float, "button4"},
2524 {ev_float, "button5"},
2525 {ev_float, "button6"},
2526 {ev_float, "button7"},
2527 {ev_float, "button8"},
2528 {ev_float, "button9"},
2529 {ev_float, "button10"},
2530 {ev_float, "button11"},
2531 {ev_float, "button12"},
2532 {ev_float, "button13"},
2533 {ev_float, "button14"},
2534 {ev_float, "button15"},
2535 {ev_float, "button16"},
2536 {ev_float, "buttonchat"},
2537 {ev_float, "buttonuse"},
2538 {ev_float, "clientcolors"},
2539 {ev_float, "cursor_active"},
2540 {ev_float, "fullbright"},
2541 {ev_float, "glow_color"},
2542 {ev_float, "glow_size"},
2543 {ev_float, "glow_trail"},
2544 {ev_float, "gravity"},
2545 {ev_float, "idealpitch"},
2546 {ev_float, "items2"},
2547 {ev_float, "light_lev"},
2548 {ev_float, "pflags"},
2550 {ev_float, "pitch_speed"},
2551 {ev_float, "pmodel"},
2552 {ev_float, "renderamt"}, // HalfLife support
2553 {ev_float, "rendermode"}, // HalfLife support
2554 {ev_float, "scale"},
2555 {ev_float, "style"},
2556 {ev_float, "tag_index"},
2557 {ev_float, "Version"},
2558 {ev_float, "viewzoom"},
2559 {ev_vector, "color"},
2560 {ev_vector, "colormod"},
2561 {ev_vector, "cursor_screen"},
2562 {ev_vector, "cursor_trace_endpos"},
2563 {ev_vector, "cursor_trace_start"},
2564 {ev_vector, "movement"},
2565 {ev_vector, "punchvector"},
2566 {ev_string, "playermodel"},
2567 {ev_string, "playerskin"},
2568 {ev_function, "SendEntity"},
2569 {ev_function, "customizeentityforclient"},
2570 // DRESK - Support for Entity Contents Transition Event
2571 {ev_function, "contentstransition"},
2574 void SV_VM_Setup(void)
2576 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
2577 extern cvar_t csqc_progcrc;
2578 extern cvar_t csqc_progsize;
2579 size_t csprogsdatasize;
2581 PRVM_InitProg( PRVM_SERVERPROG );
2583 // allocate the mempools
2584 // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
2585 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2586 prog->builtins = vm_sv_builtins;
2587 prog->numbuiltins = vm_sv_numbuiltins;
2588 prog->headercrc = PROGHEADER_CRC;
2589 prog->max_edicts = 512;
2590 prog->limit_edicts = MAX_EDICTS;
2591 prog->reserved_edicts = svs.maxclients;
2592 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2593 prog->name = "server";
2594 prog->extensionstring = vm_sv_extensions;
2595 prog->loadintoworld = true;
2597 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2598 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2599 prog->init_edict = SV_VM_CB_InitEdict;
2600 prog->free_edict = SV_VM_CB_FreeEdict;
2601 prog->count_edicts = SV_VM_CB_CountEdicts;
2602 prog->load_edict = SV_VM_CB_LoadEdict;
2603 prog->init_cmd = VM_SV_Cmd_Init;
2604 prog->reset_cmd = VM_SV_Cmd_Reset;
2605 prog->error_cmd = Host_Error;
2607 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2608 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields, 0, NULL );
2610 // some mods compiled with scrambling compilers lack certain critical
2611 // global names and field names such as "self" and "time" and "nextthink"
2612 // so we have to set these offsets manually, matching the entvars_t
2613 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, angles);
2614 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, chain);
2615 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, classname);
2616 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, frame);
2617 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, groundentity);
2618 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ideal_yaw);
2619 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, nextthink);
2620 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, think);
2621 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, yaw_speed);
2622 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, self);
2623 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, time);
2624 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_forward);
2625 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_right);
2626 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_up);
2627 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_allsolid);
2628 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_startsolid);
2629 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_fraction);
2630 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inwater);
2631 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inopen);
2632 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_endpos);
2633 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_normal);
2634 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_dist);
2635 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_ent);
2636 // OP_STATE is always supported on server (due to entvars_t)
2637 prog->flag |= PRVM_OP_STATE;
2639 VM_AutoSentStats_Clear();//[515]: csqc
2640 EntityFrameCSQC_ClearVersions();//[515]: csqc
2644 // 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
2645 sv.csqc_progname[0] = 0;
2646 sv.csqc_progcrc = FS_CRCFile(csqc_progname.string, &csprogsdatasize);
2647 sv.csqc_progsize = csprogsdatasize;
2648 if (sv.csqc_progsize > 0)
2650 strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
2651 Con_DPrintf("server detected csqc progs file \"%s\" with size %i and crc %i\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
2655 void SV_VM_Begin(void)
2658 PRVM_SetProg( PRVM_SERVERPROG );
2660 prog->globals.server->time = (float) sv.time;
2663 void SV_VM_End(void)