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)"};
43 extern cvar_t sv_random_seed;
45 static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"}; // fast but loose
46 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
47 static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
48 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)"};
50 cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebouncedownslopes", "1", "prevents MOVETYPE_BOUNCE (grenades) from getting stuck when fired down a downward sloping surface"};
51 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"};
52 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)"};
53 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)"};
54 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"};
55 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"};
56 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"};
57 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"};
58 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"};
59 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"};
60 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)"};
62 cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
64 // TODO: move these cvars here
65 extern cvar_t sv_clmovement_enable;
66 extern cvar_t sv_clmovement_minping;
67 extern cvar_t sv_clmovement_minping_disabletime;
68 extern cvar_t sv_clmovement_waitforinput;
73 mempool_t *sv_mempool = NULL;
75 //============================================================================
77 extern void SV_Phys_Init (void);
78 extern void SV_World_Init (void);
79 static void SV_SaveEntFile_f(void);
80 static void SV_StartDownload_f(void);
81 static void SV_Download_f(void);
90 // init the csqc progs cvars, since they are updated/used by the server code
91 // TODO: fix this since this is a quick hack to make some of [515]'s broken code run ;) [9/13/2006 Black]
92 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
93 extern cvar_t csqc_progcrc;
94 Cvar_RegisterVariable (&csqc_progname);
95 Cvar_RegisterVariable (&csqc_progcrc);
97 Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
98 Cmd_AddCommand_WithClientCommand("sv_startdownload", NULL, SV_StartDownload_f, "begins sending a file to the client (network protocol use only)");
99 Cmd_AddCommand_WithClientCommand("download", NULL, SV_Download_f, "downloads a specified file from the server");
100 Cvar_RegisterVariable (&sv_maxvelocity);
101 Cvar_RegisterVariable (&sv_gravity);
102 Cvar_RegisterVariable (&sv_friction);
103 Cvar_RegisterVariable (&sv_waterfriction);
104 Cvar_RegisterVariable (&sv_edgefriction);
105 Cvar_RegisterVariable (&sv_stopspeed);
106 Cvar_RegisterVariable (&sv_maxspeed);
107 Cvar_RegisterVariable (&sv_maxairspeed);
108 Cvar_RegisterVariable (&sv_accelerate);
109 Cvar_RegisterVariable (&sv_airaccelerate);
110 Cvar_RegisterVariable (&sv_wateraccelerate);
111 Cvar_RegisterVariable (&sv_clmovement_enable);
112 Cvar_RegisterVariable (&sv_clmovement_minping);
113 Cvar_RegisterVariable (&sv_clmovement_minping_disabletime);
114 Cvar_RegisterVariable (&sv_clmovement_waitforinput);
115 Cvar_RegisterVariable (&sv_idealpitchscale);
116 Cvar_RegisterVariable (&sv_aim);
117 Cvar_RegisterVariable (&sv_nostep);
118 Cvar_RegisterVariable (&sv_cullentities_pvs);
119 Cvar_RegisterVariable (&sv_cullentities_trace);
120 Cvar_RegisterVariable (&sv_cullentities_stats);
121 Cvar_RegisterVariable (&sv_entpatch);
122 Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
123 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
124 Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
125 Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
126 Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
127 Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
128 Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
129 Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
130 Cvar_RegisterVariable (&sv_gameplayfix_qwplayerphysics);
131 Cvar_RegisterVariable (&sv_gameplayfix_upwardvelocityclearsongroundflag);
132 Cvar_RegisterVariable (&sv_gameplayfix_droptofloorstartsolid);
133 Cvar_RegisterVariable (&sv_protocolname);
134 Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
135 Cvar_RegisterVariable (&sv_maxrate);
136 Cvar_RegisterVariable (&sv_allowdownloads);
137 Cvar_RegisterVariable (&sv_allowdownloads_inarchive);
138 Cvar_RegisterVariable (&sv_allowdownloads_archive);
139 Cvar_RegisterVariable (&sv_progs);
145 sv_mempool = Mem_AllocPool("server", 0, NULL);
148 static void SV_SaveEntFile_f(void)
150 char basename[MAX_QPATH];
151 if (!sv.active || !sv.worldmodel)
153 Con_Print("Not running a server\n");
156 FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
157 FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
162 =============================================================================
166 =============================================================================
173 Make sure the event gets sent to all clients
176 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
180 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
182 MSG_WriteByte (&sv.datagram, svc_particle);
183 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
184 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
185 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
186 for (i=0 ; i<3 ; i++)
187 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
188 MSG_WriteByte (&sv.datagram, count);
189 MSG_WriteByte (&sv.datagram, color);
196 Make sure the event gets sent to all clients
199 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
201 if (modelindex >= 256 || startframe >= 256)
203 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
205 MSG_WriteByte (&sv.datagram, svc_effect2);
206 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
207 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
208 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
209 MSG_WriteShort (&sv.datagram, modelindex);
210 MSG_WriteShort (&sv.datagram, startframe);
211 MSG_WriteByte (&sv.datagram, framecount);
212 MSG_WriteByte (&sv.datagram, framerate);
216 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
218 MSG_WriteByte (&sv.datagram, svc_effect);
219 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
220 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
221 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
222 MSG_WriteByte (&sv.datagram, modelindex);
223 MSG_WriteByte (&sv.datagram, startframe);
224 MSG_WriteByte (&sv.datagram, framecount);
225 MSG_WriteByte (&sv.datagram, framerate);
233 Each entity can have eight independant sound sources, like voice,
236 Channel 0 is an auto-allocate channel, the others override anything
237 already running on that entity/channel pair.
239 An attenuation of 0 will play full volume everywhere in the level.
240 Larger attenuations will drop off. (max 4 attenuation)
244 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
246 int sound_num, field_mask, i, ent;
248 if (volume < 0 || volume > 255)
250 Con_Printf ("SV_StartSound: volume = %i\n", volume);
254 if (attenuation < 0 || attenuation > 4)
256 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
260 if (channel < 0 || channel > 7)
262 Con_Printf ("SV_StartSound: channel = %i\n", channel);
266 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
269 // find precache number for sound
270 sound_num = SV_SoundIndex(sample, 1);
274 ent = PRVM_NUM_FOR_EDICT(entity);
277 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
278 field_mask |= SND_VOLUME;
279 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
280 field_mask |= SND_ATTENUATION;
282 field_mask |= SND_LARGEENTITY;
283 if (sound_num >= 256 || channel >= 8)
284 field_mask |= SND_LARGESOUND;
286 // directed messages go only to the entity they are targeted on
287 MSG_WriteByte (&sv.datagram, svc_sound);
288 MSG_WriteByte (&sv.datagram, field_mask);
289 if (field_mask & SND_VOLUME)
290 MSG_WriteByte (&sv.datagram, volume);
291 if (field_mask & SND_ATTENUATION)
292 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
293 if (field_mask & SND_LARGEENTITY)
295 MSG_WriteShort (&sv.datagram, ent);
296 MSG_WriteByte (&sv.datagram, channel);
299 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
300 if (field_mask & SND_LARGESOUND)
301 MSG_WriteShort (&sv.datagram, sound_num);
303 MSG_WriteByte (&sv.datagram, sound_num);
304 for (i = 0;i < 3;i++)
305 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
309 ==============================================================================
313 ==============================================================================
320 Sends the first message from the server to a connected client.
321 This will be sent on the initial connection and upon each server load.
324 void SV_SendServerinfo (client_t *client)
329 // we know that this client has a netconnection and thus is not a bot
331 // edicts get reallocated on level changes, so we need to update it here
332 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
334 // clear cached stuff that depends on the level
335 client->weaponmodel[0] = 0;
336 client->weaponmodelindex = 0;
338 // LordHavoc: clear entityframe tracking
339 client->latestframenum = 0;
341 if (client->entitydatabase)
342 EntityFrame_FreeDatabase(client->entitydatabase);
343 if (client->entitydatabase4)
344 EntityFrame4_FreeDatabase(client->entitydatabase4);
345 if (client->entitydatabase5)
346 EntityFrame5_FreeDatabase(client->entitydatabase5);
348 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
350 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
351 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
352 else if (sv.protocol == PROTOCOL_DARKPLACES4)
353 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
355 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
358 SZ_Clear (&client->netconnection->message);
359 MSG_WriteByte (&client->netconnection->message, svc_print);
360 dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
361 MSG_WriteString (&client->netconnection->message,message);
363 //[515]: init csprogs according to version of svprogs, check the crc, etc.
364 if (sv.csqc_progcrc >= 0)
367 Con_DPrintf("sending csqc info to client (\"%s\" with crc %i)\n", sv.csqc_progname, sv.csqc_progcrc);
368 //[515]: init stufftext string (it is sent before svc_serverinfo)
369 val = PRVM_GETGLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset("SV_InitCmd"));
370 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
371 MSG_WriteString (&client->netconnection->message, va("csqc_progname %s\n", sv.csqc_progname));
372 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
373 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", sv.csqc_progcrc));
376 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
377 MSG_WriteString (&client->netconnection->message, va("%s\n", PRVM_GetString(val->string)));
381 if (sv_allowdownloads.integer)
383 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
384 MSG_WriteString (&client->netconnection->message, "cl_serverextension_download 1");
387 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
388 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
389 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
391 if (!coop.integer && deathmatch.integer)
392 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
394 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
396 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
398 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
399 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
400 MSG_WriteByte (&client->netconnection->message, 0);
402 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
403 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
404 MSG_WriteByte (&client->netconnection->message, 0);
407 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
408 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
409 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
412 MSG_WriteByte (&client->netconnection->message, svc_setview);
413 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
415 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
416 MSG_WriteByte (&client->netconnection->message, 1);
421 host_client = client;
422 Curl_SendRequirements();
426 client->spawned = false; // need prespawn, spawn, etc
433 Initializes a client_t for a new net connection. This will only be called
434 once for a player each game, not once for each level change.
437 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
441 float spawn_parms[NUM_SPAWN_PARMS];
443 client = svs.clients + clientnum;
445 if(netconnection)//[515]: bots don't play with csqc =)
446 EntityFrameCSQC_InitClientVersions(clientnum, false);
448 // set up the client_t
450 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
451 memset (client, 0, sizeof(*client));
452 client->active = true;
453 client->netconnection = netconnection;
455 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
457 strlcpy(client->name, "unconnected", sizeof(client->name));
458 strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
459 client->spawned = false;
460 client->edict = PRVM_EDICT_NUM(clientnum+1);
461 if (client->netconnection)
462 client->netconnection->message.allowoverflow = true; // we can catch it
463 // updated by receiving "rate" command from client
464 client->rate = NET_MINRATE;
465 // no limits for local player
466 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
467 client->rate = 1000000000;
468 client->connecttime = realtime;
471 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
474 // call the progs to get default spawn parms for the new client
475 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
476 prog->globals.server->self = 0;
477 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
478 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
479 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
481 // set up the entity for this client (including .colormap, .team, etc)
482 PRVM_ED_ClearEdict(client->edict);
485 // don't call SendServerinfo for a fresh botclient because its fields have
486 // not been set up by the qc yet
487 if (client->netconnection)
488 SV_SendServerinfo (client);
490 client->spawned = true;
495 ===============================================================================
499 ===============================================================================
508 void SV_ClearDatagram (void)
510 SZ_Clear (&sv.datagram);
514 =============================================================================
516 The PVS must include a small area around the client to allow head bobbing
517 or other small motion on the client side. Otherwise, a bob might cause an
518 entity that should be visible to not show up, especially when the bob
521 =============================================================================
524 int sv_writeentitiestoclient_pvsbytes;
525 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
527 static int numsendentities;
528 static entity_state_t sendentities[MAX_EDICTS];
529 static entity_state_t *sendentitiesindex[MAX_EDICTS];
531 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
534 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
535 unsigned int customizeentityforclient;
537 vec3_t cullmins, cullmaxs;
541 // EF_NODRAW prevents sending for any reason except for your own
542 // client, so we must keep all clients in this superset
543 effects = (unsigned)ent->fields.server->effects;
545 // we can omit invisible entities with no effects that are not clients
546 // LordHavoc: this could kill tags attached to an invisible entity, I
547 // just hope we never have to support that case
548 i = (int)ent->fields.server->modelindex;
549 modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
552 i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
553 glowsize = (unsigned char)bound(0, i, 255);
554 if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
555 flags |= RENDER_GLOWTRAIL;
557 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
558 light[0] = (unsigned short)bound(0, f, 65535);
559 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
560 light[1] = (unsigned short)bound(0, f, 65535);
561 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
562 light[2] = (unsigned short)bound(0, f, 65535);
563 f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
564 light[3] = (unsigned short)bound(0, f, 65535);
565 lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
566 lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
568 if (gamemode == GAME_TENEBRAE)
570 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
574 lightpflags |= PFLAGS_FULLDYNAMIC;
576 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
580 light[0] = (int)(0.2*256);
581 light[1] = (int)(1.0*256);
582 light[2] = (int)(0.2*256);
584 lightpflags |= PFLAGS_FULLDYNAMIC;
588 specialvisibilityradius = 0;
589 if (lightpflags & PFLAGS_FULLDYNAMIC)
590 specialvisibilityradius = max(specialvisibilityradius, light[3]);
592 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
593 if (flags & RENDER_GLOWTRAIL)
594 specialvisibilityradius = max(specialvisibilityradius, 100);
595 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
597 if (effects & EF_BRIGHTFIELD)
598 specialvisibilityradius = max(specialvisibilityradius, 80);
599 if (effects & EF_MUZZLEFLASH)
600 specialvisibilityradius = max(specialvisibilityradius, 100);
601 if (effects & EF_BRIGHTLIGHT)
602 specialvisibilityradius = max(specialvisibilityradius, 400);
603 if (effects & EF_DIMLIGHT)
604 specialvisibilityradius = max(specialvisibilityradius, 200);
605 if (effects & EF_RED)
606 specialvisibilityradius = max(specialvisibilityradius, 200);
607 if (effects & EF_BLUE)
608 specialvisibilityradius = max(specialvisibilityradius, 200);
609 if (effects & EF_FLAME)
610 specialvisibilityradius = max(specialvisibilityradius, 250);
611 if (effects & EF_STARDUST)
612 specialvisibilityradius = max(specialvisibilityradius, 100);
615 // early culling checks
616 // (final culling is done by SV_MarkWriteEntityStateToClient)
617 customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_customizeentityforclient)->function;
618 if (!customizeentityforclient)
620 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
622 // this 2 billion unit check is actually to detect NAN origins
623 // (we really don't want to send those)
624 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
632 VectorCopy(ent->fields.server->origin, cs->origin);
633 VectorCopy(ent->fields.server->angles, cs->angles);
635 cs->effects = effects;
636 cs->colormap = (unsigned)ent->fields.server->colormap;
637 cs->modelindex = modelindex;
638 cs->skin = (unsigned)ent->fields.server->skin;
639 cs->frame = (unsigned)ent->fields.server->frame;
640 cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict;
641 cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)->edict;
642 cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict;
643 cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict;
644 cs->customizeentityforclient = customizeentityforclient;
645 cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict;
646 cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
647 cs->glowsize = glowsize;
649 // don't need to init cs->colormod because the defaultstate did that for us
650 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
651 val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod);
652 if (val->vector[0] || val->vector[1] || val->vector[2])
654 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
655 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
656 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
659 cs->modelindex = modelindex;
662 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f);
666 cs->alpha = (unsigned char)bound(0, i, 255);
669 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float);
673 cs->alpha = (unsigned char)bound(0, i, 255);
677 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f);
681 cs->scale = (unsigned char)bound(0, i, 255);
685 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_color)->_float);
687 cs->glowcolor = (int)f;
689 if (PRVM_GETEDICTFIELDVALUE(ent, eval_fullbright)->_float)
690 cs->effects |= EF_FULLBRIGHT;
692 if (ent->fields.server->movetype == MOVETYPE_STEP)
693 cs->flags |= RENDER_STEP;
694 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)
695 cs->flags |= RENDER_LOWPRECISION;
696 if (ent->fields.server->colormap >= 1024)
697 cs->flags |= RENDER_COLORMAPPED;
698 if (cs->viewmodelforclient)
699 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
701 cs->light[0] = light[0];
702 cs->light[1] = light[1];
703 cs->light[2] = light[2];
704 cs->light[3] = light[3];
705 cs->lightstyle = lightstyle;
706 cs->lightpflags = lightpflags;
708 cs->specialvisibilityradius = specialvisibilityradius;
710 // calculate the visible box of this entity (don't use the physics box
711 // as that is often smaller than a model, and would not count
712 // specialvisibilityradius)
713 if ((model = sv.models[modelindex]))
715 float scale = cs->scale * (1.0f / 16.0f);
716 if (cs->angles[0] || cs->angles[2]) // pitch and roll
718 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
719 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
721 else if (cs->angles[1])
723 VectorMA(cs->origin, scale, model->yawmins, cullmins);
724 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
728 VectorMA(cs->origin, scale, model->normalmins, cullmins);
729 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
734 // if there is no model (or it could not be loaded), use the physics box
735 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
736 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
738 if (specialvisibilityradius)
740 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
741 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
742 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
743 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
744 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
745 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
747 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
749 VectorCopy(cullmins, ent->priv.server->cullmins);
750 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
751 ent->priv.server->pvs_numclusters = -1;
752 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
754 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
755 if (i <= MAX_ENTITYCLUSTERS)
756 ent->priv.server->pvs_numclusters = i;
763 void SV_PrepareEntitiesForSending(void)
767 // send all entities that touch the pvs
769 sendentitiesindex[0] = NULL;
770 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
771 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
773 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
775 sendentitiesindex[e] = sendentities + numsendentities;
781 static int sententitiesmark = 0;
782 static int sententities[MAX_EDICTS];
783 static int sententitiesconsideration[MAX_EDICTS];
784 static int sv_writeentitiestoclient_culled_pvs;
785 static int sv_writeentitiestoclient_culled_trace;
786 static int sv_writeentitiestoclient_visibleentities;
787 static int sv_writeentitiestoclient_totalentities;
788 //static entity_frame_t sv_writeentitiestoclient_entityframe;
789 static int sv_writeentitiestoclient_clentnum;
790 static vec3_t sv_writeentitiestoclient_testeye;
791 static client_t *sv_writeentitiestoclient_client;
793 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
800 if (sententitiesconsideration[s->number] == sententitiesmark)
802 sententitiesconsideration[s->number] = sententitiesmark;
803 sv_writeentitiestoclient_totalentities++;
805 if (s->customizeentityforclient)
807 prog->globals.server->self = s->number;
808 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
809 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
810 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
814 // never reject player
815 if (s->number != sv_writeentitiestoclient_clentnum)
817 // check various rejection conditions
818 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
820 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
822 if (s->effects & EF_NODRAW)
824 // LordHavoc: only send entities with a model or important effects
825 if (!s->modelindex && s->specialvisibilityradius == 0)
828 // viewmodels don't have visibility checking
829 if (s->viewmodelforclient)
831 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
834 else if (s->tagentity)
836 // tag attached entities simply check their parent
837 if (!sendentitiesindex[s->tagentity])
839 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
840 if (sententities[s->tagentity] != sententitiesmark)
843 // always send world submodels in newer protocols because they don't
844 // generate much traffic (in old protocols they hog bandwidth)
845 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)))
847 // entity has survived every check so far, check if visible
848 ed = PRVM_EDICT_NUM(s->number);
850 // if not touching a visible leaf
851 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
853 if (ed->priv.server->pvs_numclusters < 0)
855 // entity too big for clusters list
856 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
858 sv_writeentitiestoclient_culled_pvs++;
865 // check cached clusters list
866 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
867 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
869 if (i == ed->priv.server->pvs_numclusters)
871 sv_writeentitiestoclient_culled_pvs++;
877 // or not seen by random tracelines
878 if (sv_cullentities_trace.integer && !isbmodel)
880 // LordHavoc: test center first
881 testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
882 testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
883 testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
884 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
885 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
886 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
889 // LordHavoc: test random offsets, to maximize chance of detection
890 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
891 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
892 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
893 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
894 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
895 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
898 if (s->specialvisibilityradius)
900 // LordHavoc: test random offsets, to maximize chance of detection
901 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
902 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
903 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
904 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
905 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
906 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
910 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
912 sv_writeentitiestoclient_culled_trace++;
919 // this just marks it for sending
920 // FIXME: it would be more efficient to send here, but the entity
921 // compressor isn't that flexible
922 sv_writeentitiestoclient_visibleentities++;
923 sententities[s->number] = sententitiesmark;
926 entity_state_t sendstates[MAX_EDICTS];
927 extern int csqc_clent;
929 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
931 int i, numsendstates;
934 // if there isn't enough space to accomplish anything, skip it
935 if (msg->cursize + 25 > msg->maxsize)
938 sv_writeentitiestoclient_client = client;
940 sv_writeentitiestoclient_culled_pvs = 0;
941 sv_writeentitiestoclient_culled_trace = 0;
942 sv_writeentitiestoclient_visibleentities = 0;
943 sv_writeentitiestoclient_totalentities = 0;
945 // find the client's PVS
946 // the real place being tested from
947 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
948 sv_writeentitiestoclient_pvsbytes = 0;
949 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
950 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
952 csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
956 for (i = 0;i < numsendentities;i++)
957 SV_MarkWriteEntityStateToClient(sendentities + i);
960 for (i = 0;i < numsendentities;i++)
962 if (sententities[sendentities[i].number] == sententitiesmark)
964 s = &sendstates[numsendstates++];
965 *s = sendentities[i];
966 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
967 s->flags |= RENDER_EXTERIORMODEL;
971 if (sv_cullentities_stats.integer)
972 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);
974 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
976 if (client->entitydatabase5)
977 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
978 else if (client->entitydatabase4)
979 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
980 else if (client->entitydatabase)
981 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
983 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
992 void SV_CleanupEnts (void)
997 ent = PRVM_NEXT_EDICT(prog->edicts);
998 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
999 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
1004 SV_WriteClientdataToMessage
1008 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1012 prvm_edict_t *other;
1020 // send a damage message
1022 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
1024 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
1025 MSG_WriteByte (msg, svc_damage);
1026 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
1027 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
1028 for (i=0 ; i<3 ; i++)
1029 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
1031 ent->fields.server->dmg_take = 0;
1032 ent->fields.server->dmg_save = 0;
1036 // send the current viewpos offset from the view entity
1038 SV_SetIdealPitch (); // how much to look up / down ideally
1040 // a fixangle might get lost in a dropped packet. Oh well.
1041 if ( ent->fields.server->fixangle )
1043 MSG_WriteByte (msg, svc_setangle);
1044 for (i=0 ; i < 3 ; i++)
1045 MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
1046 ent->fields.server->fixangle = 0;
1049 // stuff the sigil bits into the high bits of items for sbar, or else
1051 val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
1052 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1053 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1055 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1057 VectorClear(punchvector);
1058 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
1059 VectorCopy(val->vector, punchvector);
1061 // cache weapon model name and index in client struct to save time
1062 // (this search can be almost 1% of cpu time!)
1063 s = PRVM_GetString(ent->fields.server->weaponmodel);
1064 if (strcmp(s, client->weaponmodel))
1066 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1067 client->weaponmodelindex = SV_ModelIndex(s, 1);
1071 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
1072 viewzoom = (int)(val->_float * 255.0f);
1078 if ((int)ent->fields.server->flags & FL_ONGROUND)
1079 bits |= SU_ONGROUND;
1080 if (ent->fields.server->waterlevel >= 2)
1082 if (ent->fields.server->idealpitch)
1083 bits |= SU_IDEALPITCH;
1085 for (i=0 ; i<3 ; i++)
1087 if (ent->fields.server->punchangle[i])
1088 bits |= (SU_PUNCH1<<i);
1089 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1091 bits |= (SU_PUNCHVEC1<<i);
1092 if (ent->fields.server->velocity[i])
1093 bits |= (SU_VELOCITY1<<i);
1096 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1097 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1098 stats[STAT_ITEMS] = items;
1099 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1100 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1101 stats[STAT_WEAPON] = client->weaponmodelindex;
1102 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1103 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1104 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1105 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1106 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1107 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1108 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1109 stats[STAT_VIEWZOOM] = viewzoom;
1110 // the QC bumps these itself by sending svc_'s, so we have to keep them
1111 // zero or they'll be corrected by the engine
1112 //stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1113 //stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1114 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1115 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1117 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)
1119 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1121 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1122 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1124 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1125 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1126 if (viewzoom != 255)
1127 bits |= SU_VIEWZOOM;
1132 if (bits >= 16777216)
1136 MSG_WriteByte (msg, svc_clientdata);
1137 MSG_WriteShort (msg, bits);
1138 if (bits & SU_EXTEND1)
1139 MSG_WriteByte(msg, bits >> 16);
1140 if (bits & SU_EXTEND2)
1141 MSG_WriteByte(msg, bits >> 24);
1143 if (bits & SU_VIEWHEIGHT)
1144 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1146 if (bits & SU_IDEALPITCH)
1147 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1149 for (i=0 ; i<3 ; i++)
1151 if (bits & (SU_PUNCH1<<i))
1153 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1154 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1156 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1158 if (bits & (SU_PUNCHVEC1<<i))
1160 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1161 MSG_WriteCoord16i(msg, punchvector[i]);
1163 MSG_WriteCoord32f(msg, punchvector[i]);
1165 if (bits & (SU_VELOCITY1<<i))
1167 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1168 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1170 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1174 if (bits & SU_ITEMS)
1175 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1177 if (sv.protocol == PROTOCOL_DARKPLACES5)
1179 if (bits & SU_WEAPONFRAME)
1180 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1181 if (bits & SU_ARMOR)
1182 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1183 if (bits & SU_WEAPON)
1184 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1185 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1186 MSG_WriteShort (msg, stats[STAT_AMMO]);
1187 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1188 MSG_WriteShort (msg, stats[STAT_NAILS]);
1189 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1190 MSG_WriteShort (msg, stats[STAT_CELLS]);
1191 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1192 if (bits & SU_VIEWZOOM)
1193 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1195 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)
1197 if (bits & SU_WEAPONFRAME)
1198 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1199 if (bits & SU_ARMOR)
1200 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1201 if (bits & SU_WEAPON)
1202 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1203 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1204 MSG_WriteByte (msg, stats[STAT_AMMO]);
1205 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1206 MSG_WriteByte (msg, stats[STAT_NAILS]);
1207 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1208 MSG_WriteByte (msg, stats[STAT_CELLS]);
1209 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1211 for (i = 0;i < 32;i++)
1212 if (stats[STAT_WEAPON] & (1<<i))
1214 MSG_WriteByte (msg, i);
1217 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1218 if (bits & SU_VIEWZOOM)
1220 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1221 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1223 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1229 =======================
1230 SV_SendClientDatagram
1231 =======================
1233 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1234 void SV_SendClientDatagram (client_t *client)
1236 int rate, maxrate, maxsize, maxsize2, downloadsize;
1238 int stats[MAX_CL_STATS];
1240 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1242 // for good singleplayer, send huge packets
1243 maxsize = sizeof(sv_sendclientdatagram_buf);
1244 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1246 else if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1248 // no rate limiting support on older protocols because dp protocols
1249 // 1-4 kick the client off if they overflow, and quake protocol shows
1250 // less than the full entity set if rate limited
1256 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1257 maxrate = max(NET_MINRATE, sv_maxrate.integer);
1258 if (sv_maxrate.integer != maxrate)
1259 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1261 // this rate limiting does not understand sys_ticrate 0
1262 // (but no one should be running that on a server!)
1263 rate = bound(NET_MINRATE, client->rate, maxrate);
1264 rate = (int)(rate * sys_ticrate.value);
1265 maxsize = bound(100, rate, 1400);
1269 // while downloading, limit entity updates to half the packet
1270 // (any leftover space will be used for downloading)
1271 if (host_client->download_file)
1274 msg.data = sv_sendclientdatagram_buf;
1275 msg.maxsize = maxsize;
1278 if (host_client->spawned)
1280 MSG_WriteByte (&msg, svc_time);
1281 MSG_WriteFloat (&msg, sv.time);
1283 // add the client specific data to the datagram
1284 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1285 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1286 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1288 // expand packet size to allow effects to go over the rate limit
1289 // (dropping them is FAR too ugly)
1290 msg.maxsize = maxsize2;
1292 // copy the server datagram if there is space
1293 // FIXME: put in delayed queue of effects to send
1294 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1295 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1297 else if (realtime > client->keepalivetime)
1299 // the player isn't totally in the game yet
1300 // send small keepalive messages if too much time has passed
1301 msg.maxsize = maxsize2;
1302 client->keepalivetime = realtime + 5;
1303 MSG_WriteChar (&msg, svc_nop);
1306 msg.maxsize = maxsize2;
1308 // if a download is active, see if there is room to fit some download data
1310 downloadsize = maxsize * 2 - msg.cursize - 7;
1311 if (host_client->download_file && host_client->download_started && downloadsize > 0)
1313 fs_offset_t downloadstart;
1314 unsigned char data[1400];
1315 downloadstart = FS_Tell(host_client->download_file);
1316 downloadsize = min(downloadsize, (int)sizeof(data));
1317 downloadsize = FS_Read(host_client->download_file, data, downloadsize);
1318 // note this sends empty messages if at the end of the file, which is
1319 // necessary to keep the packet loss logic working
1320 // (the last blocks may be lost and need to be re-sent, and that will
1321 // only occur if the client acks the empty end messages, revealing
1322 // a gap in the download progress, causing the last blocks to be
1324 MSG_WriteChar (&msg, svc_downloaddata);
1325 MSG_WriteLong (&msg, downloadstart);
1326 MSG_WriteShort (&msg, downloadsize);
1327 if (downloadsize > 0)
1328 SZ_Write (&msg, data, downloadsize);
1331 // send the datagram
1332 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1336 =======================
1337 SV_UpdateToReliableMessages
1338 =======================
1340 void SV_UpdateToReliableMessages (void)
1349 // check for changes to be sent over the reliable streams
1350 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1352 // update the host_client fields we care about according to the entity fields
1353 host_client->edict = PRVM_EDICT_NUM(i+1);
1356 name = PRVM_GetString(host_client->edict->fields.server->netname);
1359 // always point the string back at host_client->name to keep it safe
1360 strlcpy (host_client->name, name, sizeof (host_client->name));
1361 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1362 if (strcmp(host_client->old_name, host_client->name))
1364 if (host_client->spawned)
1365 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1366 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1367 // send notification to all clients
1368 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1369 MSG_WriteByte (&sv.reliable_datagram, i);
1370 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1373 // DP_SV_CLIENTCOLORS
1374 // this is always found (since it's added by the progs loader)
1375 if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1376 host_client->colors = (int)val->_float;
1377 if (host_client->old_colors != host_client->colors)
1379 host_client->old_colors = host_client->colors;
1380 // send notification to all clients
1381 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1382 MSG_WriteByte (&sv.reliable_datagram, i);
1383 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1386 // NEXUIZ_PLAYERMODEL
1387 if( eval_playermodel ) {
1388 model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string);
1391 // always point the string back at host_client->name to keep it safe
1392 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1393 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1396 // NEXUIZ_PLAYERSKIN
1397 if( eval_playerskin ) {
1398 skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string);
1401 // always point the string back at host_client->name to keep it safe
1402 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1403 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1407 host_client->frags = (int)host_client->edict->fields.server->frags;
1408 if (host_client->old_frags != host_client->frags)
1410 host_client->old_frags = host_client->frags;
1411 // send notification to all clients
1412 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1413 MSG_WriteByte (&sv.reliable_datagram, i);
1414 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1418 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1419 if (client->netconnection)
1420 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1422 SZ_Clear (&sv.reliable_datagram);
1427 =======================
1428 SV_SendClientMessages
1429 =======================
1431 void SV_SendClientMessages (void)
1433 int i, prepared = false;
1435 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1436 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1438 // update frags, names, etc
1439 SV_UpdateToReliableMessages();
1441 // build individual updates
1442 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1444 if (!host_client->active)
1446 if (!host_client->netconnection)
1449 if (host_client->netconnection->message.overflowed)
1451 SV_DropClient (true); // if the message couldn't send, kick off
1458 // only prepare entities once per frame
1459 SV_PrepareEntitiesForSending();
1461 SV_SendClientDatagram (host_client);
1464 // clear muzzle flashes
1468 void SV_StartDownload_f(void)
1470 if (host_client->download_file)
1471 host_client->download_started = true;
1474 void SV_Download_f(void)
1476 const char *whichpack, *whichpack2, *extension;
1478 if (Cmd_Argc() != 2)
1480 SV_ClientPrintf("usage: download <filename>\n");
1484 if (FS_CheckNastyPath(Cmd_Argv(1), false))
1486 SV_ClientPrintf("Download rejected: nasty filename \"%s\"\n", Cmd_Argv(1));
1490 if (host_client->download_file)
1492 // at this point we'll assume the previous download should be aborted
1493 Con_DPrintf("Download of %s aborted by %s starting a new download\n", host_client->download_name, host_client->name);
1494 Host_ClientCommands("\nstopdownload\n");
1496 // close the file and reset variables
1497 FS_Close(host_client->download_file);
1498 host_client->download_file = NULL;
1499 host_client->download_name[0] = 0;
1500 host_client->download_expectedposition = 0;
1501 host_client->download_started = false;
1504 if (!sv_allowdownloads.integer)
1506 SV_ClientPrintf("Downloads are disabled on this server\n");
1507 Host_ClientCommands("\nstopdownload\n");
1511 strlcpy(host_client->download_name, Cmd_Argv(1), sizeof(host_client->download_name));
1513 // host_client is asking to download a specified file
1514 if (developer.integer >= 100)
1515 Con_Printf("Download request for %s by %s\n", host_client->download_name, host_client->name);
1517 if (!FS_FileExists(host_client->download_name))
1519 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);
1520 Host_ClientCommands("\nstopdownload\n");
1524 // check if the user is trying to download part of registered Quake(r)
1525 whichpack = FS_WhichPack(host_client->download_name);
1526 whichpack2 = FS_WhichPack("gfx/pop.lmp");
1527 if ((whichpack && whichpack2 && !strcasecmp(whichpack, whichpack2)) || FS_IsRegisteredQuakePack(host_client->download_name))
1529 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);
1530 Host_ClientCommands("\nstopdownload\n");
1534 // check if the server has forbidden archive downloads entirely
1535 if (!sv_allowdownloads_inarchive.integer)
1537 whichpack = FS_WhichPack(host_client->download_name);
1540 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);
1541 Host_ClientCommands("\nstopdownload\n");
1546 if (!sv_allowdownloads_archive.integer)
1548 extension = FS_FileExtension(host_client->download_name);
1549 if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
1551 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);
1552 Host_ClientCommands("\nstopdownload\n");
1557 host_client->download_file = FS_Open(host_client->download_name, "rb", true, false);
1558 if (!host_client->download_file)
1560 SV_ClientPrintf("Download rejected: server could not open the file \"%s\"\n", host_client->download_name);
1561 Host_ClientCommands("\nstopdownload\n");
1565 if (FS_FileSize(host_client->download_file) > 1<<30)
1567 SV_ClientPrintf("Download rejected: file \"%s\" is very large\n", host_client->download_name);
1568 Host_ClientCommands("\nstopdownload\n");
1569 FS_Close(host_client->download_file);
1570 host_client->download_file = NULL;
1574 Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
1576 Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name);
1578 host_client->download_expectedposition = 0;
1579 host_client->download_started = false;
1581 // the rest of the download process is handled in SV_SendClientDatagram
1582 // and other code dealing with svc_downloaddata and clc_ackdownloaddata
1584 // no svc_downloaddata messages will be sent until sv_startdownload is
1585 // sent by the client
1589 ==============================================================================
1593 ==============================================================================
1602 int SV_ModelIndex(const char *s, int precachemode)
1604 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1605 char filename[MAX_QPATH];
1609 //if (precachemode == 2)
1611 strlcpy(filename, s, sizeof(filename));
1612 for (i = 2;i < limit;i++)
1614 if (!sv.model_precache[i][0])
1618 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))
1620 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1623 if (precachemode == 1)
1624 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1625 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1626 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1627 if (sv.state != ss_loading)
1629 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1630 MSG_WriteShort(&sv.reliable_datagram, i);
1631 MSG_WriteString(&sv.reliable_datagram, filename);
1635 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1638 if (!strcmp(sv.model_precache[i], filename))
1641 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1651 int SV_SoundIndex(const char *s, int precachemode)
1653 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1654 char filename[MAX_QPATH];
1658 //if (precachemode == 2)
1660 strlcpy(filename, s, sizeof(filename));
1661 for (i = 1;i < limit;i++)
1663 if (!sv.sound_precache[i][0])
1667 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))
1669 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1672 if (precachemode == 1)
1673 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1674 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1675 if (sv.state != ss_loading)
1677 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1678 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1679 MSG_WriteString(&sv.reliable_datagram, filename);
1683 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1686 if (!strcmp(sv.sound_precache[i], filename))
1689 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1699 void SV_CreateBaseline (void)
1701 int i, entnum, large;
1702 prvm_edict_t *svent;
1704 // LordHavoc: clear *all* states (note just active ones)
1705 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1707 // get the current server version
1708 svent = PRVM_EDICT_NUM(entnum);
1710 // LordHavoc: always clear state values, whether the entity is in use or not
1711 svent->priv.server->baseline = defaultstate;
1713 if (svent->priv.server->free)
1715 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1718 // create entity baseline
1719 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1720 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1721 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1722 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1723 if (entnum > 0 && entnum <= svs.maxclients)
1725 svent->priv.server->baseline.colormap = entnum;
1726 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1730 svent->priv.server->baseline.colormap = 0;
1731 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1735 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1738 // add to the message
1740 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1742 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1743 MSG_WriteShort (&sv.signon, entnum);
1747 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1748 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1752 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1753 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1755 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1756 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1757 for (i=0 ; i<3 ; i++)
1759 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1760 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1770 Grabs the current state of each client for saving across the
1771 transition to another level
1774 void SV_SaveSpawnparms (void)
1778 svs.serverflags = (int)prog->globals.server->serverflags;
1780 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1782 if (!host_client->active)
1785 // call the progs to get default spawn parms for the new client
1786 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1787 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1788 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1789 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1793 void SV_IncreaseEdicts(void)
1797 int oldmax_edicts = prog->max_edicts;
1798 void *oldedictsengineprivate = prog->edictprivate;
1799 void *oldedictsfields = prog->edictsfields;
1800 void *oldmoved_edicts = sv.moved_edicts;
1802 if (prog->max_edicts >= MAX_EDICTS)
1805 // links don't survive the transition, so unlink everything
1806 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1808 if (!ent->priv.server->free)
1809 SV_UnlinkEdict(prog->edicts + i);
1810 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1814 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
1815 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1816 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
1817 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1819 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
1820 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
1822 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1824 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1825 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1826 // link every entity except world
1827 if (!ent->priv.server->free)
1828 SV_LinkEdict(ent, false);
1831 PR_Free(oldedictsengineprivate);
1832 PR_Free(oldedictsfields);
1833 PR_Free(oldmoved_edicts);
1840 This is called at the start of each level
1843 extern float scr_centertime_off;
1845 void SV_SpawnServer (const char *server)
1850 model_t *worldmodel;
1851 char modelname[sizeof(sv.modelname)];
1853 Con_DPrintf("SpawnServer: %s\n", server);
1855 if (cls.state != ca_dedicated)
1856 SCR_BeginLoadingPlaque();
1858 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
1859 worldmodel = Mod_ForName(modelname, false, true, true);
1860 if (!worldmodel || !worldmodel->TraceBox)
1862 Con_Printf("Couldn't load map %s\n", modelname);
1866 // let's not have any servers with no name
1867 if (hostname.string[0] == 0)
1868 Cvar_Set ("hostname", "UNNAMED");
1869 scr_centertime_off = 0;
1871 svs.changelevel_issued = false; // now safe to issue another
1873 // make the map a required file for clients
1874 Curl_ClearRequirements();
1875 Curl_RequireFile(modelname);
1878 // tell all connected clients that we are going to a new level
1883 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1885 if (client->netconnection)
1887 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
1888 MSG_WriteString(&client->netconnection->message, "reconnect\n");
1895 NetConn_OpenServerPorts(true);
1899 // make cvars consistant
1902 Cvar_SetValue ("deathmatch", 0);
1903 // LordHavoc: it can be useful to have skills outside the range 0-3...
1904 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
1905 //Cvar_SetValue ("skill", (float)current_skill);
1906 current_skill = (int)(skill.value + 0.5);
1909 // set up the new server
1911 memset (&sv, 0, sizeof(sv));
1912 // if running a local client, make sure it doesn't try to access the last
1913 // level's data which is no longer valiud
1916 if(*sv_random_seed.string)
1918 srand(sv_random_seed.integer);
1919 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);
1926 strlcpy (sv.name, server, sizeof (sv.name));
1928 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
1929 if (sv.protocol == PROTOCOL_UNKNOWN)
1932 Protocol_Names(buffer, sizeof(buffer));
1933 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
1934 sv.protocol = PROTOCOL_QUAKE;
1939 // load progs to get entity field count
1940 //PR_LoadProgs ( sv_progs.string );
1942 // allocate server memory
1943 /*// start out with just enough room for clients and a reasonable estimate of entities
1944 prog->max_edicts = max(svs.maxclients + 1, 512);
1945 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
1947 // prvm_edict_t structures (hidden from progs)
1948 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
1949 // engine private structures (hidden from progs)
1950 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1951 // progs fields, often accessed by server
1952 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
1953 // used by PushMove to move back pushed entities
1954 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1955 /*for (i = 0;i < prog->max_edicts;i++)
1957 ent = prog->edicts + i;
1958 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1959 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1962 // reset client csqc entity versions right away.
1963 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1964 EntityFrameCSQC_InitClientVersions(i, true);
1966 sv.datagram.maxsize = sizeof(sv.datagram_buf);
1967 sv.datagram.cursize = 0;
1968 sv.datagram.data = sv.datagram_buf;
1970 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
1971 sv.reliable_datagram.cursize = 0;
1972 sv.reliable_datagram.data = sv.reliable_datagram_buf;
1974 sv.signon.maxsize = sizeof(sv.signon_buf);
1975 sv.signon.cursize = 0;
1976 sv.signon.data = sv.signon_buf;
1978 // leave slots at start for clients only
1979 //prog->num_edicts = svs.maxclients+1;
1981 sv.state = ss_loading;
1982 prog->allowworldwrites = true;
1985 *prog->time = sv.time = 1.0;
1988 worldmodel->used = true;
1990 strlcpy (sv.name, server, sizeof (sv.name));
1991 strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
1992 sv.worldmodel = worldmodel;
1993 sv.models[1] = sv.worldmodel;
1996 // clear world interaction links
2000 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
2002 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
2003 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
2004 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
2006 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
2007 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
2011 // load the rest of the entities
2013 // AK possible hack since num_edicts is still 0
2014 ent = PRVM_EDICT_NUM(0);
2015 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
2016 ent->priv.server->free = false;
2017 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
2018 ent->fields.server->modelindex = 1; // world model
2019 ent->fields.server->solid = SOLID_BSP;
2020 ent->fields.server->movetype = MOVETYPE_PUSH;
2021 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->mins);
2022 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->maxs);
2023 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->absmin);
2024 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->absmax);
2027 prog->globals.server->coop = coop.integer;
2029 prog->globals.server->deathmatch = deathmatch.integer;
2031 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
2033 // serverflags are for cross level information (sigils)
2034 prog->globals.server->serverflags = svs.serverflags;
2036 // we need to reset the spawned flag on all connected clients here so that
2037 // their thinks don't run during startup (before PutClientInServer)
2038 // we also need to set up the client entities now
2039 // and we need to set the ->edict pointers to point into the progs edicts
2040 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2042 host_client->spawned = false;
2043 host_client->edict = PRVM_EDICT_NUM(i + 1);
2044 PRVM_ED_ClearEdict(host_client->edict);
2047 // load replacement entity file if found
2048 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
2050 Con_Printf("Loaded maps/%s.ent\n", sv.name);
2051 PRVM_ED_LoadFromFile (entities);
2055 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
2058 // LordHavoc: clear world angles (to fix e3m3.bsp)
2059 VectorClear(prog->edicts->fields.server->angles);
2061 // all setup is completed, any further precache statements are errors
2062 sv.state = ss_active;
2063 prog->allowworldwrites = false;
2065 // run two frames to allow everything to settle
2066 for (i = 0;i < 2;i++)
2074 // create a baseline for more efficient communications
2075 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
2076 SV_CreateBaseline ();
2078 // send serverinfo to all connected clients, and set up botclients coming back from a level change
2079 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2081 if (!host_client->active)
2083 if (host_client->netconnection)
2084 SV_SendServerinfo(host_client);
2088 // if client is a botclient coming from a level change, we need to
2089 // set up client info that normally requires networking
2091 // copy spawn parms out of the client_t
2092 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
2093 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
2095 // call the spawn function
2096 host_client->clientconnectcalled = true;
2097 prog->globals.server->time = sv.time;
2098 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2099 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
2100 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
2101 host_client->spawned = true;
2105 Con_DPrint("Server spawned.\n");
2106 NetConn_Heartbeat (2);
2111 /////////////////////////////////////////////////////
2114 void SV_VM_CB_BeginIncreaseEdicts(void)
2119 PRVM_Free( sv.moved_edicts );
2120 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2122 // links don't survive the transition, so unlink everything
2123 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2125 if (!ent->priv.server->free)
2126 SV_UnlinkEdict(prog->edicts + i);
2127 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
2132 void SV_VM_CB_EndIncreaseEdicts(void)
2137 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2139 // link every entity except world
2140 if (!ent->priv.server->free)
2141 SV_LinkEdict(ent, false);
2145 void SV_VM_CB_InitEdict(prvm_edict_t *e)
2147 // LordHavoc: for consistency set these here
2148 int num = PRVM_NUM_FOR_EDICT(e) - 1;
2150 e->priv.server->move = false; // don't move on first frame
2152 if (num >= 0 && num < svs.maxclients)
2155 // set colormap and team on newly created player entity
2156 e->fields.server->colormap = num + 1;
2157 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
2158 // set netname/clientcolors back to client values so that
2159 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
2161 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
2162 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
2163 val->_float = svs.clients[num].colors;
2164 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
2165 if( eval_playermodel )
2166 PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
2167 if( eval_playerskin )
2168 PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
2172 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
2174 SV_UnlinkEdict (ed); // unlink from world bsp
2176 ed->fields.server->model = 0;
2177 ed->fields.server->takedamage = 0;
2178 ed->fields.server->modelindex = 0;
2179 ed->fields.server->colormap = 0;
2180 ed->fields.server->skin = 0;
2181 ed->fields.server->frame = 0;
2182 VectorClear(ed->fields.server->origin);
2183 VectorClear(ed->fields.server->angles);
2184 ed->fields.server->nextthink = -1;
2185 ed->fields.server->solid = 0;
2188 void SV_VM_CB_CountEdicts(void)
2192 int active, models, solid, step;
2194 active = models = solid = step = 0;
2195 for (i=0 ; i<prog->num_edicts ; i++)
2197 ent = PRVM_EDICT_NUM(i);
2198 if (ent->priv.server->free)
2201 if (ent->fields.server->solid)
2203 if (ent->fields.server->model)
2205 if (ent->fields.server->movetype == MOVETYPE_STEP)
2209 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2210 Con_Printf("active :%3i\n", active);
2211 Con_Printf("view :%3i\n", models);
2212 Con_Printf("touch :%3i\n", solid);
2213 Con_Printf("step :%3i\n", step);
2216 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2218 // remove things from different skill levels or deathmatch
2219 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2221 if (deathmatch.integer)
2223 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2228 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2229 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2230 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2238 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)"};
2239 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2240 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2241 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2242 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2243 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2244 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2245 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2246 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2247 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2248 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2249 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2250 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2251 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2252 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2253 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2254 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2255 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2256 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2257 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2258 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2259 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2260 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2261 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2262 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2263 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2264 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2265 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2266 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2267 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2268 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2269 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2270 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2272 void SV_VM_Init(void)
2274 Cvar_RegisterVariable (&pr_checkextension);
2275 Cvar_RegisterVariable (&nomonsters);
2276 Cvar_RegisterVariable (&gamecfg);
2277 Cvar_RegisterVariable (&scratch1);
2278 Cvar_RegisterVariable (&scratch2);
2279 Cvar_RegisterVariable (&scratch3);
2280 Cvar_RegisterVariable (&scratch4);
2281 Cvar_RegisterVariable (&savedgamecfg);
2282 Cvar_RegisterVariable (&saved1);
2283 Cvar_RegisterVariable (&saved2);
2284 Cvar_RegisterVariable (&saved3);
2285 Cvar_RegisterVariable (&saved4);
2286 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2287 if (gamemode == GAME_NEHAHRA)
2289 Cvar_RegisterVariable (&nehx00);
2290 Cvar_RegisterVariable (&nehx01);
2291 Cvar_RegisterVariable (&nehx02);
2292 Cvar_RegisterVariable (&nehx03);
2293 Cvar_RegisterVariable (&nehx04);
2294 Cvar_RegisterVariable (&nehx05);
2295 Cvar_RegisterVariable (&nehx06);
2296 Cvar_RegisterVariable (&nehx07);
2297 Cvar_RegisterVariable (&nehx08);
2298 Cvar_RegisterVariable (&nehx09);
2299 Cvar_RegisterVariable (&nehx10);
2300 Cvar_RegisterVariable (&nehx11);
2301 Cvar_RegisterVariable (&nehx12);
2302 Cvar_RegisterVariable (&nehx13);
2303 Cvar_RegisterVariable (&nehx14);
2304 Cvar_RegisterVariable (&nehx15);
2305 Cvar_RegisterVariable (&nehx16);
2306 Cvar_RegisterVariable (&nehx17);
2307 Cvar_RegisterVariable (&nehx18);
2308 Cvar_RegisterVariable (&nehx19);
2310 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2313 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
2330 int eval_buttonchat;
2332 int eval_glow_trail;
2333 int eval_glow_color;
2337 int eval_renderamt; // HalfLife support
2338 int eval_rendermode; // HalfLife support
2339 int eval_fullbright;
2340 int eval_ammo_shells1;
2341 int eval_ammo_nails1;
2342 int eval_ammo_lava_nails;
2343 int eval_ammo_rockets1;
2344 int eval_ammo_multi_rockets;
2345 int eval_ammo_cells1;
2346 int eval_ammo_plasma;
2347 int eval_idealpitch;
2348 int eval_pitch_speed;
2349 int eval_viewmodelforclient;
2350 int eval_nodrawtoclient;
2351 int eval_exteriormodeltoclient;
2352 int eval_drawonlytoclient;
2356 int eval_punchvector;
2358 int eval_clientcolors;
2359 int eval_tag_entity;
2365 int eval_cursor_active;
2366 int eval_cursor_screen;
2367 int eval_cursor_trace_start;
2368 int eval_cursor_trace_endpos;
2369 int eval_cursor_trace_ent;
2371 int eval_playermodel;
2372 int eval_playerskin;
2373 int eval_SendEntity;
2375 int eval_customizeentityforclient;
2376 int eval_dphitcontentsmask;
2377 // DRESK - Support for Entity Contents Transition Event
2378 int eval_contentstransition;
2380 int gval_trace_dpstartcontents;
2381 int gval_trace_dphitcontents;
2382 int gval_trace_dphitq3surfaceflags;
2383 int gval_trace_dphittexturename;
2385 mfunction_t *SV_PlayerPhysicsQC;
2386 mfunction_t *EndFrameQC;
2387 //KrimZon - SERVER COMMANDS IN QUAKEC
2388 mfunction_t *SV_ParseClientCommandQC;
2390 void SV_VM_FindEdictFieldOffsets(void)
2392 eval_gravity = PRVM_ED_FindFieldOffset("gravity");
2393 eval_button3 = PRVM_ED_FindFieldOffset("button3");
2394 eval_button4 = PRVM_ED_FindFieldOffset("button4");
2395 eval_button5 = PRVM_ED_FindFieldOffset("button5");
2396 eval_button6 = PRVM_ED_FindFieldOffset("button6");
2397 eval_button7 = PRVM_ED_FindFieldOffset("button7");
2398 eval_button8 = PRVM_ED_FindFieldOffset("button8");
2399 eval_button9 = PRVM_ED_FindFieldOffset("button9");
2400 eval_button10 = PRVM_ED_FindFieldOffset("button10");
2401 eval_button11 = PRVM_ED_FindFieldOffset("button11");
2402 eval_button12 = PRVM_ED_FindFieldOffset("button12");
2403 eval_button13 = PRVM_ED_FindFieldOffset("button13");
2404 eval_button14 = PRVM_ED_FindFieldOffset("button14");
2405 eval_button15 = PRVM_ED_FindFieldOffset("button15");
2406 eval_button16 = PRVM_ED_FindFieldOffset("button16");
2407 eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
2408 eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
2409 eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
2410 eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
2411 eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
2412 eval_items2 = PRVM_ED_FindFieldOffset("items2");
2413 eval_scale = PRVM_ED_FindFieldOffset("scale");
2414 eval_alpha = PRVM_ED_FindFieldOffset("alpha");
2415 eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
2416 eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
2417 eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
2418 eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
2419 eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
2420 eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
2421 eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
2422 eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
2423 eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
2424 eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
2425 eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
2426 eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
2427 eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
2428 eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
2429 eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
2430 eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
2431 eval_ping = PRVM_ED_FindFieldOffset("ping");
2432 eval_movement = PRVM_ED_FindFieldOffset("movement");
2433 eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
2434 eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
2435 eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
2436 eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
2437 eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
2438 eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
2439 eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
2440 eval_color = PRVM_ED_FindFieldOffset("color");
2441 eval_style = PRVM_ED_FindFieldOffset("style");
2442 eval_pflags = PRVM_ED_FindFieldOffset("pflags");
2443 eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
2444 eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
2445 eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
2446 eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
2447 eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
2448 eval_colormod = PRVM_ED_FindFieldOffset("colormod");
2449 eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
2450 eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
2451 eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
2452 eval_Version = PRVM_ED_FindFieldOffset("Version");
2453 eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
2454 eval_dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
2455 // DRESK - Support for Entity Contents Transition Event
2456 eval_contentstransition = PRVM_ED_FindFieldOffset("contentstransition");
2458 // LordHavoc: allowing QuakeC to override the player movement code
2459 SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
2460 // LordHavoc: support for endframe
2461 EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
2462 //KrimZon - SERVER COMMANDS IN QUAKEC
2463 SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
2464 gval_trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
2465 gval_trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
2466 gval_trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
2467 gval_trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
2470 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2472 prvm_required_field_t reqfields[] =
2474 {ev_entity, "cursor_trace_ent"},
2475 {ev_entity, "drawonlytoclient"},
2476 {ev_entity, "exteriormodeltoclient"},
2477 {ev_entity, "nodrawtoclient"},
2478 {ev_entity, "tag_entity"},
2479 {ev_entity, "viewmodelforclient"},
2480 {ev_float, "alpha"},
2481 {ev_float, "ammo_cells1"},
2482 {ev_float, "ammo_lava_nails"},
2483 {ev_float, "ammo_multi_rockets"},
2484 {ev_float, "ammo_nails1"},
2485 {ev_float, "ammo_plasma"},
2486 {ev_float, "ammo_rockets1"},
2487 {ev_float, "ammo_shells1"},
2488 {ev_float, "button3"},
2489 {ev_float, "button4"},
2490 {ev_float, "button5"},
2491 {ev_float, "button6"},
2492 {ev_float, "button7"},
2493 {ev_float, "button8"},
2494 {ev_float, "button9"},
2495 {ev_float, "button10"},
2496 {ev_float, "button11"},
2497 {ev_float, "button12"},
2498 {ev_float, "button13"},
2499 {ev_float, "button14"},
2500 {ev_float, "button15"},
2501 {ev_float, "button16"},
2502 {ev_float, "buttonchat"},
2503 {ev_float, "buttonuse"},
2504 {ev_float, "clientcolors"},
2505 {ev_float, "cursor_active"},
2506 {ev_float, "fullbright"},
2507 {ev_float, "glow_color"},
2508 {ev_float, "glow_size"},
2509 {ev_float, "glow_trail"},
2510 {ev_float, "gravity"},
2511 {ev_float, "idealpitch"},
2512 {ev_float, "items2"},
2513 {ev_float, "light_lev"},
2514 {ev_float, "pflags"},
2516 {ev_float, "pitch_speed"},
2517 {ev_float, "pmodel"},
2518 {ev_float, "renderamt"}, // HalfLife support
2519 {ev_float, "rendermode"}, // HalfLife support
2520 {ev_float, "scale"},
2521 {ev_float, "style"},
2522 {ev_float, "tag_index"},
2523 {ev_float, "Version"},
2524 {ev_float, "viewzoom"},
2525 {ev_vector, "color"},
2526 {ev_vector, "colormod"},
2527 {ev_vector, "cursor_screen"},
2528 {ev_vector, "cursor_trace_endpos"},
2529 {ev_vector, "cursor_trace_start"},
2530 {ev_vector, "movement"},
2531 {ev_vector, "punchvector"},
2532 {ev_string, "playermodel"},
2533 {ev_string, "playerskin"},
2534 {ev_function, "SendEntity"},
2535 {ev_function, "customizeentityforclient"},
2536 // DRESK - Support for Entity Contents Transition Event
2537 {ev_function, "contentstransition"},
2540 void SV_VM_Setup(void)
2542 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
2543 extern cvar_t csqc_progcrc;
2544 unsigned char *csprogsdata;
2545 fs_offset_t csprogsdatasize;
2547 PRVM_InitProg( PRVM_SERVERPROG );
2549 // allocate the mempools
2550 // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
2551 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2552 prog->builtins = vm_sv_builtins;
2553 prog->numbuiltins = vm_sv_numbuiltins;
2554 prog->headercrc = PROGHEADER_CRC;
2555 prog->max_edicts = 512;
2556 prog->limit_edicts = MAX_EDICTS;
2557 prog->reserved_edicts = svs.maxclients;
2558 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2559 prog->name = "server";
2560 prog->extensionstring = vm_sv_extensions;
2561 prog->loadintoworld = true;
2563 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2564 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2565 prog->init_edict = SV_VM_CB_InitEdict;
2566 prog->free_edict = SV_VM_CB_FreeEdict;
2567 prog->count_edicts = SV_VM_CB_CountEdicts;
2568 prog->load_edict = SV_VM_CB_LoadEdict;
2569 prog->init_cmd = VM_SV_Cmd_Init;
2570 prog->reset_cmd = VM_SV_Cmd_Reset;
2571 prog->error_cmd = Host_Error;
2573 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2574 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
2575 SV_VM_FindEdictFieldOffsets();
2577 VM_AutoSentStats_Clear();//[515]: csqc
2578 EntityFrameCSQC_ClearVersions();//[515]: csqc
2582 // 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
2583 sv.csqc_progcrc = -1;
2584 sv.csqc_progname[0] = 0;
2585 csprogsdata = FS_LoadFile(csqc_progname.string, tempmempool, true, &csprogsdatasize);
2588 strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
2589 sv.csqc_progcrc = CRC_Block(csprogsdata, csprogsdatasize);
2590 Mem_Free(csprogsdata);
2591 Con_DPrintf("server detected csqc progs file \"%s\" with crc %i\n", sv.csqc_progname, sv.csqc_progcrc);
2595 void SV_VM_Begin(void)
2598 PRVM_SetProg( PRVM_SERVERPROG );
2600 *prog->time = (float) sv.time;
2603 void SV_VM_End(void)