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_clientnum;
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 sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
1004 csqc_clientnum = sv_writeentitiestoclient_clentnum - 1;
1008 for (i = 0;i < numsendentities;i++)
1009 SV_MarkWriteEntityStateToClient(sendentities + i);
1012 for (i = 0;i < numsendentities;i++)
1014 if (sententities[sendentities[i].number] == sententitiesmark)
1016 s = &sendstates[numsendstates++];
1017 *s = sendentities[i];
1018 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
1019 s->flags |= RENDER_EXTERIORMODEL;
1023 if (sv_cullentities_stats.integer)
1024 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);
1026 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
1028 if (client->entitydatabase5)
1029 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
1030 else if (client->entitydatabase4)
1031 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
1032 else if (client->entitydatabase)
1033 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
1035 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
1044 void SV_CleanupEnts (void)
1049 ent = PRVM_NEXT_EDICT(prog->edicts);
1050 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
1051 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
1056 SV_WriteClientdataToMessage
1060 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1064 prvm_edict_t *other;
1072 // send a damage message
1074 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
1076 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
1077 MSG_WriteByte (msg, svc_damage);
1078 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
1079 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
1080 for (i=0 ; i<3 ; i++)
1081 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
1083 ent->fields.server->dmg_take = 0;
1084 ent->fields.server->dmg_save = 0;
1088 // send the current viewpos offset from the view entity
1090 SV_SetIdealPitch (); // how much to look up / down ideally
1092 // a fixangle might get lost in a dropped packet. Oh well.
1093 if ( ent->fields.server->fixangle )
1095 MSG_WriteByte (msg, svc_setangle);
1096 for (i=0 ; i < 3 ; i++)
1097 MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
1098 // LordHavoc: moved fixangle = 0 to the physics code so it is
1099 // repeatedly sent to predicted clients even though they don't always
1101 //ent->fields.server->fixangle = 0;
1104 // stuff the sigil bits into the high bits of items for sbar, or else
1106 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.items2);
1107 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1108 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1110 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1112 VectorClear(punchvector);
1113 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.punchvector)))
1114 VectorCopy(val->vector, punchvector);
1116 // cache weapon model name and index in client struct to save time
1117 // (this search can be almost 1% of cpu time!)
1118 s = PRVM_GetString(ent->fields.server->weaponmodel);
1119 if (strcmp(s, client->weaponmodel))
1121 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1122 client->weaponmodelindex = SV_ModelIndex(s, 1);
1126 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewzoom)))
1127 viewzoom = (int)(val->_float * 255.0f);
1133 if ((int)ent->fields.server->flags & FL_ONGROUND)
1134 bits |= SU_ONGROUND;
1135 if (ent->fields.server->waterlevel >= 2)
1137 if (ent->fields.server->idealpitch)
1138 bits |= SU_IDEALPITCH;
1140 for (i=0 ; i<3 ; i++)
1142 if (ent->fields.server->punchangle[i])
1143 bits |= (SU_PUNCH1<<i);
1144 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1146 bits |= (SU_PUNCHVEC1<<i);
1147 if (ent->fields.server->velocity[i])
1148 bits |= (SU_VELOCITY1<<i);
1151 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1152 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1153 stats[STAT_ITEMS] = items;
1154 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1155 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1156 stats[STAT_WEAPON] = client->weaponmodelindex;
1157 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1158 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1159 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1160 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1161 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1162 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1163 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1164 stats[STAT_VIEWZOOM] = viewzoom;
1165 stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1166 stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1167 // the QC bumps these itself by sending svc_'s, so we have to keep them
1168 // zero or they'll be corrected by the engine
1169 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1170 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1172 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)
1174 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1176 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1177 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1179 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1180 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1181 if (viewzoom != 255)
1182 bits |= SU_VIEWZOOM;
1187 if (bits >= 16777216)
1191 MSG_WriteByte (msg, svc_clientdata);
1192 MSG_WriteShort (msg, bits);
1193 if (bits & SU_EXTEND1)
1194 MSG_WriteByte(msg, bits >> 16);
1195 if (bits & SU_EXTEND2)
1196 MSG_WriteByte(msg, bits >> 24);
1198 if (bits & SU_VIEWHEIGHT)
1199 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1201 if (bits & SU_IDEALPITCH)
1202 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1204 for (i=0 ; i<3 ; i++)
1206 if (bits & (SU_PUNCH1<<i))
1208 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1209 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1211 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1213 if (bits & (SU_PUNCHVEC1<<i))
1215 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1216 MSG_WriteCoord16i(msg, punchvector[i]);
1218 MSG_WriteCoord32f(msg, punchvector[i]);
1220 if (bits & (SU_VELOCITY1<<i))
1222 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1223 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1225 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1229 if (bits & SU_ITEMS)
1230 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1232 if (sv.protocol == PROTOCOL_DARKPLACES5)
1234 if (bits & SU_WEAPONFRAME)
1235 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1236 if (bits & SU_ARMOR)
1237 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1238 if (bits & SU_WEAPON)
1239 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1240 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1241 MSG_WriteShort (msg, stats[STAT_AMMO]);
1242 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1243 MSG_WriteShort (msg, stats[STAT_NAILS]);
1244 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1245 MSG_WriteShort (msg, stats[STAT_CELLS]);
1246 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1247 if (bits & SU_VIEWZOOM)
1248 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1250 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)
1252 if (bits & SU_WEAPONFRAME)
1253 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1254 if (bits & SU_ARMOR)
1255 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1256 if (bits & SU_WEAPON)
1257 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1258 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1259 MSG_WriteByte (msg, stats[STAT_AMMO]);
1260 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1261 MSG_WriteByte (msg, stats[STAT_NAILS]);
1262 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1263 MSG_WriteByte (msg, stats[STAT_CELLS]);
1264 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1266 for (i = 0;i < 32;i++)
1267 if (stats[STAT_WEAPON] & (1<<i))
1269 MSG_WriteByte (msg, i);
1272 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1273 if (bits & SU_VIEWZOOM)
1275 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1276 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1278 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1284 =======================
1285 SV_SendClientDatagram
1286 =======================
1288 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1289 void SV_SendClientDatagram (client_t *client)
1291 int rate, maxrate, maxsize, maxsize2, downloadsize;
1293 int stats[MAX_CL_STATS];
1295 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1297 // for good singleplayer, send huge packets
1298 maxsize = sizeof(sv_sendclientdatagram_buf);
1299 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1301 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)
1303 // no rate limiting support on older protocols because dp protocols
1304 // 1-4 kick the client off if they overflow, and quake protocol shows
1305 // less than the full entity set if rate limited
1311 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1312 maxrate = max(NET_MINRATE, sv_maxrate.integer);
1313 if (sv_maxrate.integer != maxrate)
1314 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1316 // this rate limiting does not understand sys_ticrate 0
1317 // (but no one should be running that on a server!)
1318 rate = bound(NET_MINRATE, client->rate, maxrate);
1319 rate = (int)(rate * sys_ticrate.value);
1320 maxsize = bound(50, rate, 1400);
1324 // while downloading, limit entity updates to half the packet
1325 // (any leftover space will be used for downloading)
1326 if (host_client->download_file)
1329 msg.data = sv_sendclientdatagram_buf;
1330 msg.maxsize = maxsize;
1333 if (host_client->spawned)
1335 MSG_WriteByte (&msg, svc_time);
1336 MSG_WriteFloat (&msg, sv.time);
1338 // add the client specific data to the datagram
1339 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1340 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1341 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1343 // expand packet size to allow effects to go over the rate limit
1344 // (dropping them is FAR too ugly)
1345 msg.maxsize = maxsize2;
1347 // copy the server datagram if there is space
1348 // FIXME: put in delayed queue of effects to send
1349 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1350 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1352 else if (realtime > client->keepalivetime)
1354 // the player isn't totally in the game yet
1355 // send small keepalive messages if too much time has passed
1356 msg.maxsize = maxsize2;
1357 client->keepalivetime = realtime + 5;
1358 MSG_WriteChar (&msg, svc_nop);
1361 msg.maxsize = maxsize2;
1363 // if a download is active, see if there is room to fit some download data
1365 downloadsize = maxsize * 2 - msg.cursize - 7;
1366 if (host_client->download_file && host_client->download_started && downloadsize > 0)
1368 fs_offset_t downloadstart;
1369 unsigned char data[1400];
1370 downloadstart = FS_Tell(host_client->download_file);
1371 downloadsize = min(downloadsize, (int)sizeof(data));
1372 downloadsize = FS_Read(host_client->download_file, data, downloadsize);
1373 // note this sends empty messages if at the end of the file, which is
1374 // necessary to keep the packet loss logic working
1375 // (the last blocks may be lost and need to be re-sent, and that will
1376 // only occur if the client acks the empty end messages, revealing
1377 // a gap in the download progress, causing the last blocks to be
1379 MSG_WriteChar (&msg, svc_downloaddata);
1380 MSG_WriteLong (&msg, downloadstart);
1381 MSG_WriteShort (&msg, downloadsize);
1382 if (downloadsize > 0)
1383 SZ_Write (&msg, data, downloadsize);
1386 // send the datagram
1387 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1391 =======================
1392 SV_UpdateToReliableMessages
1393 =======================
1395 void SV_UpdateToReliableMessages (void)
1404 // check for changes to be sent over the reliable streams
1405 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1407 // update the host_client fields we care about according to the entity fields
1408 host_client->edict = PRVM_EDICT_NUM(i+1);
1411 name = PRVM_GetString(host_client->edict->fields.server->netname);
1414 // always point the string back at host_client->name to keep it safe
1415 strlcpy (host_client->name, name, sizeof (host_client->name));
1416 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1417 if (strcmp(host_client->old_name, host_client->name))
1419 if (host_client->spawned)
1420 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1421 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1422 // send notification to all clients
1423 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1424 MSG_WriteByte (&sv.reliable_datagram, i);
1425 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1428 // DP_SV_CLIENTCOLORS
1429 // this is always found (since it's added by the progs loader)
1430 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
1431 host_client->colors = (int)val->_float;
1432 if (host_client->old_colors != host_client->colors)
1434 host_client->old_colors = host_client->colors;
1435 // send notification to all clients
1436 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1437 MSG_WriteByte (&sv.reliable_datagram, i);
1438 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1441 // NEXUIZ_PLAYERMODEL
1442 if( prog->fieldoffsets.playermodel >= 0 ) {
1443 model = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string);
1446 // always point the string back at host_client->name to keep it safe
1447 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1448 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1451 // NEXUIZ_PLAYERSKIN
1452 if( prog->fieldoffsets.playerskin >= 0 ) {
1453 skin = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string);
1456 // always point the string back at host_client->name to keep it safe
1457 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1458 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1462 host_client->frags = (int)host_client->edict->fields.server->frags;
1463 if (host_client->old_frags != host_client->frags)
1465 host_client->old_frags = host_client->frags;
1466 // send notification to all clients
1467 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1468 MSG_WriteByte (&sv.reliable_datagram, i);
1469 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1473 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1474 if (client->netconnection)
1475 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1477 SZ_Clear (&sv.reliable_datagram);
1482 =======================
1483 SV_SendClientMessages
1484 =======================
1486 void SV_SendClientMessages (void)
1488 int i, prepared = false;
1490 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1491 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1493 // update frags, names, etc
1494 SV_UpdateToReliableMessages();
1496 // build individual updates
1497 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1499 if (!host_client->active)
1501 if (!host_client->netconnection)
1504 if (host_client->netconnection->message.overflowed)
1506 SV_DropClient (true); // if the message couldn't send, kick off
1513 // only prepare entities once per frame
1514 SV_PrepareEntitiesForSending();
1516 SV_SendClientDatagram (host_client);
1519 // clear muzzle flashes
1523 void SV_StartDownload_f(void)
1525 if (host_client->download_file)
1526 host_client->download_started = true;
1529 void SV_Download_f(void)
1531 const char *whichpack, *whichpack2, *extension;
1533 if (Cmd_Argc() != 2)
1535 SV_ClientPrintf("usage: download <filename>\n");
1539 if (FS_CheckNastyPath(Cmd_Argv(1), false))
1541 SV_ClientPrintf("Download rejected: nasty filename \"%s\"\n", Cmd_Argv(1));
1545 if (host_client->download_file)
1547 // at this point we'll assume the previous download should be aborted
1548 Con_DPrintf("Download of %s aborted by %s starting a new download\n", host_client->download_name, host_client->name);
1549 Host_ClientCommands("\nstopdownload\n");
1551 // close the file and reset variables
1552 FS_Close(host_client->download_file);
1553 host_client->download_file = NULL;
1554 host_client->download_name[0] = 0;
1555 host_client->download_expectedposition = 0;
1556 host_client->download_started = false;
1559 if (!sv_allowdownloads.integer)
1561 SV_ClientPrintf("Downloads are disabled on this server\n");
1562 Host_ClientCommands("\nstopdownload\n");
1566 strlcpy(host_client->download_name, Cmd_Argv(1), sizeof(host_client->download_name));
1567 extension = FS_FileExtension(host_client->download_name);
1569 // host_client is asking to download a specified file
1570 if (developer.integer >= 100)
1571 Con_Printf("Download request for %s by %s\n", host_client->download_name, host_client->name);
1573 if (!FS_FileExists(host_client->download_name))
1575 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);
1576 Host_ClientCommands("\nstopdownload\n");
1580 // check if the user is trying to download part of registered Quake(r)
1581 whichpack = FS_WhichPack(host_client->download_name);
1582 whichpack2 = FS_WhichPack("gfx/pop.lmp");
1583 if ((whichpack && whichpack2 && !strcasecmp(whichpack, whichpack2)) || FS_IsRegisteredQuakePack(host_client->download_name))
1585 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);
1586 Host_ClientCommands("\nstopdownload\n");
1590 // check if the server has forbidden archive downloads entirely
1591 if (!sv_allowdownloads_inarchive.integer)
1593 whichpack = FS_WhichPack(host_client->download_name);
1596 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);
1597 Host_ClientCommands("\nstopdownload\n");
1602 if (!sv_allowdownloads_config.integer)
1604 if (!strcasecmp(extension, "cfg"))
1606 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);
1607 Host_ClientCommands("\nstopdownload\n");
1612 if (!sv_allowdownloads_dlcache.integer)
1614 if (!strncasecmp(host_client->download_name, "dlcache/", 8))
1616 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);
1617 Host_ClientCommands("\nstopdownload\n");
1622 if (!sv_allowdownloads_archive.integer)
1624 if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
1626 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);
1627 Host_ClientCommands("\nstopdownload\n");
1632 host_client->download_file = FS_Open(host_client->download_name, "rb", true, false);
1633 if (!host_client->download_file)
1635 SV_ClientPrintf("Download rejected: server could not open the file \"%s\"\n", host_client->download_name);
1636 Host_ClientCommands("\nstopdownload\n");
1640 if (FS_FileSize(host_client->download_file) > 1<<30)
1642 SV_ClientPrintf("Download rejected: file \"%s\" is very large\n", host_client->download_name);
1643 Host_ClientCommands("\nstopdownload\n");
1644 FS_Close(host_client->download_file);
1645 host_client->download_file = NULL;
1649 Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
1651 Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name);
1653 host_client->download_expectedposition = 0;
1654 host_client->download_started = false;
1656 // the rest of the download process is handled in SV_SendClientDatagram
1657 // and other code dealing with svc_downloaddata and clc_ackdownloaddata
1659 // no svc_downloaddata messages will be sent until sv_startdownload is
1660 // sent by the client
1664 ==============================================================================
1668 ==============================================================================
1677 int SV_ModelIndex(const char *s, int precachemode)
1679 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1680 char filename[MAX_QPATH];
1684 //if (precachemode == 2)
1686 strlcpy(filename, s, sizeof(filename));
1687 for (i = 2;i < limit;i++)
1689 if (!sv.model_precache[i][0])
1693 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))
1695 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1698 if (precachemode == 1)
1699 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1700 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1701 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1702 if (sv.state != ss_loading)
1704 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1705 MSG_WriteShort(&sv.reliable_datagram, i);
1706 MSG_WriteString(&sv.reliable_datagram, filename);
1710 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1713 if (!strcmp(sv.model_precache[i], filename))
1716 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1726 int SV_SoundIndex(const char *s, int precachemode)
1728 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1729 char filename[MAX_QPATH];
1733 //if (precachemode == 2)
1735 strlcpy(filename, s, sizeof(filename));
1736 for (i = 1;i < limit;i++)
1738 if (!sv.sound_precache[i][0])
1742 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))
1744 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1747 if (precachemode == 1)
1748 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1749 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1750 if (sv.state != ss_loading)
1752 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1753 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1754 MSG_WriteString(&sv.reliable_datagram, filename);
1758 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1761 if (!strcmp(sv.sound_precache[i], filename))
1764 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1768 // MUST match effectnameindex_t in client.h
1769 static const char *standardeffectnames[EFFECT_TOTAL] =
1777 "TE_SUPERSPIKEQUAD",
1793 "TE_TEI_BIGEXPLOSION",
1811 SV_ParticleEffectIndex
1815 int SV_ParticleEffectIndex(const char *name)
1817 int i, argc, linenumber, effectnameindex;
1818 fs_offset_t filesize;
1819 unsigned char *filedata;
1820 const char *text, *textstart, *textend;
1821 char argv[16][1024];
1822 if (!sv.particleeffectnamesloaded)
1824 sv.particleeffectnamesloaded = true;
1825 memset(sv.particleeffectname, 0, sizeof(sv.particleeffectname));
1826 for (i = 0;i < EFFECT_TOTAL;i++)
1827 strlcpy(sv.particleeffectname[i], standardeffectnames[i], sizeof(sv.particleeffectname[i]));
1828 filedata = FS_LoadFile("effectinfo.txt", tempmempool, true, &filesize);
1831 textstart = (const char *)filedata;
1832 textend = (const char *)filedata + filesize;
1834 for (linenumber = 1;;linenumber++)
1839 if (!COM_ParseToken(&text, true) || !strcmp(com_token, "\n"))
1843 strlcpy(argv[argc], com_token, sizeof(argv[argc]));
1847 if (com_token[0] == 0)
1848 break; // if the loop exited and it's not a \n, it's EOF
1851 if (!strcmp(argv[0], "effect"))
1855 for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME;effectnameindex++)
1857 if (sv.particleeffectname[effectnameindex][0])
1859 if (!strcmp(sv.particleeffectname[effectnameindex], argv[1]))
1864 strlcpy(sv.particleeffectname[effectnameindex], argv[1], sizeof(sv.particleeffectname[effectnameindex]));
1868 // if we run out of names, abort
1869 if (effectnameindex == SV_MAX_PARTICLEEFFECTNAME)
1871 Con_Printf("effectinfo.txt:%i: too many effects!\n", linenumber);
1880 // search for the name
1881 for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME && sv.particleeffectname[effectnameindex][0];effectnameindex++)
1882 if (!strcmp(sv.particleeffectname[effectnameindex], name))
1883 return effectnameindex;
1884 // return 0 if we couldn't find it
1894 void SV_CreateBaseline (void)
1896 int i, entnum, large;
1897 prvm_edict_t *svent;
1899 // LordHavoc: clear *all* states (note just active ones)
1900 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1902 // get the current server version
1903 svent = PRVM_EDICT_NUM(entnum);
1905 // LordHavoc: always clear state values, whether the entity is in use or not
1906 svent->priv.server->baseline = defaultstate;
1908 if (svent->priv.server->free)
1910 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1913 // create entity baseline
1914 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1915 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1916 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1917 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1918 if (entnum > 0 && entnum <= svs.maxclients)
1920 svent->priv.server->baseline.colormap = entnum;
1921 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1925 svent->priv.server->baseline.colormap = 0;
1926 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1930 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1933 // add to the message
1935 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1937 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1938 MSG_WriteShort (&sv.signon, entnum);
1942 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1943 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1947 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1948 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1950 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1951 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1952 for (i=0 ; i<3 ; i++)
1954 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1955 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1965 Grabs the current state of each client for saving across the
1966 transition to another level
1969 void SV_SaveSpawnparms (void)
1973 svs.serverflags = (int)prog->globals.server->serverflags;
1975 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1977 if (!host_client->active)
1980 // call the progs to get default spawn parms for the new client
1981 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1982 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1983 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1984 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1988 void SV_IncreaseEdicts(void)
1992 int oldmax_edicts = prog->max_edicts;
1993 void *oldedictsengineprivate = prog->edictprivate;
1994 void *oldedictsfields = prog->edictsfields;
1995 void *oldmoved_edicts = sv.moved_edicts;
1997 if (prog->max_edicts >= MAX_EDICTS)
2000 // links don't survive the transition, so unlink everything
2001 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2003 if (!ent->priv.server->free)
2004 SV_UnlinkEdict(prog->edicts + i);
2005 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
2007 World_Clear(&sv.world);
2009 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
2010 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
2011 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
2012 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2014 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
2015 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
2017 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2019 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
2020 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
2021 // link every entity except world
2022 if (!ent->priv.server->free)
2023 SV_LinkEdict(ent, false);
2026 PR_Free(oldedictsengineprivate);
2027 PR_Free(oldedictsfields);
2028 PR_Free(oldmoved_edicts);
2035 This is called at the start of each level
2038 extern float scr_centertime_off;
2040 void SV_SpawnServer (const char *server)
2045 model_t *worldmodel;
2046 char modelname[sizeof(sv.modelname)];
2048 Con_DPrintf("SpawnServer: %s\n", server);
2050 if (cls.state != ca_dedicated)
2051 SCR_BeginLoadingPlaque();
2053 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
2054 worldmodel = Mod_ForName(modelname, false, true, true);
2055 if (!worldmodel || !worldmodel->TraceBox)
2057 Con_Printf("Couldn't load map %s\n", modelname);
2061 // let's not have any servers with no name
2062 if (hostname.string[0] == 0)
2063 Cvar_Set ("hostname", "UNNAMED");
2064 scr_centertime_off = 0;
2066 svs.changelevel_issued = false; // now safe to issue another
2068 // make the map a required file for clients
2069 Curl_ClearRequirements();
2070 Curl_RequireFile(modelname);
2073 // tell all connected clients that we are going to a new level
2078 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
2080 if (client->netconnection)
2082 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
2083 MSG_WriteString(&client->netconnection->message, "reconnect\n");
2090 NetConn_OpenServerPorts(true);
2094 // make cvars consistant
2097 Cvar_SetValue ("deathmatch", 0);
2098 // LordHavoc: it can be useful to have skills outside the range 0-3...
2099 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
2100 //Cvar_SetValue ("skill", (float)current_skill);
2101 current_skill = (int)(skill.value + 0.5);
2104 // set up the new server
2106 memset (&sv, 0, sizeof(sv));
2107 // if running a local client, make sure it doesn't try to access the last
2108 // level's data which is no longer valiud
2111 if(*sv_random_seed.string)
2113 srand(sv_random_seed.integer);
2114 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);
2121 strlcpy (sv.name, server, sizeof (sv.name));
2123 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
2124 if (sv.protocol == PROTOCOL_UNKNOWN)
2127 Protocol_Names(buffer, sizeof(buffer));
2128 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
2129 sv.protocol = PROTOCOL_QUAKE;
2134 // load progs to get entity field count
2135 //PR_LoadProgs ( sv_progs.string );
2137 // allocate server memory
2138 /*// start out with just enough room for clients and a reasonable estimate of entities
2139 prog->max_edicts = max(svs.maxclients + 1, 512);
2140 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
2142 // prvm_edict_t structures (hidden from progs)
2143 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
2144 // engine private structures (hidden from progs)
2145 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
2146 // progs fields, often accessed by server
2147 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
2148 // used by PushMove to move back pushed entities
2149 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2150 /*for (i = 0;i < prog->max_edicts;i++)
2152 ent = prog->edicts + i;
2153 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
2154 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
2157 // reset client csqc entity versions right away.
2158 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2159 EntityFrameCSQC_InitClientVersions(i, true);
2161 sv.datagram.maxsize = sizeof(sv.datagram_buf);
2162 sv.datagram.cursize = 0;
2163 sv.datagram.data = sv.datagram_buf;
2165 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
2166 sv.reliable_datagram.cursize = 0;
2167 sv.reliable_datagram.data = sv.reliable_datagram_buf;
2169 sv.signon.maxsize = sizeof(sv.signon_buf);
2170 sv.signon.cursize = 0;
2171 sv.signon.data = sv.signon_buf;
2173 // leave slots at start for clients only
2174 //prog->num_edicts = svs.maxclients+1;
2176 sv.state = ss_loading;
2177 prog->allowworldwrites = true;
2180 prog->globals.server->time = sv.time = 1.0;
2183 worldmodel->used = true;
2185 strlcpy (sv.name, server, sizeof (sv.name));
2186 strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
2187 sv.worldmodel = worldmodel;
2188 sv.models[1] = sv.worldmodel;
2191 // clear world interaction links
2193 VectorCopy(sv.worldmodel->normalmins, sv.world.areagrid_mins);
2194 VectorCopy(sv.worldmodel->normalmaxs, sv.world.areagrid_maxs);
2195 World_Clear(&sv.world);
2197 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
2199 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
2200 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
2201 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
2203 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
2204 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
2208 // load the rest of the entities
2210 // AK possible hack since num_edicts is still 0
2211 ent = PRVM_EDICT_NUM(0);
2212 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
2213 ent->priv.server->free = false;
2214 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
2215 ent->fields.server->modelindex = 1; // world model
2216 ent->fields.server->solid = SOLID_BSP;
2217 ent->fields.server->movetype = MOVETYPE_PUSH;
2218 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->mins);
2219 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->maxs);
2220 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->absmin);
2221 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->absmax);
2224 prog->globals.server->coop = coop.integer;
2226 prog->globals.server->deathmatch = deathmatch.integer;
2228 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
2230 // serverflags are for cross level information (sigils)
2231 prog->globals.server->serverflags = svs.serverflags;
2233 // we need to reset the spawned flag on all connected clients here so that
2234 // their thinks don't run during startup (before PutClientInServer)
2235 // we also need to set up the client entities now
2236 // and we need to set the ->edict pointers to point into the progs edicts
2237 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2239 host_client->spawned = false;
2240 host_client->edict = PRVM_EDICT_NUM(i + 1);
2241 PRVM_ED_ClearEdict(host_client->edict);
2244 // load replacement entity file if found
2245 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
2247 Con_Printf("Loaded maps/%s.ent\n", sv.name);
2248 PRVM_ED_LoadFromFile (entities);
2252 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
2255 // LordHavoc: clear world angles (to fix e3m3.bsp)
2256 VectorClear(prog->edicts->fields.server->angles);
2258 // all setup is completed, any further precache statements are errors
2259 sv.state = ss_active;
2260 prog->allowworldwrites = false;
2262 // run two frames to allow everything to settle
2263 for (i = 0;i < 2;i++)
2271 // create a baseline for more efficient communications
2272 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
2273 SV_CreateBaseline ();
2275 // send serverinfo to all connected clients, and set up botclients coming back from a level change
2276 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2278 if (!host_client->active)
2280 if (host_client->netconnection)
2281 SV_SendServerinfo(host_client);
2285 // if client is a botclient coming from a level change, we need to
2286 // set up client info that normally requires networking
2288 // copy spawn parms out of the client_t
2289 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
2290 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
2292 // call the spawn function
2293 host_client->clientconnectcalled = true;
2294 prog->globals.server->time = sv.time;
2295 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2296 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
2297 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
2298 host_client->spawned = true;
2302 Con_DPrint("Server spawned.\n");
2303 NetConn_Heartbeat (2);
2308 /////////////////////////////////////////////////////
2311 void SV_VM_CB_BeginIncreaseEdicts(void)
2316 PRVM_Free( sv.moved_edicts );
2317 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2319 // links don't survive the transition, so unlink everything
2320 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2322 if (!ent->priv.server->free)
2323 World_UnlinkEdict(prog->edicts + i);
2324 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
2326 World_Clear(&sv.world);
2329 void SV_VM_CB_EndIncreaseEdicts(void)
2334 // link every entity except world
2335 for (i = 1, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2336 if (!ent->priv.server->free)
2337 SV_LinkEdict(ent, false);
2340 void SV_VM_CB_InitEdict(prvm_edict_t *e)
2342 // LordHavoc: for consistency set these here
2343 int num = PRVM_NUM_FOR_EDICT(e) - 1;
2345 e->priv.server->move = false; // don't move on first frame
2347 if (num >= 0 && num < svs.maxclients)
2350 // set colormap and team on newly created player entity
2351 e->fields.server->colormap = num + 1;
2352 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
2353 // set netname/clientcolors back to client values so that
2354 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
2356 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
2357 if ((val = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.clientcolors)))
2358 val->_float = svs.clients[num].colors;
2359 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
2360 if( prog->fieldoffsets.playermodel >= 0 )
2361 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
2362 if( prog->fieldoffsets.playerskin >= 0 )
2363 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
2367 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
2369 World_UnlinkEdict(ed); // unlink from world bsp
2371 ed->fields.server->model = 0;
2372 ed->fields.server->takedamage = 0;
2373 ed->fields.server->modelindex = 0;
2374 ed->fields.server->colormap = 0;
2375 ed->fields.server->skin = 0;
2376 ed->fields.server->frame = 0;
2377 VectorClear(ed->fields.server->origin);
2378 VectorClear(ed->fields.server->angles);
2379 ed->fields.server->nextthink = -1;
2380 ed->fields.server->solid = 0;
2383 void SV_VM_CB_CountEdicts(void)
2387 int active, models, solid, step;
2389 active = models = solid = step = 0;
2390 for (i=0 ; i<prog->num_edicts ; i++)
2392 ent = PRVM_EDICT_NUM(i);
2393 if (ent->priv.server->free)
2396 if (ent->fields.server->solid)
2398 if (ent->fields.server->model)
2400 if (ent->fields.server->movetype == MOVETYPE_STEP)
2404 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2405 Con_Printf("active :%3i\n", active);
2406 Con_Printf("view :%3i\n", models);
2407 Con_Printf("touch :%3i\n", solid);
2408 Con_Printf("step :%3i\n", step);
2411 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2413 // remove things from different skill levels or deathmatch
2414 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2416 if (deathmatch.integer)
2418 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2423 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2424 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2425 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2433 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)"};
2434 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2435 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2436 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2437 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2438 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2439 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2440 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2441 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2442 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2443 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2444 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2445 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2446 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2447 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2448 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2449 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2450 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2451 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2452 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2453 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2454 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2455 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2456 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2457 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2458 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2459 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2460 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2461 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2462 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2463 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2464 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2465 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2467 void SV_VM_Init(void)
2469 Cvar_RegisterVariable (&pr_checkextension);
2470 Cvar_RegisterVariable (&nomonsters);
2471 Cvar_RegisterVariable (&gamecfg);
2472 Cvar_RegisterVariable (&scratch1);
2473 Cvar_RegisterVariable (&scratch2);
2474 Cvar_RegisterVariable (&scratch3);
2475 Cvar_RegisterVariable (&scratch4);
2476 Cvar_RegisterVariable (&savedgamecfg);
2477 Cvar_RegisterVariable (&saved1);
2478 Cvar_RegisterVariable (&saved2);
2479 Cvar_RegisterVariable (&saved3);
2480 Cvar_RegisterVariable (&saved4);
2481 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2482 if (gamemode == GAME_NEHAHRA)
2484 Cvar_RegisterVariable (&nehx00);
2485 Cvar_RegisterVariable (&nehx01);
2486 Cvar_RegisterVariable (&nehx02);
2487 Cvar_RegisterVariable (&nehx03);
2488 Cvar_RegisterVariable (&nehx04);
2489 Cvar_RegisterVariable (&nehx05);
2490 Cvar_RegisterVariable (&nehx06);
2491 Cvar_RegisterVariable (&nehx07);
2492 Cvar_RegisterVariable (&nehx08);
2493 Cvar_RegisterVariable (&nehx09);
2494 Cvar_RegisterVariable (&nehx10);
2495 Cvar_RegisterVariable (&nehx11);
2496 Cvar_RegisterVariable (&nehx12);
2497 Cvar_RegisterVariable (&nehx13);
2498 Cvar_RegisterVariable (&nehx14);
2499 Cvar_RegisterVariable (&nehx15);
2500 Cvar_RegisterVariable (&nehx16);
2501 Cvar_RegisterVariable (&nehx17);
2502 Cvar_RegisterVariable (&nehx18);
2503 Cvar_RegisterVariable (&nehx19);
2505 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2508 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2510 prvm_required_field_t reqfields[] =
2512 {ev_entity, "cursor_trace_ent"},
2513 {ev_entity, "drawonlytoclient"},
2514 {ev_entity, "exteriormodeltoclient"},
2515 {ev_entity, "nodrawtoclient"},
2516 {ev_entity, "tag_entity"},
2517 {ev_entity, "viewmodelforclient"},
2518 {ev_float, "alpha"},
2519 {ev_float, "ammo_cells1"},
2520 {ev_float, "ammo_lava_nails"},
2521 {ev_float, "ammo_multi_rockets"},
2522 {ev_float, "ammo_nails1"},
2523 {ev_float, "ammo_plasma"},
2524 {ev_float, "ammo_rockets1"},
2525 {ev_float, "ammo_shells1"},
2526 {ev_float, "button3"},
2527 {ev_float, "button4"},
2528 {ev_float, "button5"},
2529 {ev_float, "button6"},
2530 {ev_float, "button7"},
2531 {ev_float, "button8"},
2532 {ev_float, "button9"},
2533 {ev_float, "button10"},
2534 {ev_float, "button11"},
2535 {ev_float, "button12"},
2536 {ev_float, "button13"},
2537 {ev_float, "button14"},
2538 {ev_float, "button15"},
2539 {ev_float, "button16"},
2540 {ev_float, "buttonchat"},
2541 {ev_float, "buttonuse"},
2542 {ev_float, "clientcolors"},
2543 {ev_float, "cursor_active"},
2544 {ev_float, "fullbright"},
2545 {ev_float, "glow_color"},
2546 {ev_float, "glow_size"},
2547 {ev_float, "glow_trail"},
2548 {ev_float, "gravity"},
2549 {ev_float, "idealpitch"},
2550 {ev_float, "items2"},
2551 {ev_float, "light_lev"},
2552 {ev_float, "pflags"},
2554 {ev_float, "pitch_speed"},
2555 {ev_float, "pmodel"},
2556 {ev_float, "renderamt"}, // HalfLife support
2557 {ev_float, "rendermode"}, // HalfLife support
2558 {ev_float, "scale"},
2559 {ev_float, "style"},
2560 {ev_float, "tag_index"},
2561 {ev_float, "Version"},
2562 {ev_float, "viewzoom"},
2563 {ev_vector, "color"},
2564 {ev_vector, "colormod"},
2565 {ev_vector, "cursor_screen"},
2566 {ev_vector, "cursor_trace_endpos"},
2567 {ev_vector, "cursor_trace_start"},
2568 {ev_vector, "movement"},
2569 {ev_vector, "punchvector"},
2570 {ev_string, "playermodel"},
2571 {ev_string, "playerskin"},
2572 {ev_function, "SendEntity"},
2573 {ev_function, "customizeentityforclient"},
2574 // DRESK - Support for Entity Contents Transition Event
2575 {ev_function, "contentstransition"},
2578 void SV_VM_Setup(void)
2580 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
2581 extern cvar_t csqc_progcrc;
2582 extern cvar_t csqc_progsize;
2583 size_t csprogsdatasize;
2585 PRVM_InitProg( PRVM_SERVERPROG );
2587 // allocate the mempools
2588 // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
2589 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2590 prog->builtins = vm_sv_builtins;
2591 prog->numbuiltins = vm_sv_numbuiltins;
2592 prog->headercrc = PROGHEADER_CRC;
2593 prog->max_edicts = 512;
2594 prog->limit_edicts = MAX_EDICTS;
2595 prog->reserved_edicts = svs.maxclients;
2596 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2597 prog->name = "server";
2598 prog->extensionstring = vm_sv_extensions;
2599 prog->loadintoworld = true;
2601 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2602 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2603 prog->init_edict = SV_VM_CB_InitEdict;
2604 prog->free_edict = SV_VM_CB_FreeEdict;
2605 prog->count_edicts = SV_VM_CB_CountEdicts;
2606 prog->load_edict = SV_VM_CB_LoadEdict;
2607 prog->init_cmd = VM_SV_Cmd_Init;
2608 prog->reset_cmd = VM_SV_Cmd_Reset;
2609 prog->error_cmd = Host_Error;
2611 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2612 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields, 0, NULL );
2614 // some mods compiled with scrambling compilers lack certain critical
2615 // global names and field names such as "self" and "time" and "nextthink"
2616 // so we have to set these offsets manually, matching the entvars_t
2617 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, angles);
2618 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, chain);
2619 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, classname);
2620 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, frame);
2621 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, groundentity);
2622 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ideal_yaw);
2623 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, nextthink);
2624 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, think);
2625 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, yaw_speed);
2626 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, self);
2627 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, time);
2628 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_forward);
2629 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_right);
2630 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_up);
2631 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_allsolid);
2632 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_startsolid);
2633 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_fraction);
2634 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inwater);
2635 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inopen);
2636 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_endpos);
2637 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_normal);
2638 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_dist);
2639 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_ent);
2640 // OP_STATE is always supported on server (due to entvars_t)
2641 prog->flag |= PRVM_OP_STATE;
2643 VM_AutoSentStats_Clear();//[515]: csqc
2644 EntityFrameCSQC_ClearVersions();//[515]: csqc
2648 // 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
2649 sv.csqc_progname[0] = 0;
2650 sv.csqc_progcrc = FS_CRCFile(csqc_progname.string, &csprogsdatasize);
2651 sv.csqc_progsize = csprogsdatasize;
2652 if (sv.csqc_progsize > 0)
2654 strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
2655 Con_DPrintf("server detected csqc progs file \"%s\" with size %i and crc %i\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
2659 void SV_VM_Begin(void)
2662 PRVM_SetProg( PRVM_SERVERPROG );
2664 prog->globals.server->time = (float) sv.time;
2667 void SV_VM_End(void)