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 ent->fields.server->fixangle = 0;
1101 // stuff the sigil bits into the high bits of items for sbar, or else
1103 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.items2);
1104 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1105 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1107 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1109 VectorClear(punchvector);
1110 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.punchvector)))
1111 VectorCopy(val->vector, punchvector);
1113 // cache weapon model name and index in client struct to save time
1114 // (this search can be almost 1% of cpu time!)
1115 s = PRVM_GetString(ent->fields.server->weaponmodel);
1116 if (strcmp(s, client->weaponmodel))
1118 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1119 client->weaponmodelindex = SV_ModelIndex(s, 1);
1123 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewzoom)))
1124 viewzoom = (int)(val->_float * 255.0f);
1130 if ((int)ent->fields.server->flags & FL_ONGROUND)
1131 bits |= SU_ONGROUND;
1132 if (ent->fields.server->waterlevel >= 2)
1134 if (ent->fields.server->idealpitch)
1135 bits |= SU_IDEALPITCH;
1137 for (i=0 ; i<3 ; i++)
1139 if (ent->fields.server->punchangle[i])
1140 bits |= (SU_PUNCH1<<i);
1141 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1143 bits |= (SU_PUNCHVEC1<<i);
1144 if (ent->fields.server->velocity[i])
1145 bits |= (SU_VELOCITY1<<i);
1148 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1149 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1150 stats[STAT_ITEMS] = items;
1151 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1152 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1153 stats[STAT_WEAPON] = client->weaponmodelindex;
1154 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1155 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1156 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1157 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1158 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1159 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1160 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1161 stats[STAT_VIEWZOOM] = viewzoom;
1162 stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1163 stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1164 // the QC bumps these itself by sending svc_'s, so we have to keep them
1165 // zero or they'll be corrected by the engine
1166 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1167 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1169 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)
1171 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1173 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1174 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1176 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1177 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1178 if (viewzoom != 255)
1179 bits |= SU_VIEWZOOM;
1184 if (bits >= 16777216)
1188 MSG_WriteByte (msg, svc_clientdata);
1189 MSG_WriteShort (msg, bits);
1190 if (bits & SU_EXTEND1)
1191 MSG_WriteByte(msg, bits >> 16);
1192 if (bits & SU_EXTEND2)
1193 MSG_WriteByte(msg, bits >> 24);
1195 if (bits & SU_VIEWHEIGHT)
1196 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1198 if (bits & SU_IDEALPITCH)
1199 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1201 for (i=0 ; i<3 ; i++)
1203 if (bits & (SU_PUNCH1<<i))
1205 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1206 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1208 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1210 if (bits & (SU_PUNCHVEC1<<i))
1212 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1213 MSG_WriteCoord16i(msg, punchvector[i]);
1215 MSG_WriteCoord32f(msg, punchvector[i]);
1217 if (bits & (SU_VELOCITY1<<i))
1219 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1220 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1222 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1226 if (bits & SU_ITEMS)
1227 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1229 if (sv.protocol == PROTOCOL_DARKPLACES5)
1231 if (bits & SU_WEAPONFRAME)
1232 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1233 if (bits & SU_ARMOR)
1234 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1235 if (bits & SU_WEAPON)
1236 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1237 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1238 MSG_WriteShort (msg, stats[STAT_AMMO]);
1239 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1240 MSG_WriteShort (msg, stats[STAT_NAILS]);
1241 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1242 MSG_WriteShort (msg, stats[STAT_CELLS]);
1243 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1244 if (bits & SU_VIEWZOOM)
1245 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1247 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)
1249 if (bits & SU_WEAPONFRAME)
1250 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1251 if (bits & SU_ARMOR)
1252 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1253 if (bits & SU_WEAPON)
1254 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1255 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1256 MSG_WriteByte (msg, stats[STAT_AMMO]);
1257 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1258 MSG_WriteByte (msg, stats[STAT_NAILS]);
1259 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1260 MSG_WriteByte (msg, stats[STAT_CELLS]);
1261 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1263 for (i = 0;i < 32;i++)
1264 if (stats[STAT_WEAPON] & (1<<i))
1266 MSG_WriteByte (msg, i);
1269 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1270 if (bits & SU_VIEWZOOM)
1272 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1273 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1275 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1281 =======================
1282 SV_SendClientDatagram
1283 =======================
1285 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1286 void SV_SendClientDatagram (client_t *client)
1288 int rate, maxrate, maxsize, maxsize2, downloadsize;
1290 int stats[MAX_CL_STATS];
1292 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1294 // for good singleplayer, send huge packets
1295 maxsize = sizeof(sv_sendclientdatagram_buf);
1296 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1298 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)
1300 // no rate limiting support on older protocols because dp protocols
1301 // 1-4 kick the client off if they overflow, and quake protocol shows
1302 // less than the full entity set if rate limited
1308 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1309 maxrate = max(NET_MINRATE, sv_maxrate.integer);
1310 if (sv_maxrate.integer != maxrate)
1311 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1313 // this rate limiting does not understand sys_ticrate 0
1314 // (but no one should be running that on a server!)
1315 rate = bound(NET_MINRATE, client->rate, maxrate);
1316 rate = (int)(rate * sys_ticrate.value);
1317 maxsize = bound(50, rate, 1400);
1321 // while downloading, limit entity updates to half the packet
1322 // (any leftover space will be used for downloading)
1323 if (host_client->download_file)
1326 msg.data = sv_sendclientdatagram_buf;
1327 msg.maxsize = maxsize;
1330 if (host_client->spawned)
1332 MSG_WriteByte (&msg, svc_time);
1333 MSG_WriteFloat (&msg, sv.time);
1335 // add the client specific data to the datagram
1336 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1337 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1338 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1340 // expand packet size to allow effects to go over the rate limit
1341 // (dropping them is FAR too ugly)
1342 msg.maxsize = maxsize2;
1344 // copy the server datagram if there is space
1345 // FIXME: put in delayed queue of effects to send
1346 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1347 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1349 else if (realtime > client->keepalivetime)
1351 // the player isn't totally in the game yet
1352 // send small keepalive messages if too much time has passed
1353 msg.maxsize = maxsize2;
1354 client->keepalivetime = realtime + 5;
1355 MSG_WriteChar (&msg, svc_nop);
1358 msg.maxsize = maxsize2;
1360 // if a download is active, see if there is room to fit some download data
1362 downloadsize = maxsize * 2 - msg.cursize - 7;
1363 if (host_client->download_file && host_client->download_started && downloadsize > 0)
1365 fs_offset_t downloadstart;
1366 unsigned char data[1400];
1367 downloadstart = FS_Tell(host_client->download_file);
1368 downloadsize = min(downloadsize, (int)sizeof(data));
1369 downloadsize = FS_Read(host_client->download_file, data, downloadsize);
1370 // note this sends empty messages if at the end of the file, which is
1371 // necessary to keep the packet loss logic working
1372 // (the last blocks may be lost and need to be re-sent, and that will
1373 // only occur if the client acks the empty end messages, revealing
1374 // a gap in the download progress, causing the last blocks to be
1376 MSG_WriteChar (&msg, svc_downloaddata);
1377 MSG_WriteLong (&msg, downloadstart);
1378 MSG_WriteShort (&msg, downloadsize);
1379 if (downloadsize > 0)
1380 SZ_Write (&msg, data, downloadsize);
1383 // send the datagram
1384 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1388 =======================
1389 SV_UpdateToReliableMessages
1390 =======================
1392 void SV_UpdateToReliableMessages (void)
1401 // check for changes to be sent over the reliable streams
1402 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1404 // update the host_client fields we care about according to the entity fields
1405 host_client->edict = PRVM_EDICT_NUM(i+1);
1408 name = PRVM_GetString(host_client->edict->fields.server->netname);
1411 // always point the string back at host_client->name to keep it safe
1412 strlcpy (host_client->name, name, sizeof (host_client->name));
1413 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1414 if (strcmp(host_client->old_name, host_client->name))
1416 if (host_client->spawned)
1417 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1418 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1419 // send notification to all clients
1420 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1421 MSG_WriteByte (&sv.reliable_datagram, i);
1422 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1425 // DP_SV_CLIENTCOLORS
1426 // this is always found (since it's added by the progs loader)
1427 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
1428 host_client->colors = (int)val->_float;
1429 if (host_client->old_colors != host_client->colors)
1431 host_client->old_colors = host_client->colors;
1432 // send notification to all clients
1433 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1434 MSG_WriteByte (&sv.reliable_datagram, i);
1435 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1438 // NEXUIZ_PLAYERMODEL
1439 if( prog->fieldoffsets.playermodel >= 0 ) {
1440 model = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string);
1443 // always point the string back at host_client->name to keep it safe
1444 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1445 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1448 // NEXUIZ_PLAYERSKIN
1449 if( prog->fieldoffsets.playerskin >= 0 ) {
1450 skin = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string);
1453 // always point the string back at host_client->name to keep it safe
1454 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1455 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1459 host_client->frags = (int)host_client->edict->fields.server->frags;
1460 if (host_client->old_frags != host_client->frags)
1462 host_client->old_frags = host_client->frags;
1463 // send notification to all clients
1464 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1465 MSG_WriteByte (&sv.reliable_datagram, i);
1466 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1470 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1471 if (client->netconnection)
1472 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1474 SZ_Clear (&sv.reliable_datagram);
1479 =======================
1480 SV_SendClientMessages
1481 =======================
1483 void SV_SendClientMessages (void)
1485 int i, prepared = false;
1487 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1488 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1490 // update frags, names, etc
1491 SV_UpdateToReliableMessages();
1493 // build individual updates
1494 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1496 if (!host_client->active)
1498 if (!host_client->netconnection)
1501 if (host_client->netconnection->message.overflowed)
1503 SV_DropClient (true); // if the message couldn't send, kick off
1510 // only prepare entities once per frame
1511 SV_PrepareEntitiesForSending();
1513 SV_SendClientDatagram (host_client);
1516 // clear muzzle flashes
1520 void SV_StartDownload_f(void)
1522 if (host_client->download_file)
1523 host_client->download_started = true;
1526 void SV_Download_f(void)
1528 const char *whichpack, *whichpack2, *extension;
1530 if (Cmd_Argc() != 2)
1532 SV_ClientPrintf("usage: download <filename>\n");
1536 if (FS_CheckNastyPath(Cmd_Argv(1), false))
1538 SV_ClientPrintf("Download rejected: nasty filename \"%s\"\n", Cmd_Argv(1));
1542 if (host_client->download_file)
1544 // at this point we'll assume the previous download should be aborted
1545 Con_DPrintf("Download of %s aborted by %s starting a new download\n", host_client->download_name, host_client->name);
1546 Host_ClientCommands("\nstopdownload\n");
1548 // close the file and reset variables
1549 FS_Close(host_client->download_file);
1550 host_client->download_file = NULL;
1551 host_client->download_name[0] = 0;
1552 host_client->download_expectedposition = 0;
1553 host_client->download_started = false;
1556 if (!sv_allowdownloads.integer)
1558 SV_ClientPrintf("Downloads are disabled on this server\n");
1559 Host_ClientCommands("\nstopdownload\n");
1563 strlcpy(host_client->download_name, Cmd_Argv(1), sizeof(host_client->download_name));
1564 extension = FS_FileExtension(host_client->download_name);
1566 // host_client is asking to download a specified file
1567 if (developer.integer >= 100)
1568 Con_Printf("Download request for %s by %s\n", host_client->download_name, host_client->name);
1570 if (!FS_FileExists(host_client->download_name))
1572 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);
1573 Host_ClientCommands("\nstopdownload\n");
1577 // check if the user is trying to download part of registered Quake(r)
1578 whichpack = FS_WhichPack(host_client->download_name);
1579 whichpack2 = FS_WhichPack("gfx/pop.lmp");
1580 if ((whichpack && whichpack2 && !strcasecmp(whichpack, whichpack2)) || FS_IsRegisteredQuakePack(host_client->download_name))
1582 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);
1583 Host_ClientCommands("\nstopdownload\n");
1587 // check if the server has forbidden archive downloads entirely
1588 if (!sv_allowdownloads_inarchive.integer)
1590 whichpack = FS_WhichPack(host_client->download_name);
1593 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);
1594 Host_ClientCommands("\nstopdownload\n");
1599 if (!sv_allowdownloads_config.integer)
1601 if (!strcasecmp(extension, "cfg"))
1603 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);
1604 Host_ClientCommands("\nstopdownload\n");
1609 if (!sv_allowdownloads_dlcache.integer)
1611 if (!strncasecmp(host_client->download_name, "dlcache/", 8))
1613 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);
1614 Host_ClientCommands("\nstopdownload\n");
1619 if (!sv_allowdownloads_archive.integer)
1621 if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
1623 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);
1624 Host_ClientCommands("\nstopdownload\n");
1629 host_client->download_file = FS_Open(host_client->download_name, "rb", true, false);
1630 if (!host_client->download_file)
1632 SV_ClientPrintf("Download rejected: server could not open the file \"%s\"\n", host_client->download_name);
1633 Host_ClientCommands("\nstopdownload\n");
1637 if (FS_FileSize(host_client->download_file) > 1<<30)
1639 SV_ClientPrintf("Download rejected: file \"%s\" is very large\n", host_client->download_name);
1640 Host_ClientCommands("\nstopdownload\n");
1641 FS_Close(host_client->download_file);
1642 host_client->download_file = NULL;
1646 Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
1648 Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name);
1650 host_client->download_expectedposition = 0;
1651 host_client->download_started = false;
1653 // the rest of the download process is handled in SV_SendClientDatagram
1654 // and other code dealing with svc_downloaddata and clc_ackdownloaddata
1656 // no svc_downloaddata messages will be sent until sv_startdownload is
1657 // sent by the client
1661 ==============================================================================
1665 ==============================================================================
1674 int SV_ModelIndex(const char *s, int precachemode)
1676 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1677 char filename[MAX_QPATH];
1681 //if (precachemode == 2)
1683 strlcpy(filename, s, sizeof(filename));
1684 for (i = 2;i < limit;i++)
1686 if (!sv.model_precache[i][0])
1690 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))
1692 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1695 if (precachemode == 1)
1696 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1697 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1698 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1699 if (sv.state != ss_loading)
1701 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1702 MSG_WriteShort(&sv.reliable_datagram, i);
1703 MSG_WriteString(&sv.reliable_datagram, filename);
1707 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1710 if (!strcmp(sv.model_precache[i], filename))
1713 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1723 int SV_SoundIndex(const char *s, int precachemode)
1725 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1726 char filename[MAX_QPATH];
1730 //if (precachemode == 2)
1732 strlcpy(filename, s, sizeof(filename));
1733 for (i = 1;i < limit;i++)
1735 if (!sv.sound_precache[i][0])
1739 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))
1741 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1744 if (precachemode == 1)
1745 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1746 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1747 if (sv.state != ss_loading)
1749 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1750 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1751 MSG_WriteString(&sv.reliable_datagram, filename);
1755 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1758 if (!strcmp(sv.sound_precache[i], filename))
1761 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1765 // MUST match effectnameindex_t in client.h
1766 static const char *standardeffectnames[EFFECT_TOTAL] =
1774 "TE_SUPERSPIKEQUAD",
1790 "TE_TEI_BIGEXPLOSION",
1808 SV_ParticleEffectIndex
1812 int SV_ParticleEffectIndex(const char *name)
1814 int i, argc, linenumber, effectnameindex;
1815 fs_offset_t filesize;
1816 unsigned char *filedata;
1817 const char *text, *textstart, *textend;
1818 char argv[16][1024];
1819 if (!sv.particleeffectnamesloaded)
1821 sv.particleeffectnamesloaded = true;
1822 memset(sv.particleeffectname, 0, sizeof(sv.particleeffectname));
1823 for (i = 0;i < EFFECT_TOTAL;i++)
1824 strlcpy(sv.particleeffectname[i], standardeffectnames[i], sizeof(sv.particleeffectname[i]));
1825 filedata = FS_LoadFile("effectinfo.txt", tempmempool, true, &filesize);
1828 textstart = (const char *)filedata;
1829 textend = (const char *)filedata + filesize;
1831 for (linenumber = 1;;linenumber++)
1836 if (!COM_ParseToken(&text, true) || !strcmp(com_token, "\n"))
1840 strlcpy(argv[argc], com_token, sizeof(argv[argc]));
1844 if (com_token[0] == 0)
1845 break; // if the loop exited and it's not a \n, it's EOF
1848 if (!strcmp(argv[0], "effect"))
1852 for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME;effectnameindex++)
1854 if (sv.particleeffectname[effectnameindex][0])
1856 if (!strcmp(sv.particleeffectname[effectnameindex], argv[1]))
1861 strlcpy(sv.particleeffectname[effectnameindex], argv[1], sizeof(sv.particleeffectname[effectnameindex]));
1865 // if we run out of names, abort
1866 if (effectnameindex == SV_MAX_PARTICLEEFFECTNAME)
1868 Con_Printf("effectinfo.txt:%i: too many effects!\n", linenumber);
1877 // search for the name
1878 for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME && sv.particleeffectname[effectnameindex][0];effectnameindex++)
1879 if (!strcmp(sv.particleeffectname[effectnameindex], name))
1880 return effectnameindex;
1881 // return 0 if we couldn't find it
1891 void SV_CreateBaseline (void)
1893 int i, entnum, large;
1894 prvm_edict_t *svent;
1896 // LordHavoc: clear *all* states (note just active ones)
1897 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1899 // get the current server version
1900 svent = PRVM_EDICT_NUM(entnum);
1902 // LordHavoc: always clear state values, whether the entity is in use or not
1903 svent->priv.server->baseline = defaultstate;
1905 if (svent->priv.server->free)
1907 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1910 // create entity baseline
1911 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1912 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1913 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1914 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1915 if (entnum > 0 && entnum <= svs.maxclients)
1917 svent->priv.server->baseline.colormap = entnum;
1918 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1922 svent->priv.server->baseline.colormap = 0;
1923 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1927 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1930 // add to the message
1932 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1934 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1935 MSG_WriteShort (&sv.signon, entnum);
1939 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1940 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1944 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1945 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1947 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1948 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1949 for (i=0 ; i<3 ; i++)
1951 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1952 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1962 Grabs the current state of each client for saving across the
1963 transition to another level
1966 void SV_SaveSpawnparms (void)
1970 svs.serverflags = (int)prog->globals.server->serverflags;
1972 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1974 if (!host_client->active)
1977 // call the progs to get default spawn parms for the new client
1978 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1979 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1980 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1981 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1985 void SV_IncreaseEdicts(void)
1989 int oldmax_edicts = prog->max_edicts;
1990 void *oldedictsengineprivate = prog->edictprivate;
1991 void *oldedictsfields = prog->edictsfields;
1992 void *oldmoved_edicts = sv.moved_edicts;
1994 if (prog->max_edicts >= MAX_EDICTS)
1997 // links don't survive the transition, so unlink everything
1998 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2000 if (!ent->priv.server->free)
2001 SV_UnlinkEdict(prog->edicts + i);
2002 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
2004 World_Clear(&sv.world);
2006 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
2007 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
2008 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
2009 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2011 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
2012 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
2014 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2016 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
2017 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
2018 // link every entity except world
2019 if (!ent->priv.server->free)
2020 SV_LinkEdict(ent, false);
2023 PR_Free(oldedictsengineprivate);
2024 PR_Free(oldedictsfields);
2025 PR_Free(oldmoved_edicts);
2032 This is called at the start of each level
2035 extern float scr_centertime_off;
2037 void SV_SpawnServer (const char *server)
2042 model_t *worldmodel;
2043 char modelname[sizeof(sv.modelname)];
2045 Con_DPrintf("SpawnServer: %s\n", server);
2047 if (cls.state != ca_dedicated)
2048 SCR_BeginLoadingPlaque();
2050 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
2051 worldmodel = Mod_ForName(modelname, false, true, true);
2052 if (!worldmodel || !worldmodel->TraceBox)
2054 Con_Printf("Couldn't load map %s\n", modelname);
2058 // let's not have any servers with no name
2059 if (hostname.string[0] == 0)
2060 Cvar_Set ("hostname", "UNNAMED");
2061 scr_centertime_off = 0;
2063 svs.changelevel_issued = false; // now safe to issue another
2065 // make the map a required file for clients
2066 Curl_ClearRequirements();
2067 Curl_RequireFile(modelname);
2070 // tell all connected clients that we are going to a new level
2075 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
2077 if (client->netconnection)
2079 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
2080 MSG_WriteString(&client->netconnection->message, "reconnect\n");
2087 NetConn_OpenServerPorts(true);
2091 // make cvars consistant
2094 Cvar_SetValue ("deathmatch", 0);
2095 // LordHavoc: it can be useful to have skills outside the range 0-3...
2096 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
2097 //Cvar_SetValue ("skill", (float)current_skill);
2098 current_skill = (int)(skill.value + 0.5);
2101 // set up the new server
2103 memset (&sv, 0, sizeof(sv));
2104 // if running a local client, make sure it doesn't try to access the last
2105 // level's data which is no longer valiud
2108 if(*sv_random_seed.string)
2110 srand(sv_random_seed.integer);
2111 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);
2118 strlcpy (sv.name, server, sizeof (sv.name));
2120 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
2121 if (sv.protocol == PROTOCOL_UNKNOWN)
2124 Protocol_Names(buffer, sizeof(buffer));
2125 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
2126 sv.protocol = PROTOCOL_QUAKE;
2131 // load progs to get entity field count
2132 //PR_LoadProgs ( sv_progs.string );
2134 // allocate server memory
2135 /*// start out with just enough room for clients and a reasonable estimate of entities
2136 prog->max_edicts = max(svs.maxclients + 1, 512);
2137 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
2139 // prvm_edict_t structures (hidden from progs)
2140 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
2141 // engine private structures (hidden from progs)
2142 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
2143 // progs fields, often accessed by server
2144 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
2145 // used by PushMove to move back pushed entities
2146 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2147 /*for (i = 0;i < prog->max_edicts;i++)
2149 ent = prog->edicts + i;
2150 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
2151 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
2154 // reset client csqc entity versions right away.
2155 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2156 EntityFrameCSQC_InitClientVersions(i, true);
2158 sv.datagram.maxsize = sizeof(sv.datagram_buf);
2159 sv.datagram.cursize = 0;
2160 sv.datagram.data = sv.datagram_buf;
2162 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
2163 sv.reliable_datagram.cursize = 0;
2164 sv.reliable_datagram.data = sv.reliable_datagram_buf;
2166 sv.signon.maxsize = sizeof(sv.signon_buf);
2167 sv.signon.cursize = 0;
2168 sv.signon.data = sv.signon_buf;
2170 // leave slots at start for clients only
2171 //prog->num_edicts = svs.maxclients+1;
2173 sv.state = ss_loading;
2174 prog->allowworldwrites = true;
2177 prog->globals.server->time = sv.time = 1.0;
2180 worldmodel->used = true;
2182 strlcpy (sv.name, server, sizeof (sv.name));
2183 strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
2184 sv.worldmodel = worldmodel;
2185 sv.models[1] = sv.worldmodel;
2188 // clear world interaction links
2190 VectorCopy(sv.worldmodel->normalmins, sv.world.areagrid_mins);
2191 VectorCopy(sv.worldmodel->normalmaxs, sv.world.areagrid_maxs);
2192 World_Clear(&sv.world);
2194 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
2196 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
2197 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
2198 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
2200 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
2201 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
2205 // load the rest of the entities
2207 // AK possible hack since num_edicts is still 0
2208 ent = PRVM_EDICT_NUM(0);
2209 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
2210 ent->priv.server->free = false;
2211 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
2212 ent->fields.server->modelindex = 1; // world model
2213 ent->fields.server->solid = SOLID_BSP;
2214 ent->fields.server->movetype = MOVETYPE_PUSH;
2215 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->mins);
2216 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->maxs);
2217 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->absmin);
2218 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->absmax);
2221 prog->globals.server->coop = coop.integer;
2223 prog->globals.server->deathmatch = deathmatch.integer;
2225 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
2227 // serverflags are for cross level information (sigils)
2228 prog->globals.server->serverflags = svs.serverflags;
2230 // we need to reset the spawned flag on all connected clients here so that
2231 // their thinks don't run during startup (before PutClientInServer)
2232 // we also need to set up the client entities now
2233 // and we need to set the ->edict pointers to point into the progs edicts
2234 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2236 host_client->spawned = false;
2237 host_client->edict = PRVM_EDICT_NUM(i + 1);
2238 PRVM_ED_ClearEdict(host_client->edict);
2241 // load replacement entity file if found
2242 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
2244 Con_Printf("Loaded maps/%s.ent\n", sv.name);
2245 PRVM_ED_LoadFromFile (entities);
2249 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
2252 // LordHavoc: clear world angles (to fix e3m3.bsp)
2253 VectorClear(prog->edicts->fields.server->angles);
2255 // all setup is completed, any further precache statements are errors
2256 sv.state = ss_active;
2257 prog->allowworldwrites = false;
2259 // run two frames to allow everything to settle
2260 for (i = 0;i < 2;i++)
2268 // create a baseline for more efficient communications
2269 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
2270 SV_CreateBaseline ();
2272 // send serverinfo to all connected clients, and set up botclients coming back from a level change
2273 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2275 if (!host_client->active)
2277 if (host_client->netconnection)
2278 SV_SendServerinfo(host_client);
2282 // if client is a botclient coming from a level change, we need to
2283 // set up client info that normally requires networking
2285 // copy spawn parms out of the client_t
2286 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
2287 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
2289 // call the spawn function
2290 host_client->clientconnectcalled = true;
2291 prog->globals.server->time = sv.time;
2292 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2293 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
2294 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
2295 host_client->spawned = true;
2299 Con_DPrint("Server spawned.\n");
2300 NetConn_Heartbeat (2);
2305 /////////////////////////////////////////////////////
2308 void SV_VM_CB_BeginIncreaseEdicts(void)
2313 PRVM_Free( sv.moved_edicts );
2314 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2316 // links don't survive the transition, so unlink everything
2317 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2319 if (!ent->priv.server->free)
2320 World_UnlinkEdict(prog->edicts + i);
2321 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
2323 World_Clear(&sv.world);
2326 void SV_VM_CB_EndIncreaseEdicts(void)
2331 // link every entity except world
2332 for (i = 1, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2333 if (!ent->priv.server->free)
2334 SV_LinkEdict(ent, false);
2337 void SV_VM_CB_InitEdict(prvm_edict_t *e)
2339 // LordHavoc: for consistency set these here
2340 int num = PRVM_NUM_FOR_EDICT(e) - 1;
2342 e->priv.server->move = false; // don't move on first frame
2344 if (num >= 0 && num < svs.maxclients)
2347 // set colormap and team on newly created player entity
2348 e->fields.server->colormap = num + 1;
2349 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
2350 // set netname/clientcolors back to client values so that
2351 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
2353 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
2354 if ((val = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.clientcolors)))
2355 val->_float = svs.clients[num].colors;
2356 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
2357 if( prog->fieldoffsets.playermodel >= 0 )
2358 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
2359 if( prog->fieldoffsets.playerskin >= 0 )
2360 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
2364 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
2366 World_UnlinkEdict(ed); // unlink from world bsp
2368 ed->fields.server->model = 0;
2369 ed->fields.server->takedamage = 0;
2370 ed->fields.server->modelindex = 0;
2371 ed->fields.server->colormap = 0;
2372 ed->fields.server->skin = 0;
2373 ed->fields.server->frame = 0;
2374 VectorClear(ed->fields.server->origin);
2375 VectorClear(ed->fields.server->angles);
2376 ed->fields.server->nextthink = -1;
2377 ed->fields.server->solid = 0;
2380 void SV_VM_CB_CountEdicts(void)
2384 int active, models, solid, step;
2386 active = models = solid = step = 0;
2387 for (i=0 ; i<prog->num_edicts ; i++)
2389 ent = PRVM_EDICT_NUM(i);
2390 if (ent->priv.server->free)
2393 if (ent->fields.server->solid)
2395 if (ent->fields.server->model)
2397 if (ent->fields.server->movetype == MOVETYPE_STEP)
2401 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2402 Con_Printf("active :%3i\n", active);
2403 Con_Printf("view :%3i\n", models);
2404 Con_Printf("touch :%3i\n", solid);
2405 Con_Printf("step :%3i\n", step);
2408 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2410 // remove things from different skill levels or deathmatch
2411 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2413 if (deathmatch.integer)
2415 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2420 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2421 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2422 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2430 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)"};
2431 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2432 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2433 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2434 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2435 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2436 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2437 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2438 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2439 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2440 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2441 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2442 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2443 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2444 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2445 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2446 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2447 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2448 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2449 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2450 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2451 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2452 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2453 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2454 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2455 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2456 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2457 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2458 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2459 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2460 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2461 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2462 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2464 void SV_VM_Init(void)
2466 Cvar_RegisterVariable (&pr_checkextension);
2467 Cvar_RegisterVariable (&nomonsters);
2468 Cvar_RegisterVariable (&gamecfg);
2469 Cvar_RegisterVariable (&scratch1);
2470 Cvar_RegisterVariable (&scratch2);
2471 Cvar_RegisterVariable (&scratch3);
2472 Cvar_RegisterVariable (&scratch4);
2473 Cvar_RegisterVariable (&savedgamecfg);
2474 Cvar_RegisterVariable (&saved1);
2475 Cvar_RegisterVariable (&saved2);
2476 Cvar_RegisterVariable (&saved3);
2477 Cvar_RegisterVariable (&saved4);
2478 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2479 if (gamemode == GAME_NEHAHRA)
2481 Cvar_RegisterVariable (&nehx00);
2482 Cvar_RegisterVariable (&nehx01);
2483 Cvar_RegisterVariable (&nehx02);
2484 Cvar_RegisterVariable (&nehx03);
2485 Cvar_RegisterVariable (&nehx04);
2486 Cvar_RegisterVariable (&nehx05);
2487 Cvar_RegisterVariable (&nehx06);
2488 Cvar_RegisterVariable (&nehx07);
2489 Cvar_RegisterVariable (&nehx08);
2490 Cvar_RegisterVariable (&nehx09);
2491 Cvar_RegisterVariable (&nehx10);
2492 Cvar_RegisterVariable (&nehx11);
2493 Cvar_RegisterVariable (&nehx12);
2494 Cvar_RegisterVariable (&nehx13);
2495 Cvar_RegisterVariable (&nehx14);
2496 Cvar_RegisterVariable (&nehx15);
2497 Cvar_RegisterVariable (&nehx16);
2498 Cvar_RegisterVariable (&nehx17);
2499 Cvar_RegisterVariable (&nehx18);
2500 Cvar_RegisterVariable (&nehx19);
2502 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2505 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2507 prvm_required_field_t reqfields[] =
2509 {ev_entity, "cursor_trace_ent"},
2510 {ev_entity, "drawonlytoclient"},
2511 {ev_entity, "exteriormodeltoclient"},
2512 {ev_entity, "nodrawtoclient"},
2513 {ev_entity, "tag_entity"},
2514 {ev_entity, "viewmodelforclient"},
2515 {ev_float, "alpha"},
2516 {ev_float, "ammo_cells1"},
2517 {ev_float, "ammo_lava_nails"},
2518 {ev_float, "ammo_multi_rockets"},
2519 {ev_float, "ammo_nails1"},
2520 {ev_float, "ammo_plasma"},
2521 {ev_float, "ammo_rockets1"},
2522 {ev_float, "ammo_shells1"},
2523 {ev_float, "button3"},
2524 {ev_float, "button4"},
2525 {ev_float, "button5"},
2526 {ev_float, "button6"},
2527 {ev_float, "button7"},
2528 {ev_float, "button8"},
2529 {ev_float, "button9"},
2530 {ev_float, "button10"},
2531 {ev_float, "button11"},
2532 {ev_float, "button12"},
2533 {ev_float, "button13"},
2534 {ev_float, "button14"},
2535 {ev_float, "button15"},
2536 {ev_float, "button16"},
2537 {ev_float, "buttonchat"},
2538 {ev_float, "buttonuse"},
2539 {ev_float, "clientcolors"},
2540 {ev_float, "cursor_active"},
2541 {ev_float, "fullbright"},
2542 {ev_float, "glow_color"},
2543 {ev_float, "glow_size"},
2544 {ev_float, "glow_trail"},
2545 {ev_float, "gravity"},
2546 {ev_float, "idealpitch"},
2547 {ev_float, "items2"},
2548 {ev_float, "light_lev"},
2549 {ev_float, "pflags"},
2551 {ev_float, "pitch_speed"},
2552 {ev_float, "pmodel"},
2553 {ev_float, "renderamt"}, // HalfLife support
2554 {ev_float, "rendermode"}, // HalfLife support
2555 {ev_float, "scale"},
2556 {ev_float, "style"},
2557 {ev_float, "tag_index"},
2558 {ev_float, "Version"},
2559 {ev_float, "viewzoom"},
2560 {ev_vector, "color"},
2561 {ev_vector, "colormod"},
2562 {ev_vector, "cursor_screen"},
2563 {ev_vector, "cursor_trace_endpos"},
2564 {ev_vector, "cursor_trace_start"},
2565 {ev_vector, "movement"},
2566 {ev_vector, "punchvector"},
2567 {ev_string, "playermodel"},
2568 {ev_string, "playerskin"},
2569 {ev_function, "SendEntity"},
2570 {ev_function, "customizeentityforclient"},
2571 // DRESK - Support for Entity Contents Transition Event
2572 {ev_function, "contentstransition"},
2575 void SV_VM_Setup(void)
2577 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
2578 extern cvar_t csqc_progcrc;
2579 extern cvar_t csqc_progsize;
2580 size_t csprogsdatasize;
2582 PRVM_InitProg( PRVM_SERVERPROG );
2584 // allocate the mempools
2585 // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
2586 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2587 prog->builtins = vm_sv_builtins;
2588 prog->numbuiltins = vm_sv_numbuiltins;
2589 prog->headercrc = PROGHEADER_CRC;
2590 prog->max_edicts = 512;
2591 prog->limit_edicts = MAX_EDICTS;
2592 prog->reserved_edicts = svs.maxclients;
2593 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2594 prog->name = "server";
2595 prog->extensionstring = vm_sv_extensions;
2596 prog->loadintoworld = true;
2598 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2599 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2600 prog->init_edict = SV_VM_CB_InitEdict;
2601 prog->free_edict = SV_VM_CB_FreeEdict;
2602 prog->count_edicts = SV_VM_CB_CountEdicts;
2603 prog->load_edict = SV_VM_CB_LoadEdict;
2604 prog->init_cmd = VM_SV_Cmd_Init;
2605 prog->reset_cmd = VM_SV_Cmd_Reset;
2606 prog->error_cmd = Host_Error;
2608 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2609 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields, 0, NULL );
2611 // some mods compiled with scrambling compilers lack certain critical
2612 // global names and field names such as "self" and "time" and "nextthink"
2613 // so we have to set these offsets manually, matching the entvars_t
2614 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, angles);
2615 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, chain);
2616 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, classname);
2617 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, frame);
2618 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, groundentity);
2619 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ideal_yaw);
2620 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, nextthink);
2621 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, think);
2622 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, yaw_speed);
2623 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, self);
2624 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, time);
2625 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_forward);
2626 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_right);
2627 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_up);
2628 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_allsolid);
2629 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_startsolid);
2630 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_fraction);
2631 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inwater);
2632 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inopen);
2633 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_endpos);
2634 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_normal);
2635 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_dist);
2636 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_ent);
2637 // OP_STATE is always supported on server (due to entvars_t)
2638 prog->flag |= PRVM_OP_STATE;
2640 VM_AutoSentStats_Clear();//[515]: csqc
2641 EntityFrameCSQC_ClearVersions();//[515]: csqc
2645 // 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
2646 sv.csqc_progname[0] = 0;
2647 sv.csqc_progcrc = FS_CRCFile(csqc_progname.string, &csprogsdatasize);
2648 sv.csqc_progsize = csprogsdatasize;
2649 if (sv.csqc_progsize > 0)
2651 strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
2652 Con_DPrintf("server detected csqc progs file \"%s\" with size %i and crc %i\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
2656 void SV_VM_Begin(void)
2659 PRVM_SetProg( PRVM_SERVERPROG );
2661 prog->globals.server->time = (float) sv.time;
2664 void SV_VM_End(void)