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 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
784 VectorCopy(cullmins, ent->priv.server->cullmins);
785 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
786 ent->priv.server->pvs_numclusters = -1;
787 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
789 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
790 if (i <= MAX_ENTITYCLUSTERS)
791 ent->priv.server->pvs_numclusters = i;
798 void SV_PrepareEntitiesForSending(void)
802 // send all entities that touch the pvs
804 sendentitiesindex[0] = NULL;
805 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
806 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
808 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
810 sendentitiesindex[e] = sendentities + numsendentities;
816 static int sententitiesmark = 0;
817 static int sententities[MAX_EDICTS];
818 static int sententitiesconsideration[MAX_EDICTS];
819 static int sv_writeentitiestoclient_culled_pvs;
820 static int sv_writeentitiestoclient_culled_trace;
821 static int sv_writeentitiestoclient_visibleentities;
822 static int sv_writeentitiestoclient_totalentities;
823 //static entity_frame_t sv_writeentitiestoclient_entityframe;
824 static int sv_writeentitiestoclient_clentnum;
825 static vec3_t sv_writeentitiestoclient_testeye;
826 static client_t *sv_writeentitiestoclient_client;
828 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
833 if (sententitiesconsideration[s->number] == sententitiesmark)
835 sententitiesconsideration[s->number] = sententitiesmark;
836 sv_writeentitiestoclient_totalentities++;
838 if (s->customizeentityforclient)
840 prog->globals.server->self = s->number;
841 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
842 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
843 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
847 // never reject player
848 if (s->number != sv_writeentitiestoclient_clentnum)
850 // check various rejection conditions
851 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
853 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
855 if (s->effects & EF_NODRAW)
857 // LordHavoc: only send entities with a model or important effects
858 if (!s->modelindex && s->specialvisibilityradius == 0)
861 isbmodel = (model = sv.models[s->modelindex]) != NULL && model->name[0] == '*';
862 // viewmodels don't have visibility checking
863 if (s->viewmodelforclient)
865 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
868 else if (s->tagentity)
870 // tag attached entities simply check their parent
871 if (!sendentitiesindex[s->tagentity])
873 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
874 if (sententities[s->tagentity] != sententitiesmark)
877 // always send world submodels in newer protocols because they don't
878 // generate much traffic (in old protocols they hog bandwidth)
879 // but only if sv_cullentities_alwayssendbmodels is on
880 else if (!(s->effects & EF_NODEPTHTEST) && (!isbmodel || !sv_cullentities_nevercullbmodels.integer || sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE))
882 // entity has survived every check so far, check if visible
883 ed = PRVM_EDICT_NUM(s->number);
885 // if not touching a visible leaf
886 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
888 if (ed->priv.server->pvs_numclusters < 0)
890 // entity too big for clusters list
891 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
893 sv_writeentitiestoclient_culled_pvs++;
900 // check cached clusters list
901 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
902 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
904 if (i == ed->priv.server->pvs_numclusters)
906 sv_writeentitiestoclient_culled_pvs++;
912 // or not seen by random tracelines
913 if (sv_cullentities_trace.integer && !isbmodel)
915 int samples = s->specialvisibilityradius ? sv_cullentities_trace_samples_extra.integer : sv_cullentities_trace_samples.integer;
916 float enlarge = sv_cullentities_trace_enlarge.value;
918 qboolean visible = TRUE;
922 if(Mod_CanSeeBox_Trace(samples, enlarge, sv.worldmodel, sv_writeentitiestoclient_testeye, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
923 break; // directly visible from the server's view
925 if(sv_cullentities_trace_prediction.integer)
929 // get player velocity
930 float predtime = bound(0, host_client->ping, 0.2); // / 2
931 // sorry, no wallhacking by high ping please, and at 200ms
932 // ping a FPS is annoying to play anyway and a player is
933 // likely to have changed his direction
934 VectorMA(sv_writeentitiestoclient_testeye, predtime, host_client->edict->fields.server->velocity, predeye);
935 if(sv.worldmodel->brush.TraceLineOfSight(sv.worldmodel, sv_writeentitiestoclient_testeye, predeye)) // must be able to go there...
937 if(Mod_CanSeeBox_Trace(samples, enlarge, sv.worldmodel, predeye, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
938 break; // directly visible from the predicted view
942 //Con_DPrintf("Trying to walk into solid in a pingtime... not predicting for culling\n");
946 // when we get here, we can't see the entity
952 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + sv_cullentities_trace_delay.value;
954 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
956 sv_writeentitiestoclient_culled_trace++;
963 // this just marks it for sending
964 // FIXME: it would be more efficient to send here, but the entity
965 // compressor isn't that flexible
966 sv_writeentitiestoclient_visibleentities++;
967 sententities[s->number] = sententitiesmark;
970 entity_state_t sendstates[MAX_EDICTS];
971 extern int csqc_clent;
973 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
975 int i, numsendstates;
978 // if there isn't enough space to accomplish anything, skip it
979 if (msg->cursize + 25 > msg->maxsize)
982 sv_writeentitiestoclient_client = client;
984 sv_writeentitiestoclient_culled_pvs = 0;
985 sv_writeentitiestoclient_culled_trace = 0;
986 sv_writeentitiestoclient_visibleentities = 0;
987 sv_writeentitiestoclient_totalentities = 0;
989 // find the client's PVS
990 // the real place being tested from
991 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
992 sv_writeentitiestoclient_pvsbytes = 0;
993 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
994 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
996 csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
1000 for (i = 0;i < numsendentities;i++)
1001 SV_MarkWriteEntityStateToClient(sendentities + i);
1004 for (i = 0;i < numsendentities;i++)
1006 if (sententities[sendentities[i].number] == sententitiesmark)
1008 s = &sendstates[numsendstates++];
1009 *s = sendentities[i];
1010 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
1011 s->flags |= RENDER_EXTERIORMODEL;
1015 if (sv_cullentities_stats.integer)
1016 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);
1018 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
1020 if (client->entitydatabase5)
1021 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
1022 else if (client->entitydatabase4)
1023 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
1024 else if (client->entitydatabase)
1025 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
1027 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
1036 void SV_CleanupEnts (void)
1041 ent = PRVM_NEXT_EDICT(prog->edicts);
1042 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
1043 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
1048 SV_WriteClientdataToMessage
1052 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1056 prvm_edict_t *other;
1064 // send a damage message
1066 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
1068 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
1069 MSG_WriteByte (msg, svc_damage);
1070 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
1071 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
1072 for (i=0 ; i<3 ; i++)
1073 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
1075 ent->fields.server->dmg_take = 0;
1076 ent->fields.server->dmg_save = 0;
1080 // send the current viewpos offset from the view entity
1082 SV_SetIdealPitch (); // how much to look up / down ideally
1084 // a fixangle might get lost in a dropped packet. Oh well.
1085 if ( ent->fields.server->fixangle )
1087 MSG_WriteByte (msg, svc_setangle);
1088 for (i=0 ; i < 3 ; i++)
1089 MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
1090 ent->fields.server->fixangle = 0;
1093 // stuff the sigil bits into the high bits of items for sbar, or else
1095 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.items2);
1096 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1097 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1099 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1101 VectorClear(punchvector);
1102 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.punchvector)))
1103 VectorCopy(val->vector, punchvector);
1105 // cache weapon model name and index in client struct to save time
1106 // (this search can be almost 1% of cpu time!)
1107 s = PRVM_GetString(ent->fields.server->weaponmodel);
1108 if (strcmp(s, client->weaponmodel))
1110 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1111 client->weaponmodelindex = SV_ModelIndex(s, 1);
1115 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewzoom)))
1116 viewzoom = (int)(val->_float * 255.0f);
1122 if ((int)ent->fields.server->flags & FL_ONGROUND)
1123 bits |= SU_ONGROUND;
1124 if (ent->fields.server->waterlevel >= 2)
1126 if (ent->fields.server->idealpitch)
1127 bits |= SU_IDEALPITCH;
1129 for (i=0 ; i<3 ; i++)
1131 if (ent->fields.server->punchangle[i])
1132 bits |= (SU_PUNCH1<<i);
1133 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1135 bits |= (SU_PUNCHVEC1<<i);
1136 if (ent->fields.server->velocity[i])
1137 bits |= (SU_VELOCITY1<<i);
1140 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1141 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1142 stats[STAT_ITEMS] = items;
1143 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1144 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1145 stats[STAT_WEAPON] = client->weaponmodelindex;
1146 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1147 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1148 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1149 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1150 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1151 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1152 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1153 stats[STAT_VIEWZOOM] = viewzoom;
1154 stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1155 stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1156 // the QC bumps these itself by sending svc_'s, so we have to keep them
1157 // zero or they'll be corrected by the engine
1158 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1159 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1161 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)
1163 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1165 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1166 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1168 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1169 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1170 if (viewzoom != 255)
1171 bits |= SU_VIEWZOOM;
1176 if (bits >= 16777216)
1180 MSG_WriteByte (msg, svc_clientdata);
1181 MSG_WriteShort (msg, bits);
1182 if (bits & SU_EXTEND1)
1183 MSG_WriteByte(msg, bits >> 16);
1184 if (bits & SU_EXTEND2)
1185 MSG_WriteByte(msg, bits >> 24);
1187 if (bits & SU_VIEWHEIGHT)
1188 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1190 if (bits & SU_IDEALPITCH)
1191 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1193 for (i=0 ; i<3 ; i++)
1195 if (bits & (SU_PUNCH1<<i))
1197 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1198 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1200 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1202 if (bits & (SU_PUNCHVEC1<<i))
1204 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1205 MSG_WriteCoord16i(msg, punchvector[i]);
1207 MSG_WriteCoord32f(msg, punchvector[i]);
1209 if (bits & (SU_VELOCITY1<<i))
1211 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1212 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1214 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1218 if (bits & SU_ITEMS)
1219 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1221 if (sv.protocol == PROTOCOL_DARKPLACES5)
1223 if (bits & SU_WEAPONFRAME)
1224 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1225 if (bits & SU_ARMOR)
1226 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1227 if (bits & SU_WEAPON)
1228 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1229 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1230 MSG_WriteShort (msg, stats[STAT_AMMO]);
1231 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1232 MSG_WriteShort (msg, stats[STAT_NAILS]);
1233 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1234 MSG_WriteShort (msg, stats[STAT_CELLS]);
1235 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1236 if (bits & SU_VIEWZOOM)
1237 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1239 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)
1241 if (bits & SU_WEAPONFRAME)
1242 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1243 if (bits & SU_ARMOR)
1244 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1245 if (bits & SU_WEAPON)
1246 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1247 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1248 MSG_WriteByte (msg, stats[STAT_AMMO]);
1249 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1250 MSG_WriteByte (msg, stats[STAT_NAILS]);
1251 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1252 MSG_WriteByte (msg, stats[STAT_CELLS]);
1253 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1255 for (i = 0;i < 32;i++)
1256 if (stats[STAT_WEAPON] & (1<<i))
1258 MSG_WriteByte (msg, i);
1261 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1262 if (bits & SU_VIEWZOOM)
1264 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1265 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1267 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1273 =======================
1274 SV_SendClientDatagram
1275 =======================
1277 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1278 void SV_SendClientDatagram (client_t *client)
1280 int rate, maxrate, maxsize, maxsize2, downloadsize;
1282 int stats[MAX_CL_STATS];
1284 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1286 // for good singleplayer, send huge packets
1287 maxsize = sizeof(sv_sendclientdatagram_buf);
1288 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1290 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)
1292 // no rate limiting support on older protocols because dp protocols
1293 // 1-4 kick the client off if they overflow, and quake protocol shows
1294 // less than the full entity set if rate limited
1300 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1301 maxrate = max(NET_MINRATE, sv_maxrate.integer);
1302 if (sv_maxrate.integer != maxrate)
1303 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1305 // this rate limiting does not understand sys_ticrate 0
1306 // (but no one should be running that on a server!)
1307 rate = bound(NET_MINRATE, client->rate, maxrate);
1308 rate = (int)(rate * sys_ticrate.value);
1309 maxsize = bound(50, rate, 1400);
1313 // while downloading, limit entity updates to half the packet
1314 // (any leftover space will be used for downloading)
1315 if (host_client->download_file)
1318 msg.data = sv_sendclientdatagram_buf;
1319 msg.maxsize = maxsize;
1322 if (host_client->spawned)
1324 MSG_WriteByte (&msg, svc_time);
1325 MSG_WriteFloat (&msg, sv.time);
1327 // add the client specific data to the datagram
1328 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1329 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1330 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1332 // expand packet size to allow effects to go over the rate limit
1333 // (dropping them is FAR too ugly)
1334 msg.maxsize = maxsize2;
1336 // copy the server datagram if there is space
1337 // FIXME: put in delayed queue of effects to send
1338 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1339 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1341 else if (realtime > client->keepalivetime)
1343 // the player isn't totally in the game yet
1344 // send small keepalive messages if too much time has passed
1345 msg.maxsize = maxsize2;
1346 client->keepalivetime = realtime + 5;
1347 MSG_WriteChar (&msg, svc_nop);
1350 msg.maxsize = maxsize2;
1352 // if a download is active, see if there is room to fit some download data
1354 downloadsize = maxsize * 2 - msg.cursize - 7;
1355 if (host_client->download_file && host_client->download_started && downloadsize > 0)
1357 fs_offset_t downloadstart;
1358 unsigned char data[1400];
1359 downloadstart = FS_Tell(host_client->download_file);
1360 downloadsize = min(downloadsize, (int)sizeof(data));
1361 downloadsize = FS_Read(host_client->download_file, data, downloadsize);
1362 // note this sends empty messages if at the end of the file, which is
1363 // necessary to keep the packet loss logic working
1364 // (the last blocks may be lost and need to be re-sent, and that will
1365 // only occur if the client acks the empty end messages, revealing
1366 // a gap in the download progress, causing the last blocks to be
1368 MSG_WriteChar (&msg, svc_downloaddata);
1369 MSG_WriteLong (&msg, downloadstart);
1370 MSG_WriteShort (&msg, downloadsize);
1371 if (downloadsize > 0)
1372 SZ_Write (&msg, data, downloadsize);
1375 // send the datagram
1376 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1380 =======================
1381 SV_UpdateToReliableMessages
1382 =======================
1384 void SV_UpdateToReliableMessages (void)
1393 // check for changes to be sent over the reliable streams
1394 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1396 // update the host_client fields we care about according to the entity fields
1397 host_client->edict = PRVM_EDICT_NUM(i+1);
1400 name = PRVM_GetString(host_client->edict->fields.server->netname);
1403 // always point the string back at host_client->name to keep it safe
1404 strlcpy (host_client->name, name, sizeof (host_client->name));
1405 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1406 if (strcmp(host_client->old_name, host_client->name))
1408 if (host_client->spawned)
1409 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1410 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1411 // send notification to all clients
1412 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1413 MSG_WriteByte (&sv.reliable_datagram, i);
1414 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1417 // DP_SV_CLIENTCOLORS
1418 // this is always found (since it's added by the progs loader)
1419 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
1420 host_client->colors = (int)val->_float;
1421 if (host_client->old_colors != host_client->colors)
1423 host_client->old_colors = host_client->colors;
1424 // send notification to all clients
1425 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1426 MSG_WriteByte (&sv.reliable_datagram, i);
1427 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1430 // NEXUIZ_PLAYERMODEL
1431 if( prog->fieldoffsets.playermodel >= 0 ) {
1432 model = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string);
1435 // always point the string back at host_client->name to keep it safe
1436 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1437 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1440 // NEXUIZ_PLAYERSKIN
1441 if( prog->fieldoffsets.playerskin >= 0 ) {
1442 skin = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string);
1445 // always point the string back at host_client->name to keep it safe
1446 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1447 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1451 host_client->frags = (int)host_client->edict->fields.server->frags;
1452 if (host_client->old_frags != host_client->frags)
1454 host_client->old_frags = host_client->frags;
1455 // send notification to all clients
1456 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1457 MSG_WriteByte (&sv.reliable_datagram, i);
1458 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1462 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1463 if (client->netconnection)
1464 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1466 SZ_Clear (&sv.reliable_datagram);
1471 =======================
1472 SV_SendClientMessages
1473 =======================
1475 void SV_SendClientMessages (void)
1477 int i, prepared = false;
1479 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1480 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1482 // update frags, names, etc
1483 SV_UpdateToReliableMessages();
1485 // build individual updates
1486 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1488 if (!host_client->active)
1490 if (!host_client->netconnection)
1493 if (host_client->netconnection->message.overflowed)
1495 SV_DropClient (true); // if the message couldn't send, kick off
1502 // only prepare entities once per frame
1503 SV_PrepareEntitiesForSending();
1505 SV_SendClientDatagram (host_client);
1508 // clear muzzle flashes
1512 void SV_StartDownload_f(void)
1514 if (host_client->download_file)
1515 host_client->download_started = true;
1518 void SV_Download_f(void)
1520 const char *whichpack, *whichpack2, *extension;
1522 if (Cmd_Argc() != 2)
1524 SV_ClientPrintf("usage: download <filename>\n");
1528 if (FS_CheckNastyPath(Cmd_Argv(1), false))
1530 SV_ClientPrintf("Download rejected: nasty filename \"%s\"\n", Cmd_Argv(1));
1534 if (host_client->download_file)
1536 // at this point we'll assume the previous download should be aborted
1537 Con_DPrintf("Download of %s aborted by %s starting a new download\n", host_client->download_name, host_client->name);
1538 Host_ClientCommands("\nstopdownload\n");
1540 // close the file and reset variables
1541 FS_Close(host_client->download_file);
1542 host_client->download_file = NULL;
1543 host_client->download_name[0] = 0;
1544 host_client->download_expectedposition = 0;
1545 host_client->download_started = false;
1548 if (!sv_allowdownloads.integer)
1550 SV_ClientPrintf("Downloads are disabled on this server\n");
1551 Host_ClientCommands("\nstopdownload\n");
1555 strlcpy(host_client->download_name, Cmd_Argv(1), sizeof(host_client->download_name));
1556 extension = FS_FileExtension(host_client->download_name);
1558 // host_client is asking to download a specified file
1559 if (developer.integer >= 100)
1560 Con_Printf("Download request for %s by %s\n", host_client->download_name, host_client->name);
1562 if (!FS_FileExists(host_client->download_name))
1564 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);
1565 Host_ClientCommands("\nstopdownload\n");
1569 // check if the user is trying to download part of registered Quake(r)
1570 whichpack = FS_WhichPack(host_client->download_name);
1571 whichpack2 = FS_WhichPack("gfx/pop.lmp");
1572 if ((whichpack && whichpack2 && !strcasecmp(whichpack, whichpack2)) || FS_IsRegisteredQuakePack(host_client->download_name))
1574 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);
1575 Host_ClientCommands("\nstopdownload\n");
1579 // check if the server has forbidden archive downloads entirely
1580 if (!sv_allowdownloads_inarchive.integer)
1582 whichpack = FS_WhichPack(host_client->download_name);
1585 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);
1586 Host_ClientCommands("\nstopdownload\n");
1591 if (!sv_allowdownloads_config.integer)
1593 if (!strcasecmp(extension, "cfg"))
1595 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);
1596 Host_ClientCommands("\nstopdownload\n");
1601 if (!sv_allowdownloads_dlcache.integer)
1603 if (!strncasecmp(host_client->download_name, "dlcache/", 8))
1605 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);
1606 Host_ClientCommands("\nstopdownload\n");
1611 if (!sv_allowdownloads_archive.integer)
1613 if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
1615 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);
1616 Host_ClientCommands("\nstopdownload\n");
1621 host_client->download_file = FS_Open(host_client->download_name, "rb", true, false);
1622 if (!host_client->download_file)
1624 SV_ClientPrintf("Download rejected: server could not open the file \"%s\"\n", host_client->download_name);
1625 Host_ClientCommands("\nstopdownload\n");
1629 if (FS_FileSize(host_client->download_file) > 1<<30)
1631 SV_ClientPrintf("Download rejected: file \"%s\" is very large\n", host_client->download_name);
1632 Host_ClientCommands("\nstopdownload\n");
1633 FS_Close(host_client->download_file);
1634 host_client->download_file = NULL;
1638 Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
1640 Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name);
1642 host_client->download_expectedposition = 0;
1643 host_client->download_started = false;
1645 // the rest of the download process is handled in SV_SendClientDatagram
1646 // and other code dealing with svc_downloaddata and clc_ackdownloaddata
1648 // no svc_downloaddata messages will be sent until sv_startdownload is
1649 // sent by the client
1653 ==============================================================================
1657 ==============================================================================
1666 int SV_ModelIndex(const char *s, int precachemode)
1668 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1669 char filename[MAX_QPATH];
1673 //if (precachemode == 2)
1675 strlcpy(filename, s, sizeof(filename));
1676 for (i = 2;i < limit;i++)
1678 if (!sv.model_precache[i][0])
1682 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))
1684 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1687 if (precachemode == 1)
1688 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1689 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1690 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1691 if (sv.state != ss_loading)
1693 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1694 MSG_WriteShort(&sv.reliable_datagram, i);
1695 MSG_WriteString(&sv.reliable_datagram, filename);
1699 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1702 if (!strcmp(sv.model_precache[i], filename))
1705 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1715 int SV_SoundIndex(const char *s, int precachemode)
1717 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1718 char filename[MAX_QPATH];
1722 //if (precachemode == 2)
1724 strlcpy(filename, s, sizeof(filename));
1725 for (i = 1;i < limit;i++)
1727 if (!sv.sound_precache[i][0])
1731 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))
1733 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1736 if (precachemode == 1)
1737 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1738 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1739 if (sv.state != ss_loading)
1741 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1742 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1743 MSG_WriteString(&sv.reliable_datagram, filename);
1747 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1750 if (!strcmp(sv.sound_precache[i], filename))
1753 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1757 // MUST match effectnameindex_t in client.h
1758 static const char *standardeffectnames[EFFECT_TOTAL] =
1766 "TE_SUPERSPIKEQUAD",
1782 "TE_TEI_BIGEXPLOSION",
1800 SV_ParticleEffectIndex
1804 int SV_ParticleEffectIndex(const char *name)
1806 int i, argc, linenumber, effectnameindex;
1807 fs_offset_t filesize;
1808 unsigned char *filedata;
1809 const char *text, *textstart, *textend;
1810 char argv[16][1024];
1811 if (!sv.particleeffectnamesloaded)
1813 sv.particleeffectnamesloaded = true;
1814 memset(sv.particleeffectname, 0, sizeof(sv.particleeffectname));
1815 for (i = 0;i < EFFECT_TOTAL;i++)
1816 strlcpy(sv.particleeffectname[i], standardeffectnames[i], sizeof(sv.particleeffectname[i]));
1817 filedata = FS_LoadFile("effectinfo.txt", tempmempool, true, &filesize);
1820 textstart = (const char *)filedata;
1821 textend = (const char *)filedata + filesize;
1823 for (linenumber = 1;;linenumber++)
1828 if (!COM_ParseToken(&text, true) || !strcmp(com_token, "\n"))
1832 strlcpy(argv[argc], com_token, sizeof(argv[argc]));
1836 if (com_token[0] == 0)
1837 break; // if the loop exited and it's not a \n, it's EOF
1840 if (!strcmp(argv[0], "effect"))
1844 for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME;effectnameindex++)
1846 if (sv.particleeffectname[effectnameindex][0])
1848 if (!strcmp(sv.particleeffectname[effectnameindex], argv[1]))
1853 strlcpy(sv.particleeffectname[effectnameindex], argv[1], sizeof(sv.particleeffectname[effectnameindex]));
1857 // if we run out of names, abort
1858 if (effectnameindex == SV_MAX_PARTICLEEFFECTNAME)
1860 Con_Printf("effectinfo.txt:%i: too many effects!\n", linenumber);
1869 // search for the name
1870 for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME && sv.particleeffectname[effectnameindex][0];effectnameindex++)
1871 if (!strcmp(sv.particleeffectname[effectnameindex], name))
1872 return effectnameindex;
1873 // return 0 if we couldn't find it
1883 void SV_CreateBaseline (void)
1885 int i, entnum, large;
1886 prvm_edict_t *svent;
1888 // LordHavoc: clear *all* states (note just active ones)
1889 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1891 // get the current server version
1892 svent = PRVM_EDICT_NUM(entnum);
1894 // LordHavoc: always clear state values, whether the entity is in use or not
1895 svent->priv.server->baseline = defaultstate;
1897 if (svent->priv.server->free)
1899 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1902 // create entity baseline
1903 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1904 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1905 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1906 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1907 if (entnum > 0 && entnum <= svs.maxclients)
1909 svent->priv.server->baseline.colormap = entnum;
1910 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1914 svent->priv.server->baseline.colormap = 0;
1915 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1919 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1922 // add to the message
1924 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1926 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1927 MSG_WriteShort (&sv.signon, entnum);
1931 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1932 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1936 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1937 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1939 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1940 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1941 for (i=0 ; i<3 ; i++)
1943 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1944 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1954 Grabs the current state of each client for saving across the
1955 transition to another level
1958 void SV_SaveSpawnparms (void)
1962 svs.serverflags = (int)prog->globals.server->serverflags;
1964 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1966 if (!host_client->active)
1969 // call the progs to get default spawn parms for the new client
1970 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1971 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1972 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1973 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1977 void SV_IncreaseEdicts(void)
1981 int oldmax_edicts = prog->max_edicts;
1982 void *oldedictsengineprivate = prog->edictprivate;
1983 void *oldedictsfields = prog->edictsfields;
1984 void *oldmoved_edicts = sv.moved_edicts;
1986 if (prog->max_edicts >= MAX_EDICTS)
1989 // links don't survive the transition, so unlink everything
1990 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1992 if (!ent->priv.server->free)
1993 SV_UnlinkEdict(prog->edicts + i);
1994 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1996 World_Clear(&sv.world);
1998 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
1999 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
2000 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
2001 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2003 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
2004 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
2006 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2008 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
2009 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
2010 // link every entity except world
2011 if (!ent->priv.server->free)
2012 SV_LinkEdict(ent, false);
2015 PR_Free(oldedictsengineprivate);
2016 PR_Free(oldedictsfields);
2017 PR_Free(oldmoved_edicts);
2024 This is called at the start of each level
2027 extern float scr_centertime_off;
2029 void SV_SpawnServer (const char *server)
2034 model_t *worldmodel;
2035 char modelname[sizeof(sv.modelname)];
2037 Con_DPrintf("SpawnServer: %s\n", server);
2039 if (cls.state != ca_dedicated)
2040 SCR_BeginLoadingPlaque();
2042 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
2043 worldmodel = Mod_ForName(modelname, false, true, true);
2044 if (!worldmodel || !worldmodel->TraceBox)
2046 Con_Printf("Couldn't load map %s\n", modelname);
2050 // let's not have any servers with no name
2051 if (hostname.string[0] == 0)
2052 Cvar_Set ("hostname", "UNNAMED");
2053 scr_centertime_off = 0;
2055 svs.changelevel_issued = false; // now safe to issue another
2057 // make the map a required file for clients
2058 Curl_ClearRequirements();
2059 Curl_RequireFile(modelname);
2062 // tell all connected clients that we are going to a new level
2067 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
2069 if (client->netconnection)
2071 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
2072 MSG_WriteString(&client->netconnection->message, "reconnect\n");
2079 NetConn_OpenServerPorts(true);
2083 // make cvars consistant
2086 Cvar_SetValue ("deathmatch", 0);
2087 // LordHavoc: it can be useful to have skills outside the range 0-3...
2088 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
2089 //Cvar_SetValue ("skill", (float)current_skill);
2090 current_skill = (int)(skill.value + 0.5);
2093 // set up the new server
2095 memset (&sv, 0, sizeof(sv));
2096 // if running a local client, make sure it doesn't try to access the last
2097 // level's data which is no longer valiud
2100 if(*sv_random_seed.string)
2102 srand(sv_random_seed.integer);
2103 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);
2110 strlcpy (sv.name, server, sizeof (sv.name));
2112 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
2113 if (sv.protocol == PROTOCOL_UNKNOWN)
2116 Protocol_Names(buffer, sizeof(buffer));
2117 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
2118 sv.protocol = PROTOCOL_QUAKE;
2123 // load progs to get entity field count
2124 //PR_LoadProgs ( sv_progs.string );
2126 // allocate server memory
2127 /*// start out with just enough room for clients and a reasonable estimate of entities
2128 prog->max_edicts = max(svs.maxclients + 1, 512);
2129 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
2131 // prvm_edict_t structures (hidden from progs)
2132 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
2133 // engine private structures (hidden from progs)
2134 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
2135 // progs fields, often accessed by server
2136 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
2137 // used by PushMove to move back pushed entities
2138 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2139 /*for (i = 0;i < prog->max_edicts;i++)
2141 ent = prog->edicts + i;
2142 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
2143 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
2146 // reset client csqc entity versions right away.
2147 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2148 EntityFrameCSQC_InitClientVersions(i, true);
2150 sv.datagram.maxsize = sizeof(sv.datagram_buf);
2151 sv.datagram.cursize = 0;
2152 sv.datagram.data = sv.datagram_buf;
2154 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
2155 sv.reliable_datagram.cursize = 0;
2156 sv.reliable_datagram.data = sv.reliable_datagram_buf;
2158 sv.signon.maxsize = sizeof(sv.signon_buf);
2159 sv.signon.cursize = 0;
2160 sv.signon.data = sv.signon_buf;
2162 // leave slots at start for clients only
2163 //prog->num_edicts = svs.maxclients+1;
2165 sv.state = ss_loading;
2166 prog->allowworldwrites = true;
2169 prog->globals.server->time = sv.time = 1.0;
2172 worldmodel->used = true;
2174 strlcpy (sv.name, server, sizeof (sv.name));
2175 strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
2176 sv.worldmodel = worldmodel;
2177 sv.models[1] = sv.worldmodel;
2180 // clear world interaction links
2182 VectorCopy(sv.worldmodel->normalmins, sv.world.areagrid_mins);
2183 VectorCopy(sv.worldmodel->normalmaxs, sv.world.areagrid_maxs);
2184 World_Clear(&sv.world);
2186 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
2188 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
2189 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
2190 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
2192 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
2193 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
2197 // load the rest of the entities
2199 // AK possible hack since num_edicts is still 0
2200 ent = PRVM_EDICT_NUM(0);
2201 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
2202 ent->priv.server->free = false;
2203 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
2204 ent->fields.server->modelindex = 1; // world model
2205 ent->fields.server->solid = SOLID_BSP;
2206 ent->fields.server->movetype = MOVETYPE_PUSH;
2207 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->mins);
2208 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->maxs);
2209 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->absmin);
2210 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->absmax);
2213 prog->globals.server->coop = coop.integer;
2215 prog->globals.server->deathmatch = deathmatch.integer;
2217 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
2219 // serverflags are for cross level information (sigils)
2220 prog->globals.server->serverflags = svs.serverflags;
2222 // we need to reset the spawned flag on all connected clients here so that
2223 // their thinks don't run during startup (before PutClientInServer)
2224 // we also need to set up the client entities now
2225 // and we need to set the ->edict pointers to point into the progs edicts
2226 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2228 host_client->spawned = false;
2229 host_client->edict = PRVM_EDICT_NUM(i + 1);
2230 PRVM_ED_ClearEdict(host_client->edict);
2233 // load replacement entity file if found
2234 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
2236 Con_Printf("Loaded maps/%s.ent\n", sv.name);
2237 PRVM_ED_LoadFromFile (entities);
2241 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
2244 // LordHavoc: clear world angles (to fix e3m3.bsp)
2245 VectorClear(prog->edicts->fields.server->angles);
2247 // all setup is completed, any further precache statements are errors
2248 sv.state = ss_active;
2249 prog->allowworldwrites = false;
2251 // run two frames to allow everything to settle
2252 for (i = 0;i < 2;i++)
2260 // create a baseline for more efficient communications
2261 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
2262 SV_CreateBaseline ();
2264 // send serverinfo to all connected clients, and set up botclients coming back from a level change
2265 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2267 if (!host_client->active)
2269 if (host_client->netconnection)
2270 SV_SendServerinfo(host_client);
2274 // if client is a botclient coming from a level change, we need to
2275 // set up client info that normally requires networking
2277 // copy spawn parms out of the client_t
2278 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
2279 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
2281 // call the spawn function
2282 host_client->clientconnectcalled = true;
2283 prog->globals.server->time = sv.time;
2284 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2285 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
2286 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
2287 host_client->spawned = true;
2291 Con_DPrint("Server spawned.\n");
2292 NetConn_Heartbeat (2);
2297 /////////////////////////////////////////////////////
2300 void SV_VM_CB_BeginIncreaseEdicts(void)
2305 PRVM_Free( sv.moved_edicts );
2306 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2308 // links don't survive the transition, so unlink everything
2309 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2311 if (!ent->priv.server->free)
2312 World_UnlinkEdict(prog->edicts + i);
2313 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
2315 World_Clear(&sv.world);
2318 void SV_VM_CB_EndIncreaseEdicts(void)
2323 // link every entity except world
2324 for (i = 1, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2325 if (!ent->priv.server->free)
2326 SV_LinkEdict(ent, false);
2329 void SV_VM_CB_InitEdict(prvm_edict_t *e)
2331 // LordHavoc: for consistency set these here
2332 int num = PRVM_NUM_FOR_EDICT(e) - 1;
2334 e->priv.server->move = false; // don't move on first frame
2336 if (num >= 0 && num < svs.maxclients)
2339 // set colormap and team on newly created player entity
2340 e->fields.server->colormap = num + 1;
2341 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
2342 // set netname/clientcolors back to client values so that
2343 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
2345 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
2346 if ((val = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.clientcolors)))
2347 val->_float = svs.clients[num].colors;
2348 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
2349 if( prog->fieldoffsets.playermodel >= 0 )
2350 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
2351 if( prog->fieldoffsets.playerskin >= 0 )
2352 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
2356 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
2358 World_UnlinkEdict(ed); // unlink from world bsp
2360 ed->fields.server->model = 0;
2361 ed->fields.server->takedamage = 0;
2362 ed->fields.server->modelindex = 0;
2363 ed->fields.server->colormap = 0;
2364 ed->fields.server->skin = 0;
2365 ed->fields.server->frame = 0;
2366 VectorClear(ed->fields.server->origin);
2367 VectorClear(ed->fields.server->angles);
2368 ed->fields.server->nextthink = -1;
2369 ed->fields.server->solid = 0;
2372 void SV_VM_CB_CountEdicts(void)
2376 int active, models, solid, step;
2378 active = models = solid = step = 0;
2379 for (i=0 ; i<prog->num_edicts ; i++)
2381 ent = PRVM_EDICT_NUM(i);
2382 if (ent->priv.server->free)
2385 if (ent->fields.server->solid)
2387 if (ent->fields.server->model)
2389 if (ent->fields.server->movetype == MOVETYPE_STEP)
2393 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2394 Con_Printf("active :%3i\n", active);
2395 Con_Printf("view :%3i\n", models);
2396 Con_Printf("touch :%3i\n", solid);
2397 Con_Printf("step :%3i\n", step);
2400 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2402 // remove things from different skill levels or deathmatch
2403 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2405 if (deathmatch.integer)
2407 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2412 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2413 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2414 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2422 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)"};
2423 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2424 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2425 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2426 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2427 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2428 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2429 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2430 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2431 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2432 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2433 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2434 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2435 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2436 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2437 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2438 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2439 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2440 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2441 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2442 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2443 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2444 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2445 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2446 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2447 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2448 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2449 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2450 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2451 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2452 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2453 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2454 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2456 void SV_VM_Init(void)
2458 Cvar_RegisterVariable (&pr_checkextension);
2459 Cvar_RegisterVariable (&nomonsters);
2460 Cvar_RegisterVariable (&gamecfg);
2461 Cvar_RegisterVariable (&scratch1);
2462 Cvar_RegisterVariable (&scratch2);
2463 Cvar_RegisterVariable (&scratch3);
2464 Cvar_RegisterVariable (&scratch4);
2465 Cvar_RegisterVariable (&savedgamecfg);
2466 Cvar_RegisterVariable (&saved1);
2467 Cvar_RegisterVariable (&saved2);
2468 Cvar_RegisterVariable (&saved3);
2469 Cvar_RegisterVariable (&saved4);
2470 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2471 if (gamemode == GAME_NEHAHRA)
2473 Cvar_RegisterVariable (&nehx00);
2474 Cvar_RegisterVariable (&nehx01);
2475 Cvar_RegisterVariable (&nehx02);
2476 Cvar_RegisterVariable (&nehx03);
2477 Cvar_RegisterVariable (&nehx04);
2478 Cvar_RegisterVariable (&nehx05);
2479 Cvar_RegisterVariable (&nehx06);
2480 Cvar_RegisterVariable (&nehx07);
2481 Cvar_RegisterVariable (&nehx08);
2482 Cvar_RegisterVariable (&nehx09);
2483 Cvar_RegisterVariable (&nehx10);
2484 Cvar_RegisterVariable (&nehx11);
2485 Cvar_RegisterVariable (&nehx12);
2486 Cvar_RegisterVariable (&nehx13);
2487 Cvar_RegisterVariable (&nehx14);
2488 Cvar_RegisterVariable (&nehx15);
2489 Cvar_RegisterVariable (&nehx16);
2490 Cvar_RegisterVariable (&nehx17);
2491 Cvar_RegisterVariable (&nehx18);
2492 Cvar_RegisterVariable (&nehx19);
2494 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2497 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2499 prvm_required_field_t reqfields[] =
2501 {ev_entity, "cursor_trace_ent"},
2502 {ev_entity, "drawonlytoclient"},
2503 {ev_entity, "exteriormodeltoclient"},
2504 {ev_entity, "nodrawtoclient"},
2505 {ev_entity, "tag_entity"},
2506 {ev_entity, "viewmodelforclient"},
2507 {ev_float, "alpha"},
2508 {ev_float, "ammo_cells1"},
2509 {ev_float, "ammo_lava_nails"},
2510 {ev_float, "ammo_multi_rockets"},
2511 {ev_float, "ammo_nails1"},
2512 {ev_float, "ammo_plasma"},
2513 {ev_float, "ammo_rockets1"},
2514 {ev_float, "ammo_shells1"},
2515 {ev_float, "button3"},
2516 {ev_float, "button4"},
2517 {ev_float, "button5"},
2518 {ev_float, "button6"},
2519 {ev_float, "button7"},
2520 {ev_float, "button8"},
2521 {ev_float, "button9"},
2522 {ev_float, "button10"},
2523 {ev_float, "button11"},
2524 {ev_float, "button12"},
2525 {ev_float, "button13"},
2526 {ev_float, "button14"},
2527 {ev_float, "button15"},
2528 {ev_float, "button16"},
2529 {ev_float, "buttonchat"},
2530 {ev_float, "buttonuse"},
2531 {ev_float, "clientcolors"},
2532 {ev_float, "cursor_active"},
2533 {ev_float, "fullbright"},
2534 {ev_float, "glow_color"},
2535 {ev_float, "glow_size"},
2536 {ev_float, "glow_trail"},
2537 {ev_float, "gravity"},
2538 {ev_float, "idealpitch"},
2539 {ev_float, "items2"},
2540 {ev_float, "light_lev"},
2541 {ev_float, "pflags"},
2543 {ev_float, "pitch_speed"},
2544 {ev_float, "pmodel"},
2545 {ev_float, "renderamt"}, // HalfLife support
2546 {ev_float, "rendermode"}, // HalfLife support
2547 {ev_float, "scale"},
2548 {ev_float, "style"},
2549 {ev_float, "tag_index"},
2550 {ev_float, "Version"},
2551 {ev_float, "viewzoom"},
2552 {ev_vector, "color"},
2553 {ev_vector, "colormod"},
2554 {ev_vector, "cursor_screen"},
2555 {ev_vector, "cursor_trace_endpos"},
2556 {ev_vector, "cursor_trace_start"},
2557 {ev_vector, "movement"},
2558 {ev_vector, "punchvector"},
2559 {ev_string, "playermodel"},
2560 {ev_string, "playerskin"},
2561 {ev_function, "SendEntity"},
2562 {ev_function, "customizeentityforclient"},
2563 // DRESK - Support for Entity Contents Transition Event
2564 {ev_function, "contentstransition"},
2567 void SV_VM_Setup(void)
2569 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
2570 extern cvar_t csqc_progcrc;
2571 extern cvar_t csqc_progsize;
2572 size_t csprogsdatasize;
2574 PRVM_InitProg( PRVM_SERVERPROG );
2576 // allocate the mempools
2577 // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
2578 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2579 prog->builtins = vm_sv_builtins;
2580 prog->numbuiltins = vm_sv_numbuiltins;
2581 prog->headercrc = PROGHEADER_CRC;
2582 prog->max_edicts = 512;
2583 prog->limit_edicts = MAX_EDICTS;
2584 prog->reserved_edicts = svs.maxclients;
2585 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2586 prog->name = "server";
2587 prog->extensionstring = vm_sv_extensions;
2588 prog->loadintoworld = true;
2590 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2591 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2592 prog->init_edict = SV_VM_CB_InitEdict;
2593 prog->free_edict = SV_VM_CB_FreeEdict;
2594 prog->count_edicts = SV_VM_CB_CountEdicts;
2595 prog->load_edict = SV_VM_CB_LoadEdict;
2596 prog->init_cmd = VM_SV_Cmd_Init;
2597 prog->reset_cmd = VM_SV_Cmd_Reset;
2598 prog->error_cmd = Host_Error;
2600 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2601 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields, 0, NULL );
2603 // some mods compiled with scrambling compilers lack certain critical
2604 // global names and field names such as "self" and "time" and "nextthink"
2605 // so we have to set these offsets manually, matching the entvars_t
2606 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, angles);
2607 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, chain);
2608 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, classname);
2609 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, frame);
2610 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, groundentity);
2611 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ideal_yaw);
2612 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, nextthink);
2613 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, think);
2614 PRVM_ED_FindFieldOffset_FromStruct(entvars_t, yaw_speed);
2615 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, self);
2616 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, time);
2617 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_forward);
2618 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_right);
2619 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_up);
2620 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_allsolid);
2621 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_startsolid);
2622 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_fraction);
2623 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inwater);
2624 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inopen);
2625 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_endpos);
2626 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_normal);
2627 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_dist);
2628 PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_ent);
2629 // OP_STATE is always supported on server (due to entvars_t)
2630 prog->flag |= PRVM_OP_STATE;
2632 VM_AutoSentStats_Clear();//[515]: csqc
2633 EntityFrameCSQC_ClearVersions();//[515]: csqc
2637 // 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
2638 sv.csqc_progname[0] = 0;
2639 sv.csqc_progcrc = FS_CRCFile(csqc_progname.string, &csprogsdatasize);
2640 sv.csqc_progsize = csprogsdatasize;
2641 if (sv.csqc_progsize > 0)
2643 strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
2644 Con_DPrintf("server detected csqc progs file \"%s\" with size %i and crc %i\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
2648 void SV_VM_Begin(void)
2651 PRVM_SetProg( PRVM_SERVERPROG );
2653 prog->globals.server->time = (float) sv.time;
2656 void SV_VM_End(void)