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_stats = {0, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
50 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)"};
52 cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebouncedownslopes", "1", "prevents MOVETYPE_BOUNCE (grenades) from getting stuck when fired down a downward sloping surface"};
53 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"};
54 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)"};
55 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)"};
56 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"};
57 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"};
58 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"};
59 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"};
60 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"};
61 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"};
62 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)"};
64 cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
66 // TODO: move these cvars here
67 extern cvar_t sv_clmovement_enable;
68 extern cvar_t sv_clmovement_minping;
69 extern cvar_t sv_clmovement_minping_disabletime;
70 extern cvar_t sv_clmovement_waitforinput;
75 mempool_t *sv_mempool = NULL;
77 //============================================================================
79 extern void SV_Phys_Init (void);
80 extern void SV_World_Init (void);
81 static void SV_SaveEntFile_f(void);
82 static void SV_StartDownload_f(void);
83 static void SV_Download_f(void);
92 // init the csqc progs cvars, since they are updated/used by the server code
93 // TODO: fix this since this is a quick hack to make some of [515]'s broken code run ;) [9/13/2006 Black]
94 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
95 extern cvar_t csqc_progcrc;
96 extern cvar_t csqc_progsize;
97 Cvar_RegisterVariable (&csqc_progname);
98 Cvar_RegisterVariable (&csqc_progcrc);
99 Cvar_RegisterVariable (&csqc_progsize);
101 Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
102 Cmd_AddCommand_WithClientCommand("sv_startdownload", NULL, SV_StartDownload_f, "begins sending a file to the client (network protocol use only)");
103 Cmd_AddCommand_WithClientCommand("download", NULL, SV_Download_f, "downloads a specified file from the server");
104 Cvar_RegisterVariable (&sv_maxvelocity);
105 Cvar_RegisterVariable (&sv_gravity);
106 Cvar_RegisterVariable (&sv_friction);
107 Cvar_RegisterVariable (&sv_waterfriction);
108 Cvar_RegisterVariable (&sv_edgefriction);
109 Cvar_RegisterVariable (&sv_stopspeed);
110 Cvar_RegisterVariable (&sv_maxspeed);
111 Cvar_RegisterVariable (&sv_maxairspeed);
112 Cvar_RegisterVariable (&sv_accelerate);
113 Cvar_RegisterVariable (&sv_airaccelerate);
114 Cvar_RegisterVariable (&sv_wateraccelerate);
115 Cvar_RegisterVariable (&sv_clmovement_enable);
116 Cvar_RegisterVariable (&sv_clmovement_minping);
117 Cvar_RegisterVariable (&sv_clmovement_minping_disabletime);
118 Cvar_RegisterVariable (&sv_clmovement_waitforinput);
119 Cvar_RegisterVariable (&sv_idealpitchscale);
120 Cvar_RegisterVariable (&sv_aim);
121 Cvar_RegisterVariable (&sv_nostep);
122 Cvar_RegisterVariable (&sv_cullentities_pvs);
123 Cvar_RegisterVariable (&sv_cullentities_trace);
124 Cvar_RegisterVariable (&sv_cullentities_stats);
125 Cvar_RegisterVariable (&sv_entpatch);
126 Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
127 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
128 Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
129 Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
130 Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
131 Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
132 Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
133 Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
134 Cvar_RegisterVariable (&sv_gameplayfix_qwplayerphysics);
135 Cvar_RegisterVariable (&sv_gameplayfix_upwardvelocityclearsongroundflag);
136 Cvar_RegisterVariable (&sv_gameplayfix_droptofloorstartsolid);
137 Cvar_RegisterVariable (&sv_protocolname);
138 Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
139 Cvar_RegisterVariable (&sv_maxrate);
140 Cvar_RegisterVariable (&sv_allowdownloads);
141 Cvar_RegisterVariable (&sv_allowdownloads_inarchive);
142 Cvar_RegisterVariable (&sv_allowdownloads_archive);
143 Cvar_RegisterVariable (&sv_allowdownloads_config);
144 Cvar_RegisterVariable (&sv_allowdownloads_dlcache);
145 Cvar_RegisterVariable (&sv_progs);
151 sv_mempool = Mem_AllocPool("server", 0, NULL);
154 static void SV_SaveEntFile_f(void)
156 char basename[MAX_QPATH];
157 if (!sv.active || !sv.worldmodel)
159 Con_Print("Not running a server\n");
162 FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
163 FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
168 =============================================================================
172 =============================================================================
179 Make sure the event gets sent to all clients
182 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
186 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
188 MSG_WriteByte (&sv.datagram, svc_particle);
189 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
190 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
191 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
192 for (i=0 ; i<3 ; i++)
193 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
194 MSG_WriteByte (&sv.datagram, count);
195 MSG_WriteByte (&sv.datagram, color);
202 Make sure the event gets sent to all clients
205 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
207 if (modelindex >= 256 || startframe >= 256)
209 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
211 MSG_WriteByte (&sv.datagram, svc_effect2);
212 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
213 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
214 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
215 MSG_WriteShort (&sv.datagram, modelindex);
216 MSG_WriteShort (&sv.datagram, startframe);
217 MSG_WriteByte (&sv.datagram, framecount);
218 MSG_WriteByte (&sv.datagram, framerate);
222 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
224 MSG_WriteByte (&sv.datagram, svc_effect);
225 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
226 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
227 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
228 MSG_WriteByte (&sv.datagram, modelindex);
229 MSG_WriteByte (&sv.datagram, startframe);
230 MSG_WriteByte (&sv.datagram, framecount);
231 MSG_WriteByte (&sv.datagram, framerate);
239 Each entity can have eight independant sound sources, like voice,
242 Channel 0 is an auto-allocate channel, the others override anything
243 already running on that entity/channel pair.
245 An attenuation of 0 will play full volume everywhere in the level.
246 Larger attenuations will drop off. (max 4 attenuation)
250 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
252 int sound_num, field_mask, i, ent;
254 if (volume < 0 || volume > 255)
256 Con_Printf ("SV_StartSound: volume = %i\n", volume);
260 if (attenuation < 0 || attenuation > 4)
262 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
266 if (channel < 0 || channel > 7)
268 Con_Printf ("SV_StartSound: channel = %i\n", channel);
272 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
275 // find precache number for sound
276 sound_num = SV_SoundIndex(sample, 1);
280 ent = PRVM_NUM_FOR_EDICT(entity);
283 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
284 field_mask |= SND_VOLUME;
285 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
286 field_mask |= SND_ATTENUATION;
288 field_mask |= SND_LARGEENTITY;
289 if (sound_num >= 256 || channel >= 8)
290 field_mask |= SND_LARGESOUND;
292 // directed messages go only to the entity they are targeted on
293 MSG_WriteByte (&sv.datagram, svc_sound);
294 MSG_WriteByte (&sv.datagram, field_mask);
295 if (field_mask & SND_VOLUME)
296 MSG_WriteByte (&sv.datagram, volume);
297 if (field_mask & SND_ATTENUATION)
298 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
299 if (field_mask & SND_LARGEENTITY)
301 MSG_WriteShort (&sv.datagram, ent);
302 MSG_WriteByte (&sv.datagram, channel);
305 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
306 if (field_mask & SND_LARGESOUND)
307 MSG_WriteShort (&sv.datagram, sound_num);
309 MSG_WriteByte (&sv.datagram, sound_num);
310 for (i = 0;i < 3;i++)
311 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
315 ==============================================================================
319 ==============================================================================
326 Sends the first message from the server to a connected client.
327 This will be sent on the initial connection and upon each server load.
330 void SV_SendServerinfo (client_t *client)
335 // we know that this client has a netconnection and thus is not a bot
337 // edicts get reallocated on level changes, so we need to update it here
338 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
340 // clear cached stuff that depends on the level
341 client->weaponmodel[0] = 0;
342 client->weaponmodelindex = 0;
344 // LordHavoc: clear entityframe tracking
345 client->latestframenum = 0;
347 if (client->entitydatabase)
348 EntityFrame_FreeDatabase(client->entitydatabase);
349 if (client->entitydatabase4)
350 EntityFrame4_FreeDatabase(client->entitydatabase4);
351 if (client->entitydatabase5)
352 EntityFrame5_FreeDatabase(client->entitydatabase5);
354 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
356 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
357 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
358 else if (sv.protocol == PROTOCOL_DARKPLACES4)
359 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
361 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
364 SZ_Clear (&client->netconnection->message);
365 MSG_WriteByte (&client->netconnection->message, svc_print);
366 dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
367 MSG_WriteString (&client->netconnection->message,message);
369 //[515]: init csprogs according to version of svprogs, check the crc, etc.
370 if (sv.csqc_progname[0])
373 Con_DPrintf("sending csqc info to client (\"%s\" with size %i and crc %i)\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
374 //[515]: init stufftext string (it is sent before svc_serverinfo)
375 val = PRVM_GETGLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset("SV_InitCmd"));
376 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
377 MSG_WriteString (&client->netconnection->message, va("csqc_progname %s\n", sv.csqc_progname));
378 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
379 MSG_WriteString (&client->netconnection->message, va("csqc_progsize %i\n", sv.csqc_progsize));
380 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
381 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", sv.csqc_progcrc));
384 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
385 MSG_WriteString (&client->netconnection->message, va("%s\n", PRVM_GetString(val->string)));
389 if (sv_allowdownloads.integer)
391 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
392 MSG_WriteString (&client->netconnection->message, "cl_serverextension_download 1");
395 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
396 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
397 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
399 if (!coop.integer && deathmatch.integer)
400 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
402 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
404 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
406 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
407 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
408 MSG_WriteByte (&client->netconnection->message, 0);
410 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
411 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
412 MSG_WriteByte (&client->netconnection->message, 0);
415 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
416 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
417 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
420 MSG_WriteByte (&client->netconnection->message, svc_setview);
421 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
423 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
424 MSG_WriteByte (&client->netconnection->message, 1);
429 host_client = client;
430 Curl_SendRequirements();
434 client->spawned = false; // need prespawn, spawn, etc
441 Initializes a client_t for a new net connection. This will only be called
442 once for a player each game, not once for each level change.
445 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
449 float spawn_parms[NUM_SPAWN_PARMS];
451 client = svs.clients + clientnum;
453 if(netconnection)//[515]: bots don't play with csqc =)
454 EntityFrameCSQC_InitClientVersions(clientnum, false);
456 // set up the client_t
458 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
459 memset (client, 0, sizeof(*client));
460 client->active = true;
461 client->netconnection = netconnection;
463 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
465 strlcpy(client->name, "unconnected", sizeof(client->name));
466 strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
467 client->spawned = false;
468 client->edict = PRVM_EDICT_NUM(clientnum+1);
469 if (client->netconnection)
470 client->netconnection->message.allowoverflow = true; // we can catch it
471 // updated by receiving "rate" command from client
472 client->rate = NET_MINRATE;
473 // no limits for local player
474 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
475 client->rate = 1000000000;
476 client->connecttime = realtime;
479 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
482 // call the progs to get default spawn parms for the new client
483 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
484 prog->globals.server->self = 0;
485 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
486 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
487 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
489 // set up the entity for this client (including .colormap, .team, etc)
490 PRVM_ED_ClearEdict(client->edict);
493 // don't call SendServerinfo for a fresh botclient because its fields have
494 // not been set up by the qc yet
495 if (client->netconnection)
496 SV_SendServerinfo (client);
498 client->spawned = true;
503 ===============================================================================
507 ===============================================================================
516 void SV_ClearDatagram (void)
518 SZ_Clear (&sv.datagram);
522 =============================================================================
524 The PVS must include a small area around the client to allow head bobbing
525 or other small motion on the client side. Otherwise, a bob might cause an
526 entity that should be visible to not show up, especially when the bob
529 =============================================================================
532 int sv_writeentitiestoclient_pvsbytes;
533 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
535 static int numsendentities;
536 static entity_state_t sendentities[MAX_EDICTS];
537 static entity_state_t *sendentitiesindex[MAX_EDICTS];
539 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
542 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
543 unsigned int customizeentityforclient;
545 vec3_t cullmins, cullmaxs;
549 // EF_NODRAW prevents sending for any reason except for your own
550 // client, so we must keep all clients in this superset
551 effects = (unsigned)ent->fields.server->effects;
553 // we can omit invisible entities with no effects that are not clients
554 // LordHavoc: this could kill tags attached to an invisible entity, I
555 // just hope we never have to support that case
556 i = (int)ent->fields.server->modelindex;
557 modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
560 i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
561 glowsize = (unsigned char)bound(0, i, 255);
562 if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
563 flags |= RENDER_GLOWTRAIL;
565 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
566 light[0] = (unsigned short)bound(0, f, 65535);
567 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
568 light[1] = (unsigned short)bound(0, f, 65535);
569 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
570 light[2] = (unsigned short)bound(0, f, 65535);
571 f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
572 light[3] = (unsigned short)bound(0, f, 65535);
573 lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
574 lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
576 if (gamemode == GAME_TENEBRAE)
578 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
582 lightpflags |= PFLAGS_FULLDYNAMIC;
584 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
588 light[0] = (int)(0.2*256);
589 light[1] = (int)(1.0*256);
590 light[2] = (int)(0.2*256);
592 lightpflags |= PFLAGS_FULLDYNAMIC;
596 specialvisibilityradius = 0;
597 if (lightpflags & PFLAGS_FULLDYNAMIC)
598 specialvisibilityradius = max(specialvisibilityradius, light[3]);
600 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
601 if (flags & RENDER_GLOWTRAIL)
602 specialvisibilityradius = max(specialvisibilityradius, 100);
603 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
605 if (effects & EF_BRIGHTFIELD)
606 specialvisibilityradius = max(specialvisibilityradius, 80);
607 if (effects & EF_MUZZLEFLASH)
608 specialvisibilityradius = max(specialvisibilityradius, 100);
609 if (effects & EF_BRIGHTLIGHT)
610 specialvisibilityradius = max(specialvisibilityradius, 400);
611 if (effects & EF_DIMLIGHT)
612 specialvisibilityradius = max(specialvisibilityradius, 200);
613 if (effects & EF_RED)
614 specialvisibilityradius = max(specialvisibilityradius, 200);
615 if (effects & EF_BLUE)
616 specialvisibilityradius = max(specialvisibilityradius, 200);
617 if (effects & EF_FLAME)
618 specialvisibilityradius = max(specialvisibilityradius, 250);
619 if (effects & EF_STARDUST)
620 specialvisibilityradius = max(specialvisibilityradius, 100);
623 // early culling checks
624 // (final culling is done by SV_MarkWriteEntityStateToClient)
625 customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_customizeentityforclient)->function;
626 if (!customizeentityforclient)
628 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
630 // this 2 billion unit check is actually to detect NAN origins
631 // (we really don't want to send those)
632 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
640 VectorCopy(ent->fields.server->origin, cs->origin);
641 VectorCopy(ent->fields.server->angles, cs->angles);
643 cs->effects = effects;
644 cs->colormap = (unsigned)ent->fields.server->colormap;
645 cs->modelindex = modelindex;
646 cs->skin = (unsigned)ent->fields.server->skin;
647 cs->frame = (unsigned)ent->fields.server->frame;
648 cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict;
649 cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)->edict;
650 cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict;
651 cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict;
652 cs->customizeentityforclient = customizeentityforclient;
653 cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict;
654 cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
655 cs->glowsize = glowsize;
657 // don't need to init cs->colormod because the defaultstate did that for us
658 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
659 val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod);
660 if (val->vector[0] || val->vector[1] || val->vector[2])
662 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
663 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
664 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
667 cs->modelindex = modelindex;
670 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f);
674 cs->alpha = (unsigned char)bound(0, i, 255);
677 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float);
681 cs->alpha = (unsigned char)bound(0, i, 255);
685 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f);
689 cs->scale = (unsigned char)bound(0, i, 255);
693 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_color)->_float);
695 cs->glowcolor = (int)f;
697 if (PRVM_GETEDICTFIELDVALUE(ent, eval_fullbright)->_float)
698 cs->effects |= EF_FULLBRIGHT;
700 if (ent->fields.server->movetype == MOVETYPE_STEP)
701 cs->flags |= RENDER_STEP;
702 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)
703 cs->flags |= RENDER_LOWPRECISION;
704 if (ent->fields.server->colormap >= 1024)
705 cs->flags |= RENDER_COLORMAPPED;
706 if (cs->viewmodelforclient)
707 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
709 cs->light[0] = light[0];
710 cs->light[1] = light[1];
711 cs->light[2] = light[2];
712 cs->light[3] = light[3];
713 cs->lightstyle = lightstyle;
714 cs->lightpflags = lightpflags;
716 cs->specialvisibilityradius = specialvisibilityradius;
718 // calculate the visible box of this entity (don't use the physics box
719 // as that is often smaller than a model, and would not count
720 // specialvisibilityradius)
721 if ((model = sv.models[modelindex]))
723 float scale = cs->scale * (1.0f / 16.0f);
724 if (cs->angles[0] || cs->angles[2]) // pitch and roll
726 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
727 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
729 else if (cs->angles[1])
731 VectorMA(cs->origin, scale, model->yawmins, cullmins);
732 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
736 VectorMA(cs->origin, scale, model->normalmins, cullmins);
737 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
742 // if there is no model (or it could not be loaded), use the physics box
743 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
744 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
746 if (specialvisibilityradius)
748 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
749 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
750 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
751 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
752 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
753 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
755 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
757 VectorCopy(cullmins, ent->priv.server->cullmins);
758 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
759 ent->priv.server->pvs_numclusters = -1;
760 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
762 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
763 if (i <= MAX_ENTITYCLUSTERS)
764 ent->priv.server->pvs_numclusters = i;
771 void SV_PrepareEntitiesForSending(void)
775 // send all entities that touch the pvs
777 sendentitiesindex[0] = NULL;
778 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
779 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
781 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
783 sendentitiesindex[e] = sendentities + numsendentities;
789 static int sententitiesmark = 0;
790 static int sententities[MAX_EDICTS];
791 static int sententitiesconsideration[MAX_EDICTS];
792 static int sv_writeentitiestoclient_culled_pvs;
793 static int sv_writeentitiestoclient_culled_trace;
794 static int sv_writeentitiestoclient_visibleentities;
795 static int sv_writeentitiestoclient_totalentities;
796 //static entity_frame_t sv_writeentitiestoclient_entityframe;
797 static int sv_writeentitiestoclient_clentnum;
798 static vec3_t sv_writeentitiestoclient_testeye;
799 static client_t *sv_writeentitiestoclient_client;
801 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
808 if (sententitiesconsideration[s->number] == sententitiesmark)
810 sententitiesconsideration[s->number] = sententitiesmark;
811 sv_writeentitiestoclient_totalentities++;
813 if (s->customizeentityforclient)
815 prog->globals.server->self = s->number;
816 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
817 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
818 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
822 // never reject player
823 if (s->number != sv_writeentitiestoclient_clentnum)
825 // check various rejection conditions
826 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
828 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
830 if (s->effects & EF_NODRAW)
832 // LordHavoc: only send entities with a model or important effects
833 if (!s->modelindex && s->specialvisibilityradius == 0)
836 // viewmodels don't have visibility checking
837 if (s->viewmodelforclient)
839 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
842 else if (s->tagentity)
844 // tag attached entities simply check their parent
845 if (!sendentitiesindex[s->tagentity])
847 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
848 if (sententities[s->tagentity] != sententitiesmark)
851 // always send world submodels in newer protocols because they don't
852 // generate much traffic (in old protocols they hog bandwidth)
853 else if (!(s->effects & EF_NODEPTHTEST) && !((isbmodel = (model = sv.models[s->modelindex]) != NULL && model->name[0] == '*') && (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)))
855 // entity has survived every check so far, check if visible
856 ed = PRVM_EDICT_NUM(s->number);
858 // if not touching a visible leaf
859 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
861 if (ed->priv.server->pvs_numclusters < 0)
863 // entity too big for clusters list
864 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
866 sv_writeentitiestoclient_culled_pvs++;
873 // check cached clusters list
874 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
875 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
877 if (i == ed->priv.server->pvs_numclusters)
879 sv_writeentitiestoclient_culled_pvs++;
885 // or not seen by random tracelines
886 if (sv_cullentities_trace.integer && !isbmodel)
888 // LordHavoc: test center first
889 testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
890 testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
891 testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
892 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
893 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
894 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
897 // LordHavoc: test random offsets, to maximize chance of detection
898 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
899 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
900 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
901 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
902 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
903 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
906 if (s->specialvisibilityradius)
908 // LordHavoc: test random offsets, to maximize chance of detection
909 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
910 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
911 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
912 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
913 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
914 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
918 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
920 sv_writeentitiestoclient_culled_trace++;
927 // this just marks it for sending
928 // FIXME: it would be more efficient to send here, but the entity
929 // compressor isn't that flexible
930 sv_writeentitiestoclient_visibleentities++;
931 sententities[s->number] = sententitiesmark;
934 entity_state_t sendstates[MAX_EDICTS];
935 extern int csqc_clent;
937 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
939 int i, numsendstates;
942 // if there isn't enough space to accomplish anything, skip it
943 if (msg->cursize + 25 > msg->maxsize)
946 sv_writeentitiestoclient_client = client;
948 sv_writeentitiestoclient_culled_pvs = 0;
949 sv_writeentitiestoclient_culled_trace = 0;
950 sv_writeentitiestoclient_visibleentities = 0;
951 sv_writeentitiestoclient_totalentities = 0;
953 // find the client's PVS
954 // the real place being tested from
955 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
956 sv_writeentitiestoclient_pvsbytes = 0;
957 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
958 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
960 csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
964 for (i = 0;i < numsendentities;i++)
965 SV_MarkWriteEntityStateToClient(sendentities + i);
968 for (i = 0;i < numsendentities;i++)
970 if (sententities[sendentities[i].number] == sententitiesmark)
972 s = &sendstates[numsendstates++];
973 *s = sendentities[i];
974 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
975 s->flags |= RENDER_EXTERIORMODEL;
979 if (sv_cullentities_stats.integer)
980 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);
982 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
984 if (client->entitydatabase5)
985 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
986 else if (client->entitydatabase4)
987 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
988 else if (client->entitydatabase)
989 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
991 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
1000 void SV_CleanupEnts (void)
1005 ent = PRVM_NEXT_EDICT(prog->edicts);
1006 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
1007 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
1012 SV_WriteClientdataToMessage
1016 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1020 prvm_edict_t *other;
1028 // send a damage message
1030 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
1032 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
1033 MSG_WriteByte (msg, svc_damage);
1034 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
1035 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
1036 for (i=0 ; i<3 ; i++)
1037 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
1039 ent->fields.server->dmg_take = 0;
1040 ent->fields.server->dmg_save = 0;
1044 // send the current viewpos offset from the view entity
1046 SV_SetIdealPitch (); // how much to look up / down ideally
1048 // a fixangle might get lost in a dropped packet. Oh well.
1049 if ( ent->fields.server->fixangle )
1051 MSG_WriteByte (msg, svc_setangle);
1052 for (i=0 ; i < 3 ; i++)
1053 MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
1054 ent->fields.server->fixangle = 0;
1057 // stuff the sigil bits into the high bits of items for sbar, or else
1059 val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
1060 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1061 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1063 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1065 VectorClear(punchvector);
1066 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
1067 VectorCopy(val->vector, punchvector);
1069 // cache weapon model name and index in client struct to save time
1070 // (this search can be almost 1% of cpu time!)
1071 s = PRVM_GetString(ent->fields.server->weaponmodel);
1072 if (strcmp(s, client->weaponmodel))
1074 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1075 client->weaponmodelindex = SV_ModelIndex(s, 1);
1079 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
1080 viewzoom = (int)(val->_float * 255.0f);
1086 if ((int)ent->fields.server->flags & FL_ONGROUND)
1087 bits |= SU_ONGROUND;
1088 if (ent->fields.server->waterlevel >= 2)
1090 if (ent->fields.server->idealpitch)
1091 bits |= SU_IDEALPITCH;
1093 for (i=0 ; i<3 ; i++)
1095 if (ent->fields.server->punchangle[i])
1096 bits |= (SU_PUNCH1<<i);
1097 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1099 bits |= (SU_PUNCHVEC1<<i);
1100 if (ent->fields.server->velocity[i])
1101 bits |= (SU_VELOCITY1<<i);
1104 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1105 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1106 stats[STAT_ITEMS] = items;
1107 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1108 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1109 stats[STAT_WEAPON] = client->weaponmodelindex;
1110 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1111 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1112 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1113 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1114 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1115 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1116 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1117 stats[STAT_VIEWZOOM] = viewzoom;
1118 stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1119 stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1120 // the QC bumps these itself by sending svc_'s, so we have to keep them
1121 // zero or they'll be corrected by the engine
1122 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1123 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1125 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)
1127 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1129 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1130 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1132 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1133 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1134 if (viewzoom != 255)
1135 bits |= SU_VIEWZOOM;
1140 if (bits >= 16777216)
1144 MSG_WriteByte (msg, svc_clientdata);
1145 MSG_WriteShort (msg, bits);
1146 if (bits & SU_EXTEND1)
1147 MSG_WriteByte(msg, bits >> 16);
1148 if (bits & SU_EXTEND2)
1149 MSG_WriteByte(msg, bits >> 24);
1151 if (bits & SU_VIEWHEIGHT)
1152 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1154 if (bits & SU_IDEALPITCH)
1155 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1157 for (i=0 ; i<3 ; i++)
1159 if (bits & (SU_PUNCH1<<i))
1161 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1162 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1164 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1166 if (bits & (SU_PUNCHVEC1<<i))
1168 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1169 MSG_WriteCoord16i(msg, punchvector[i]);
1171 MSG_WriteCoord32f(msg, punchvector[i]);
1173 if (bits & (SU_VELOCITY1<<i))
1175 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1176 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1178 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1182 if (bits & SU_ITEMS)
1183 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1185 if (sv.protocol == PROTOCOL_DARKPLACES5)
1187 if (bits & SU_WEAPONFRAME)
1188 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1189 if (bits & SU_ARMOR)
1190 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1191 if (bits & SU_WEAPON)
1192 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1193 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1194 MSG_WriteShort (msg, stats[STAT_AMMO]);
1195 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1196 MSG_WriteShort (msg, stats[STAT_NAILS]);
1197 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1198 MSG_WriteShort (msg, stats[STAT_CELLS]);
1199 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1200 if (bits & SU_VIEWZOOM)
1201 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1203 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)
1205 if (bits & SU_WEAPONFRAME)
1206 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1207 if (bits & SU_ARMOR)
1208 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1209 if (bits & SU_WEAPON)
1210 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1211 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1212 MSG_WriteByte (msg, stats[STAT_AMMO]);
1213 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1214 MSG_WriteByte (msg, stats[STAT_NAILS]);
1215 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1216 MSG_WriteByte (msg, stats[STAT_CELLS]);
1217 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1219 for (i = 0;i < 32;i++)
1220 if (stats[STAT_WEAPON] & (1<<i))
1222 MSG_WriteByte (msg, i);
1225 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1226 if (bits & SU_VIEWZOOM)
1228 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1229 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1231 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1237 =======================
1238 SV_SendClientDatagram
1239 =======================
1241 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1242 void SV_SendClientDatagram (client_t *client)
1244 int rate, maxrate, maxsize, maxsize2, downloadsize;
1246 int stats[MAX_CL_STATS];
1248 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1250 // for good singleplayer, send huge packets
1251 maxsize = sizeof(sv_sendclientdatagram_buf);
1252 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1254 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)
1256 // no rate limiting support on older protocols because dp protocols
1257 // 1-4 kick the client off if they overflow, and quake protocol shows
1258 // less than the full entity set if rate limited
1264 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1265 maxrate = max(NET_MINRATE, sv_maxrate.integer);
1266 if (sv_maxrate.integer != maxrate)
1267 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1269 // this rate limiting does not understand sys_ticrate 0
1270 // (but no one should be running that on a server!)
1271 rate = bound(NET_MINRATE, client->rate, maxrate);
1272 rate = (int)(rate * sys_ticrate.value);
1273 maxsize = bound(50, rate, 1400);
1277 // while downloading, limit entity updates to half the packet
1278 // (any leftover space will be used for downloading)
1279 if (host_client->download_file)
1282 msg.data = sv_sendclientdatagram_buf;
1283 msg.maxsize = maxsize;
1286 if (host_client->spawned)
1288 MSG_WriteByte (&msg, svc_time);
1289 MSG_WriteFloat (&msg, sv.time);
1291 // add the client specific data to the datagram
1292 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1293 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1294 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1296 // expand packet size to allow effects to go over the rate limit
1297 // (dropping them is FAR too ugly)
1298 msg.maxsize = maxsize2;
1300 // copy the server datagram if there is space
1301 // FIXME: put in delayed queue of effects to send
1302 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1303 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1305 else if (realtime > client->keepalivetime)
1307 // the player isn't totally in the game yet
1308 // send small keepalive messages if too much time has passed
1309 msg.maxsize = maxsize2;
1310 client->keepalivetime = realtime + 5;
1311 MSG_WriteChar (&msg, svc_nop);
1314 msg.maxsize = maxsize2;
1316 // if a download is active, see if there is room to fit some download data
1318 downloadsize = maxsize * 2 - msg.cursize - 7;
1319 if (host_client->download_file && host_client->download_started && downloadsize > 0)
1321 fs_offset_t downloadstart;
1322 unsigned char data[1400];
1323 downloadstart = FS_Tell(host_client->download_file);
1324 downloadsize = min(downloadsize, (int)sizeof(data));
1325 downloadsize = FS_Read(host_client->download_file, data, downloadsize);
1326 // note this sends empty messages if at the end of the file, which is
1327 // necessary to keep the packet loss logic working
1328 // (the last blocks may be lost and need to be re-sent, and that will
1329 // only occur if the client acks the empty end messages, revealing
1330 // a gap in the download progress, causing the last blocks to be
1332 MSG_WriteChar (&msg, svc_downloaddata);
1333 MSG_WriteLong (&msg, downloadstart);
1334 MSG_WriteShort (&msg, downloadsize);
1335 if (downloadsize > 0)
1336 SZ_Write (&msg, data, downloadsize);
1339 // send the datagram
1340 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1344 =======================
1345 SV_UpdateToReliableMessages
1346 =======================
1348 void SV_UpdateToReliableMessages (void)
1357 // check for changes to be sent over the reliable streams
1358 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1360 // update the host_client fields we care about according to the entity fields
1361 host_client->edict = PRVM_EDICT_NUM(i+1);
1364 name = PRVM_GetString(host_client->edict->fields.server->netname);
1367 // always point the string back at host_client->name to keep it safe
1368 strlcpy (host_client->name, name, sizeof (host_client->name));
1369 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1370 if (strcmp(host_client->old_name, host_client->name))
1372 if (host_client->spawned)
1373 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1374 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1375 // send notification to all clients
1376 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1377 MSG_WriteByte (&sv.reliable_datagram, i);
1378 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1381 // DP_SV_CLIENTCOLORS
1382 // this is always found (since it's added by the progs loader)
1383 if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1384 host_client->colors = (int)val->_float;
1385 if (host_client->old_colors != host_client->colors)
1387 host_client->old_colors = host_client->colors;
1388 // send notification to all clients
1389 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1390 MSG_WriteByte (&sv.reliable_datagram, i);
1391 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1394 // NEXUIZ_PLAYERMODEL
1395 if( eval_playermodel ) {
1396 model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string);
1399 // always point the string back at host_client->name to keep it safe
1400 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1401 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1404 // NEXUIZ_PLAYERSKIN
1405 if( eval_playerskin ) {
1406 skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string);
1409 // always point the string back at host_client->name to keep it safe
1410 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1411 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1415 host_client->frags = (int)host_client->edict->fields.server->frags;
1416 if (host_client->old_frags != host_client->frags)
1418 host_client->old_frags = host_client->frags;
1419 // send notification to all clients
1420 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1421 MSG_WriteByte (&sv.reliable_datagram, i);
1422 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1426 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1427 if (client->netconnection)
1428 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1430 SZ_Clear (&sv.reliable_datagram);
1435 =======================
1436 SV_SendClientMessages
1437 =======================
1439 void SV_SendClientMessages (void)
1441 int i, prepared = false;
1443 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1444 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1446 // update frags, names, etc
1447 SV_UpdateToReliableMessages();
1449 // build individual updates
1450 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1452 if (!host_client->active)
1454 if (!host_client->netconnection)
1457 if (host_client->netconnection->message.overflowed)
1459 SV_DropClient (true); // if the message couldn't send, kick off
1466 // only prepare entities once per frame
1467 SV_PrepareEntitiesForSending();
1469 SV_SendClientDatagram (host_client);
1472 // clear muzzle flashes
1476 void SV_StartDownload_f(void)
1478 if (host_client->download_file)
1479 host_client->download_started = true;
1482 void SV_Download_f(void)
1484 const char *whichpack, *whichpack2, *extension;
1486 if (Cmd_Argc() != 2)
1488 SV_ClientPrintf("usage: download <filename>\n");
1492 if (FS_CheckNastyPath(Cmd_Argv(1), false))
1494 SV_ClientPrintf("Download rejected: nasty filename \"%s\"\n", Cmd_Argv(1));
1498 if (host_client->download_file)
1500 // at this point we'll assume the previous download should be aborted
1501 Con_DPrintf("Download of %s aborted by %s starting a new download\n", host_client->download_name, host_client->name);
1502 Host_ClientCommands("\nstopdownload\n");
1504 // close the file and reset variables
1505 FS_Close(host_client->download_file);
1506 host_client->download_file = NULL;
1507 host_client->download_name[0] = 0;
1508 host_client->download_expectedposition = 0;
1509 host_client->download_started = false;
1512 if (!sv_allowdownloads.integer)
1514 SV_ClientPrintf("Downloads are disabled on this server\n");
1515 Host_ClientCommands("\nstopdownload\n");
1519 strlcpy(host_client->download_name, Cmd_Argv(1), sizeof(host_client->download_name));
1520 extension = FS_FileExtension(host_client->download_name);
1522 // host_client is asking to download a specified file
1523 if (developer.integer >= 100)
1524 Con_Printf("Download request for %s by %s\n", host_client->download_name, host_client->name);
1526 if (!FS_FileExists(host_client->download_name))
1528 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);
1529 Host_ClientCommands("\nstopdownload\n");
1533 // check if the user is trying to download part of registered Quake(r)
1534 whichpack = FS_WhichPack(host_client->download_name);
1535 whichpack2 = FS_WhichPack("gfx/pop.lmp");
1536 if ((whichpack && whichpack2 && !strcasecmp(whichpack, whichpack2)) || FS_IsRegisteredQuakePack(host_client->download_name))
1538 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);
1539 Host_ClientCommands("\nstopdownload\n");
1543 // check if the server has forbidden archive downloads entirely
1544 if (!sv_allowdownloads_inarchive.integer)
1546 whichpack = FS_WhichPack(host_client->download_name);
1549 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);
1550 Host_ClientCommands("\nstopdownload\n");
1555 if (!sv_allowdownloads_config.integer)
1557 if (!strcasecmp(extension, "cfg"))
1559 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);
1560 Host_ClientCommands("\nstopdownload\n");
1565 if (!sv_allowdownloads_dlcache.integer)
1567 if (!strncasecmp(host_client->download_name, "dlcache/", 8))
1569 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);
1570 Host_ClientCommands("\nstopdownload\n");
1575 if (!sv_allowdownloads_archive.integer)
1577 if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
1579 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);
1580 Host_ClientCommands("\nstopdownload\n");
1585 host_client->download_file = FS_Open(host_client->download_name, "rb", true, false);
1586 if (!host_client->download_file)
1588 SV_ClientPrintf("Download rejected: server could not open the file \"%s\"\n", host_client->download_name);
1589 Host_ClientCommands("\nstopdownload\n");
1593 if (FS_FileSize(host_client->download_file) > 1<<30)
1595 SV_ClientPrintf("Download rejected: file \"%s\" is very large\n", host_client->download_name);
1596 Host_ClientCommands("\nstopdownload\n");
1597 FS_Close(host_client->download_file);
1598 host_client->download_file = NULL;
1602 Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
1604 Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name);
1606 host_client->download_expectedposition = 0;
1607 host_client->download_started = false;
1609 // the rest of the download process is handled in SV_SendClientDatagram
1610 // and other code dealing with svc_downloaddata and clc_ackdownloaddata
1612 // no svc_downloaddata messages will be sent until sv_startdownload is
1613 // sent by the client
1617 ==============================================================================
1621 ==============================================================================
1630 int SV_ModelIndex(const char *s, int precachemode)
1632 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1633 char filename[MAX_QPATH];
1637 //if (precachemode == 2)
1639 strlcpy(filename, s, sizeof(filename));
1640 for (i = 2;i < limit;i++)
1642 if (!sv.model_precache[i][0])
1646 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))
1648 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1651 if (precachemode == 1)
1652 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1653 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1654 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1655 if (sv.state != ss_loading)
1657 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1658 MSG_WriteShort(&sv.reliable_datagram, i);
1659 MSG_WriteString(&sv.reliable_datagram, filename);
1663 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1666 if (!strcmp(sv.model_precache[i], filename))
1669 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1679 int SV_SoundIndex(const char *s, int precachemode)
1681 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1682 char filename[MAX_QPATH];
1686 //if (precachemode == 2)
1688 strlcpy(filename, s, sizeof(filename));
1689 for (i = 1;i < limit;i++)
1691 if (!sv.sound_precache[i][0])
1695 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))
1697 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1700 if (precachemode == 1)
1701 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1702 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1703 if (sv.state != ss_loading)
1705 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1706 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1707 MSG_WriteString(&sv.reliable_datagram, filename);
1711 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1714 if (!strcmp(sv.sound_precache[i], filename))
1717 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1727 void SV_CreateBaseline (void)
1729 int i, entnum, large;
1730 prvm_edict_t *svent;
1732 // LordHavoc: clear *all* states (note just active ones)
1733 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1735 // get the current server version
1736 svent = PRVM_EDICT_NUM(entnum);
1738 // LordHavoc: always clear state values, whether the entity is in use or not
1739 svent->priv.server->baseline = defaultstate;
1741 if (svent->priv.server->free)
1743 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1746 // create entity baseline
1747 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1748 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1749 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1750 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1751 if (entnum > 0 && entnum <= svs.maxclients)
1753 svent->priv.server->baseline.colormap = entnum;
1754 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1758 svent->priv.server->baseline.colormap = 0;
1759 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1763 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1766 // add to the message
1768 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1770 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1771 MSG_WriteShort (&sv.signon, entnum);
1775 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1776 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1780 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1781 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1783 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1784 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1785 for (i=0 ; i<3 ; i++)
1787 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1788 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1798 Grabs the current state of each client for saving across the
1799 transition to another level
1802 void SV_SaveSpawnparms (void)
1806 svs.serverflags = (int)prog->globals.server->serverflags;
1808 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1810 if (!host_client->active)
1813 // call the progs to get default spawn parms for the new client
1814 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1815 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1816 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1817 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1821 void SV_IncreaseEdicts(void)
1825 int oldmax_edicts = prog->max_edicts;
1826 void *oldedictsengineprivate = prog->edictprivate;
1827 void *oldedictsfields = prog->edictsfields;
1828 void *oldmoved_edicts = sv.moved_edicts;
1830 if (prog->max_edicts >= MAX_EDICTS)
1833 // links don't survive the transition, so unlink everything
1834 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1836 if (!ent->priv.server->free)
1837 SV_UnlinkEdict(prog->edicts + i);
1838 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1842 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
1843 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1844 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
1845 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1847 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
1848 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
1850 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1852 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1853 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1854 // link every entity except world
1855 if (!ent->priv.server->free)
1856 SV_LinkEdict(ent, false);
1859 PR_Free(oldedictsengineprivate);
1860 PR_Free(oldedictsfields);
1861 PR_Free(oldmoved_edicts);
1868 This is called at the start of each level
1871 extern float scr_centertime_off;
1873 void SV_SpawnServer (const char *server)
1878 model_t *worldmodel;
1879 char modelname[sizeof(sv.modelname)];
1881 Con_DPrintf("SpawnServer: %s\n", server);
1883 if (cls.state != ca_dedicated)
1884 SCR_BeginLoadingPlaque();
1886 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
1887 worldmodel = Mod_ForName(modelname, false, true, true);
1888 if (!worldmodel || !worldmodel->TraceBox)
1890 Con_Printf("Couldn't load map %s\n", modelname);
1894 // let's not have any servers with no name
1895 if (hostname.string[0] == 0)
1896 Cvar_Set ("hostname", "UNNAMED");
1897 scr_centertime_off = 0;
1899 svs.changelevel_issued = false; // now safe to issue another
1901 // make the map a required file for clients
1902 Curl_ClearRequirements();
1903 Curl_RequireFile(modelname);
1906 // tell all connected clients that we are going to a new level
1911 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1913 if (client->netconnection)
1915 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
1916 MSG_WriteString(&client->netconnection->message, "reconnect\n");
1923 NetConn_OpenServerPorts(true);
1927 // make cvars consistant
1930 Cvar_SetValue ("deathmatch", 0);
1931 // LordHavoc: it can be useful to have skills outside the range 0-3...
1932 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
1933 //Cvar_SetValue ("skill", (float)current_skill);
1934 current_skill = (int)(skill.value + 0.5);
1937 // set up the new server
1939 memset (&sv, 0, sizeof(sv));
1940 // if running a local client, make sure it doesn't try to access the last
1941 // level's data which is no longer valiud
1944 if(*sv_random_seed.string)
1946 srand(sv_random_seed.integer);
1947 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);
1954 strlcpy (sv.name, server, sizeof (sv.name));
1956 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
1957 if (sv.protocol == PROTOCOL_UNKNOWN)
1960 Protocol_Names(buffer, sizeof(buffer));
1961 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
1962 sv.protocol = PROTOCOL_QUAKE;
1967 // load progs to get entity field count
1968 //PR_LoadProgs ( sv_progs.string );
1970 // allocate server memory
1971 /*// start out with just enough room for clients and a reasonable estimate of entities
1972 prog->max_edicts = max(svs.maxclients + 1, 512);
1973 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
1975 // prvm_edict_t structures (hidden from progs)
1976 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
1977 // engine private structures (hidden from progs)
1978 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1979 // progs fields, often accessed by server
1980 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
1981 // used by PushMove to move back pushed entities
1982 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1983 /*for (i = 0;i < prog->max_edicts;i++)
1985 ent = prog->edicts + i;
1986 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1987 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1990 // reset client csqc entity versions right away.
1991 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1992 EntityFrameCSQC_InitClientVersions(i, true);
1994 sv.datagram.maxsize = sizeof(sv.datagram_buf);
1995 sv.datagram.cursize = 0;
1996 sv.datagram.data = sv.datagram_buf;
1998 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
1999 sv.reliable_datagram.cursize = 0;
2000 sv.reliable_datagram.data = sv.reliable_datagram_buf;
2002 sv.signon.maxsize = sizeof(sv.signon_buf);
2003 sv.signon.cursize = 0;
2004 sv.signon.data = sv.signon_buf;
2006 // leave slots at start for clients only
2007 //prog->num_edicts = svs.maxclients+1;
2009 sv.state = ss_loading;
2010 prog->allowworldwrites = true;
2013 *prog->time = sv.time = 1.0;
2016 worldmodel->used = true;
2018 strlcpy (sv.name, server, sizeof (sv.name));
2019 strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
2020 sv.worldmodel = worldmodel;
2021 sv.models[1] = sv.worldmodel;
2024 // clear world interaction links
2028 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
2030 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
2031 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
2032 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
2034 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
2035 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
2039 // load the rest of the entities
2041 // AK possible hack since num_edicts is still 0
2042 ent = PRVM_EDICT_NUM(0);
2043 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
2044 ent->priv.server->free = false;
2045 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
2046 ent->fields.server->modelindex = 1; // world model
2047 ent->fields.server->solid = SOLID_BSP;
2048 ent->fields.server->movetype = MOVETYPE_PUSH;
2049 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->mins);
2050 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->maxs);
2051 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->absmin);
2052 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->absmax);
2055 prog->globals.server->coop = coop.integer;
2057 prog->globals.server->deathmatch = deathmatch.integer;
2059 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
2061 // serverflags are for cross level information (sigils)
2062 prog->globals.server->serverflags = svs.serverflags;
2064 // we need to reset the spawned flag on all connected clients here so that
2065 // their thinks don't run during startup (before PutClientInServer)
2066 // we also need to set up the client entities now
2067 // and we need to set the ->edict pointers to point into the progs edicts
2068 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2070 host_client->spawned = false;
2071 host_client->edict = PRVM_EDICT_NUM(i + 1);
2072 PRVM_ED_ClearEdict(host_client->edict);
2075 // load replacement entity file if found
2076 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
2078 Con_Printf("Loaded maps/%s.ent\n", sv.name);
2079 PRVM_ED_LoadFromFile (entities);
2083 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
2086 // LordHavoc: clear world angles (to fix e3m3.bsp)
2087 VectorClear(prog->edicts->fields.server->angles);
2089 // all setup is completed, any further precache statements are errors
2090 sv.state = ss_active;
2091 prog->allowworldwrites = false;
2093 // run two frames to allow everything to settle
2094 for (i = 0;i < 2;i++)
2102 // create a baseline for more efficient communications
2103 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
2104 SV_CreateBaseline ();
2106 // send serverinfo to all connected clients, and set up botclients coming back from a level change
2107 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2109 if (!host_client->active)
2111 if (host_client->netconnection)
2112 SV_SendServerinfo(host_client);
2116 // if client is a botclient coming from a level change, we need to
2117 // set up client info that normally requires networking
2119 // copy spawn parms out of the client_t
2120 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
2121 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
2123 // call the spawn function
2124 host_client->clientconnectcalled = true;
2125 prog->globals.server->time = sv.time;
2126 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2127 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
2128 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
2129 host_client->spawned = true;
2133 Con_DPrint("Server spawned.\n");
2134 NetConn_Heartbeat (2);
2139 /////////////////////////////////////////////////////
2142 void SV_VM_CB_BeginIncreaseEdicts(void)
2147 PRVM_Free( sv.moved_edicts );
2148 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2150 // links don't survive the transition, so unlink everything
2151 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2153 if (!ent->priv.server->free)
2154 SV_UnlinkEdict(prog->edicts + i);
2155 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
2160 void SV_VM_CB_EndIncreaseEdicts(void)
2165 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2167 // link every entity except world
2168 if (!ent->priv.server->free)
2169 SV_LinkEdict(ent, false);
2173 void SV_VM_CB_InitEdict(prvm_edict_t *e)
2175 // LordHavoc: for consistency set these here
2176 int num = PRVM_NUM_FOR_EDICT(e) - 1;
2178 e->priv.server->move = false; // don't move on first frame
2180 if (num >= 0 && num < svs.maxclients)
2183 // set colormap and team on newly created player entity
2184 e->fields.server->colormap = num + 1;
2185 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
2186 // set netname/clientcolors back to client values so that
2187 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
2189 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
2190 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
2191 val->_float = svs.clients[num].colors;
2192 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
2193 if( eval_playermodel )
2194 PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
2195 if( eval_playerskin )
2196 PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
2200 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
2202 SV_UnlinkEdict (ed); // unlink from world bsp
2204 ed->fields.server->model = 0;
2205 ed->fields.server->takedamage = 0;
2206 ed->fields.server->modelindex = 0;
2207 ed->fields.server->colormap = 0;
2208 ed->fields.server->skin = 0;
2209 ed->fields.server->frame = 0;
2210 VectorClear(ed->fields.server->origin);
2211 VectorClear(ed->fields.server->angles);
2212 ed->fields.server->nextthink = -1;
2213 ed->fields.server->solid = 0;
2216 void SV_VM_CB_CountEdicts(void)
2220 int active, models, solid, step;
2222 active = models = solid = step = 0;
2223 for (i=0 ; i<prog->num_edicts ; i++)
2225 ent = PRVM_EDICT_NUM(i);
2226 if (ent->priv.server->free)
2229 if (ent->fields.server->solid)
2231 if (ent->fields.server->model)
2233 if (ent->fields.server->movetype == MOVETYPE_STEP)
2237 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2238 Con_Printf("active :%3i\n", active);
2239 Con_Printf("view :%3i\n", models);
2240 Con_Printf("touch :%3i\n", solid);
2241 Con_Printf("step :%3i\n", step);
2244 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2246 // remove things from different skill levels or deathmatch
2247 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2249 if (deathmatch.integer)
2251 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2256 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2257 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2258 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2266 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)"};
2267 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2268 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2269 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2270 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2271 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2272 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2273 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2274 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2275 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2276 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2277 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2278 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2279 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2280 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2281 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2282 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2283 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2284 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2285 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2286 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2287 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2288 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2289 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2290 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2291 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2292 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2293 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2294 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2295 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2296 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2297 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2298 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2300 void SV_VM_Init(void)
2302 Cvar_RegisterVariable (&pr_checkextension);
2303 Cvar_RegisterVariable (&nomonsters);
2304 Cvar_RegisterVariable (&gamecfg);
2305 Cvar_RegisterVariable (&scratch1);
2306 Cvar_RegisterVariable (&scratch2);
2307 Cvar_RegisterVariable (&scratch3);
2308 Cvar_RegisterVariable (&scratch4);
2309 Cvar_RegisterVariable (&savedgamecfg);
2310 Cvar_RegisterVariable (&saved1);
2311 Cvar_RegisterVariable (&saved2);
2312 Cvar_RegisterVariable (&saved3);
2313 Cvar_RegisterVariable (&saved4);
2314 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2315 if (gamemode == GAME_NEHAHRA)
2317 Cvar_RegisterVariable (&nehx00);
2318 Cvar_RegisterVariable (&nehx01);
2319 Cvar_RegisterVariable (&nehx02);
2320 Cvar_RegisterVariable (&nehx03);
2321 Cvar_RegisterVariable (&nehx04);
2322 Cvar_RegisterVariable (&nehx05);
2323 Cvar_RegisterVariable (&nehx06);
2324 Cvar_RegisterVariable (&nehx07);
2325 Cvar_RegisterVariable (&nehx08);
2326 Cvar_RegisterVariable (&nehx09);
2327 Cvar_RegisterVariable (&nehx10);
2328 Cvar_RegisterVariable (&nehx11);
2329 Cvar_RegisterVariable (&nehx12);
2330 Cvar_RegisterVariable (&nehx13);
2331 Cvar_RegisterVariable (&nehx14);
2332 Cvar_RegisterVariable (&nehx15);
2333 Cvar_RegisterVariable (&nehx16);
2334 Cvar_RegisterVariable (&nehx17);
2335 Cvar_RegisterVariable (&nehx18);
2336 Cvar_RegisterVariable (&nehx19);
2338 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2341 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
2358 int eval_buttonchat;
2360 int eval_glow_trail;
2361 int eval_glow_color;
2365 int eval_renderamt; // HalfLife support
2366 int eval_rendermode; // HalfLife support
2367 int eval_fullbright;
2368 int eval_ammo_shells1;
2369 int eval_ammo_nails1;
2370 int eval_ammo_lava_nails;
2371 int eval_ammo_rockets1;
2372 int eval_ammo_multi_rockets;
2373 int eval_ammo_cells1;
2374 int eval_ammo_plasma;
2375 int eval_idealpitch;
2376 int eval_pitch_speed;
2377 int eval_viewmodelforclient;
2378 int eval_nodrawtoclient;
2379 int eval_exteriormodeltoclient;
2380 int eval_drawonlytoclient;
2384 int eval_punchvector;
2386 int eval_clientcolors;
2387 int eval_tag_entity;
2393 int eval_cursor_active;
2394 int eval_cursor_screen;
2395 int eval_cursor_trace_start;
2396 int eval_cursor_trace_endpos;
2397 int eval_cursor_trace_ent;
2399 int eval_playermodel;
2400 int eval_playerskin;
2401 int eval_SendEntity;
2403 int eval_customizeentityforclient;
2404 int eval_dphitcontentsmask;
2405 // DRESK - Support for Entity Contents Transition Event
2406 int eval_contentstransition;
2408 int gval_trace_dpstartcontents;
2409 int gval_trace_dphitcontents;
2410 int gval_trace_dphitq3surfaceflags;
2411 int gval_trace_dphittexturename;
2413 mfunction_t *SV_PlayerPhysicsQC;
2414 mfunction_t *EndFrameQC;
2415 //KrimZon - SERVER COMMANDS IN QUAKEC
2416 mfunction_t *SV_ParseClientCommandQC;
2418 void SV_VM_FindEdictFieldOffsets(void)
2420 eval_gravity = PRVM_ED_FindFieldOffset("gravity");
2421 eval_button3 = PRVM_ED_FindFieldOffset("button3");
2422 eval_button4 = PRVM_ED_FindFieldOffset("button4");
2423 eval_button5 = PRVM_ED_FindFieldOffset("button5");
2424 eval_button6 = PRVM_ED_FindFieldOffset("button6");
2425 eval_button7 = PRVM_ED_FindFieldOffset("button7");
2426 eval_button8 = PRVM_ED_FindFieldOffset("button8");
2427 eval_button9 = PRVM_ED_FindFieldOffset("button9");
2428 eval_button10 = PRVM_ED_FindFieldOffset("button10");
2429 eval_button11 = PRVM_ED_FindFieldOffset("button11");
2430 eval_button12 = PRVM_ED_FindFieldOffset("button12");
2431 eval_button13 = PRVM_ED_FindFieldOffset("button13");
2432 eval_button14 = PRVM_ED_FindFieldOffset("button14");
2433 eval_button15 = PRVM_ED_FindFieldOffset("button15");
2434 eval_button16 = PRVM_ED_FindFieldOffset("button16");
2435 eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
2436 eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
2437 eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
2438 eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
2439 eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
2440 eval_items2 = PRVM_ED_FindFieldOffset("items2");
2441 eval_scale = PRVM_ED_FindFieldOffset("scale");
2442 eval_alpha = PRVM_ED_FindFieldOffset("alpha");
2443 eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
2444 eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
2445 eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
2446 eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
2447 eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
2448 eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
2449 eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
2450 eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
2451 eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
2452 eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
2453 eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
2454 eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
2455 eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
2456 eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
2457 eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
2458 eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
2459 eval_ping = PRVM_ED_FindFieldOffset("ping");
2460 eval_movement = PRVM_ED_FindFieldOffset("movement");
2461 eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
2462 eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
2463 eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
2464 eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
2465 eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
2466 eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
2467 eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
2468 eval_color = PRVM_ED_FindFieldOffset("color");
2469 eval_style = PRVM_ED_FindFieldOffset("style");
2470 eval_pflags = PRVM_ED_FindFieldOffset("pflags");
2471 eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
2472 eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
2473 eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
2474 eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
2475 eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
2476 eval_colormod = PRVM_ED_FindFieldOffset("colormod");
2477 eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
2478 eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
2479 eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
2480 eval_Version = PRVM_ED_FindFieldOffset("Version");
2481 eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
2482 eval_dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
2483 // DRESK - Support for Entity Contents Transition Event
2484 eval_contentstransition = PRVM_ED_FindFieldOffset("contentstransition");
2486 // LordHavoc: allowing QuakeC to override the player movement code
2487 SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
2488 // LordHavoc: support for endframe
2489 EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
2490 //KrimZon - SERVER COMMANDS IN QUAKEC
2491 SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
2492 gval_trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
2493 gval_trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
2494 gval_trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
2495 gval_trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
2498 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2500 prvm_required_field_t reqfields[] =
2502 {ev_entity, "cursor_trace_ent"},
2503 {ev_entity, "drawonlytoclient"},
2504 {ev_entity, "exteriormodeltoclient"},
2505 {ev_entity, "nodrawtoclient"},
2506 {ev_entity, "tag_entity"},
2507 {ev_entity, "viewmodelforclient"},
2508 {ev_float, "alpha"},
2509 {ev_float, "ammo_cells1"},
2510 {ev_float, "ammo_lava_nails"},
2511 {ev_float, "ammo_multi_rockets"},
2512 {ev_float, "ammo_nails1"},
2513 {ev_float, "ammo_plasma"},
2514 {ev_float, "ammo_rockets1"},
2515 {ev_float, "ammo_shells1"},
2516 {ev_float, "button3"},
2517 {ev_float, "button4"},
2518 {ev_float, "button5"},
2519 {ev_float, "button6"},
2520 {ev_float, "button7"},
2521 {ev_float, "button8"},
2522 {ev_float, "button9"},
2523 {ev_float, "button10"},
2524 {ev_float, "button11"},
2525 {ev_float, "button12"},
2526 {ev_float, "button13"},
2527 {ev_float, "button14"},
2528 {ev_float, "button15"},
2529 {ev_float, "button16"},
2530 {ev_float, "buttonchat"},
2531 {ev_float, "buttonuse"},
2532 {ev_float, "clientcolors"},
2533 {ev_float, "cursor_active"},
2534 {ev_float, "fullbright"},
2535 {ev_float, "glow_color"},
2536 {ev_float, "glow_size"},
2537 {ev_float, "glow_trail"},
2538 {ev_float, "gravity"},
2539 {ev_float, "idealpitch"},
2540 {ev_float, "items2"},
2541 {ev_float, "light_lev"},
2542 {ev_float, "pflags"},
2544 {ev_float, "pitch_speed"},
2545 {ev_float, "pmodel"},
2546 {ev_float, "renderamt"}, // HalfLife support
2547 {ev_float, "rendermode"}, // HalfLife support
2548 {ev_float, "scale"},
2549 {ev_float, "style"},
2550 {ev_float, "tag_index"},
2551 {ev_float, "Version"},
2552 {ev_float, "viewzoom"},
2553 {ev_vector, "color"},
2554 {ev_vector, "colormod"},
2555 {ev_vector, "cursor_screen"},
2556 {ev_vector, "cursor_trace_endpos"},
2557 {ev_vector, "cursor_trace_start"},
2558 {ev_vector, "movement"},
2559 {ev_vector, "punchvector"},
2560 {ev_string, "playermodel"},
2561 {ev_string, "playerskin"},
2562 {ev_function, "SendEntity"},
2563 {ev_function, "customizeentityforclient"},
2564 // DRESK - Support for Entity Contents Transition Event
2565 {ev_function, "contentstransition"},
2568 void SV_VM_Setup(void)
2570 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
2571 extern cvar_t csqc_progcrc;
2572 extern cvar_t csqc_progsize;
2573 size_t csprogsdatasize;
2575 PRVM_InitProg( PRVM_SERVERPROG );
2577 // allocate the mempools
2578 // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
2579 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2580 prog->builtins = vm_sv_builtins;
2581 prog->numbuiltins = vm_sv_numbuiltins;
2582 prog->headercrc = PROGHEADER_CRC;
2583 prog->max_edicts = 512;
2584 prog->limit_edicts = MAX_EDICTS;
2585 prog->reserved_edicts = svs.maxclients;
2586 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2587 prog->name = "server";
2588 prog->extensionstring = vm_sv_extensions;
2589 prog->loadintoworld = true;
2591 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2592 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2593 prog->init_edict = SV_VM_CB_InitEdict;
2594 prog->free_edict = SV_VM_CB_FreeEdict;
2595 prog->count_edicts = SV_VM_CB_CountEdicts;
2596 prog->load_edict = SV_VM_CB_LoadEdict;
2597 prog->init_cmd = VM_SV_Cmd_Init;
2598 prog->reset_cmd = VM_SV_Cmd_Reset;
2599 prog->error_cmd = Host_Error;
2601 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2602 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
2603 SV_VM_FindEdictFieldOffsets();
2605 VM_AutoSentStats_Clear();//[515]: csqc
2606 EntityFrameCSQC_ClearVersions();//[515]: csqc
2610 // 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
2611 sv.csqc_progname[0] = 0;
2612 sv.csqc_progcrc = FS_CRCFile(csqc_progname.string, &csprogsdatasize);
2613 sv.csqc_progsize = csprogsdatasize;
2614 if (sv.csqc_progsize > 0)
2616 strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
2617 Con_DPrintf("server detected csqc progs file \"%s\" with size %i and crc %i\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
2621 void SV_VM_Begin(void)
2624 PRVM_SetProg( PRVM_SERVERPROG );
2626 *prog->time = (float) sv.time;
2629 void SV_VM_End(void)