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"};
61 cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
63 // TODO: move these cvars here
64 extern cvar_t sv_clmovement_enable;
65 extern cvar_t sv_clmovement_minping;
66 extern cvar_t sv_clmovement_minping_disabletime;
67 extern cvar_t sv_clmovement_waitforinput;
72 mempool_t *sv_mempool = NULL;
74 //============================================================================
76 extern void SV_Phys_Init (void);
77 extern void SV_World_Init (void);
78 static void SV_SaveEntFile_f(void);
79 static void SV_StartDownload_f(void);
80 static void SV_Download_f(void);
89 // init the csqc progs cvars, since they are updated/used by the server code
90 // TODO: fix this since this is a quick hack to make some of [515]'s broken code run ;) [9/13/2006 Black]
91 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
92 extern cvar_t csqc_progcrc;
93 Cvar_RegisterVariable (&csqc_progname);
94 Cvar_RegisterVariable (&csqc_progcrc);
96 Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
97 Cmd_AddCommand_WithClientCommand("sv_startdownload", NULL, SV_StartDownload_f, "begins sending a file to the client (network protocol use only)");
98 Cmd_AddCommand_WithClientCommand("download", NULL, SV_Download_f, "downloads a specified file from the server");
99 Cvar_RegisterVariable (&sv_maxvelocity);
100 Cvar_RegisterVariable (&sv_gravity);
101 Cvar_RegisterVariable (&sv_friction);
102 Cvar_RegisterVariable (&sv_waterfriction);
103 Cvar_RegisterVariable (&sv_edgefriction);
104 Cvar_RegisterVariable (&sv_stopspeed);
105 Cvar_RegisterVariable (&sv_maxspeed);
106 Cvar_RegisterVariable (&sv_maxairspeed);
107 Cvar_RegisterVariable (&sv_accelerate);
108 Cvar_RegisterVariable (&sv_airaccelerate);
109 Cvar_RegisterVariable (&sv_wateraccelerate);
110 Cvar_RegisterVariable (&sv_clmovement_enable);
111 Cvar_RegisterVariable (&sv_clmovement_minping);
112 Cvar_RegisterVariable (&sv_clmovement_minping_disabletime);
113 Cvar_RegisterVariable (&sv_clmovement_waitforinput);
114 Cvar_RegisterVariable (&sv_idealpitchscale);
115 Cvar_RegisterVariable (&sv_aim);
116 Cvar_RegisterVariable (&sv_nostep);
117 Cvar_RegisterVariable (&sv_cullentities_pvs);
118 Cvar_RegisterVariable (&sv_cullentities_trace);
119 Cvar_RegisterVariable (&sv_cullentities_stats);
120 Cvar_RegisterVariable (&sv_entpatch);
121 Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
122 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
123 Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
124 Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
125 Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
126 Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
127 Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
128 Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
129 Cvar_RegisterVariable (&sv_gameplayfix_qwplayerphysics);
130 Cvar_RegisterVariable (&sv_gameplayfix_upwardvelocityclearsongroundflag);
131 Cvar_RegisterVariable (&sv_protocolname);
132 Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
133 Cvar_RegisterVariable (&sv_maxrate);
134 Cvar_RegisterVariable (&sv_allowdownloads);
135 Cvar_RegisterVariable (&sv_allowdownloads_inarchive);
136 Cvar_RegisterVariable (&sv_allowdownloads_archive);
137 Cvar_RegisterVariable (&sv_progs);
143 sv_mempool = Mem_AllocPool("server", 0, NULL);
146 static void SV_SaveEntFile_f(void)
148 char basename[MAX_QPATH];
149 if (!sv.active || !sv.worldmodel)
151 Con_Print("Not running a server\n");
154 FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
155 FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
160 =============================================================================
164 =============================================================================
171 Make sure the event gets sent to all clients
174 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
178 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
180 MSG_WriteByte (&sv.datagram, svc_particle);
181 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
182 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
183 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
184 for (i=0 ; i<3 ; i++)
185 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
186 MSG_WriteByte (&sv.datagram, count);
187 MSG_WriteByte (&sv.datagram, color);
194 Make sure the event gets sent to all clients
197 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
199 if (modelindex >= 256 || startframe >= 256)
201 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
203 MSG_WriteByte (&sv.datagram, svc_effect2);
204 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
205 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
206 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
207 MSG_WriteShort (&sv.datagram, modelindex);
208 MSG_WriteShort (&sv.datagram, startframe);
209 MSG_WriteByte (&sv.datagram, framecount);
210 MSG_WriteByte (&sv.datagram, framerate);
214 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
216 MSG_WriteByte (&sv.datagram, svc_effect);
217 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
218 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
219 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
220 MSG_WriteByte (&sv.datagram, modelindex);
221 MSG_WriteByte (&sv.datagram, startframe);
222 MSG_WriteByte (&sv.datagram, framecount);
223 MSG_WriteByte (&sv.datagram, framerate);
231 Each entity can have eight independant sound sources, like voice,
234 Channel 0 is an auto-allocate channel, the others override anything
235 already running on that entity/channel pair.
237 An attenuation of 0 will play full volume everywhere in the level.
238 Larger attenuations will drop off. (max 4 attenuation)
242 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
244 int sound_num, field_mask, i, ent;
246 if (volume < 0 || volume > 255)
248 Con_Printf ("SV_StartSound: volume = %i\n", volume);
252 if (attenuation < 0 || attenuation > 4)
254 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
258 if (channel < 0 || channel > 7)
260 Con_Printf ("SV_StartSound: channel = %i\n", channel);
264 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
267 // find precache number for sound
268 sound_num = SV_SoundIndex(sample, 1);
272 ent = PRVM_NUM_FOR_EDICT(entity);
275 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
276 field_mask |= SND_VOLUME;
277 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
278 field_mask |= SND_ATTENUATION;
280 field_mask |= SND_LARGEENTITY;
281 if (sound_num >= 256 || channel >= 8)
282 field_mask |= SND_LARGESOUND;
284 // directed messages go only to the entity they are targeted on
285 MSG_WriteByte (&sv.datagram, svc_sound);
286 MSG_WriteByte (&sv.datagram, field_mask);
287 if (field_mask & SND_VOLUME)
288 MSG_WriteByte (&sv.datagram, volume);
289 if (field_mask & SND_ATTENUATION)
290 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
291 if (field_mask & SND_LARGEENTITY)
293 MSG_WriteShort (&sv.datagram, ent);
294 MSG_WriteByte (&sv.datagram, channel);
297 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
298 if (field_mask & SND_LARGESOUND)
299 MSG_WriteShort (&sv.datagram, sound_num);
301 MSG_WriteByte (&sv.datagram, sound_num);
302 for (i = 0;i < 3;i++)
303 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
307 ==============================================================================
311 ==============================================================================
318 Sends the first message from the server to a connected client.
319 This will be sent on the initial connection and upon each server load.
322 void SV_SendServerinfo (client_t *client)
327 // we know that this client has a netconnection and thus is not a bot
329 // edicts get reallocated on level changes, so we need to update it here
330 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
332 // clear cached stuff that depends on the level
333 client->weaponmodel[0] = 0;
334 client->weaponmodelindex = 0;
336 // LordHavoc: clear entityframe tracking
337 client->latestframenum = 0;
339 if (client->entitydatabase)
340 EntityFrame_FreeDatabase(client->entitydatabase);
341 if (client->entitydatabase4)
342 EntityFrame4_FreeDatabase(client->entitydatabase4);
343 if (client->entitydatabase5)
344 EntityFrame5_FreeDatabase(client->entitydatabase5);
346 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
348 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
349 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
350 else if (sv.protocol == PROTOCOL_DARKPLACES4)
351 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
353 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
356 SZ_Clear (&client->netconnection->message);
357 MSG_WriteByte (&client->netconnection->message, svc_print);
358 dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
359 MSG_WriteString (&client->netconnection->message,message);
361 //[515]: init csprogs according to version of svprogs, check the crc, etc.
362 if (sv.csqc_progcrc >= 0)
365 Con_DPrintf("sending csqc info to client (\"%s\" with crc %i)\n", sv.csqc_progname, sv.csqc_progcrc);
366 //[515]: init stufftext string (it is sent before svc_serverinfo)
367 val = PRVM_GETGLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset("SV_InitCmd"));
368 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
369 MSG_WriteString (&client->netconnection->message, va("csqc_progname %s\n", sv.csqc_progname));
370 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
371 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", sv.csqc_progcrc));
374 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
375 MSG_WriteString (&client->netconnection->message, va("%s\n", PRVM_GetString(val->string)));
379 if (sv_allowdownloads.integer)
381 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
382 MSG_WriteString (&client->netconnection->message, "cl_serverextension_download 1");
385 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
386 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
387 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
389 if (!coop.integer && deathmatch.integer)
390 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
392 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
394 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
396 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
397 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
398 MSG_WriteByte (&client->netconnection->message, 0);
400 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
401 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
402 MSG_WriteByte (&client->netconnection->message, 0);
405 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
406 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
407 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
410 MSG_WriteByte (&client->netconnection->message, svc_setview);
411 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
413 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
414 MSG_WriteByte (&client->netconnection->message, 1);
419 host_client = client;
420 Curl_SendRequirements();
424 client->spawned = false; // need prespawn, spawn, etc
431 Initializes a client_t for a new net connection. This will only be called
432 once for a player each game, not once for each level change.
435 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
439 float spawn_parms[NUM_SPAWN_PARMS];
441 client = svs.clients + clientnum;
443 if(netconnection)//[515]: bots don't play with csqc =)
444 EntityFrameCSQC_InitClientVersions(clientnum, false);
446 // set up the client_t
448 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
449 memset (client, 0, sizeof(*client));
450 client->active = true;
451 client->netconnection = netconnection;
453 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
455 strlcpy(client->name, "unconnected", sizeof(client->name));
456 strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
457 client->spawned = false;
458 client->edict = PRVM_EDICT_NUM(clientnum+1);
459 if (client->netconnection)
460 client->netconnection->message.allowoverflow = true; // we can catch it
461 // updated by receiving "rate" command from client
462 client->rate = NET_MINRATE;
463 // no limits for local player
464 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
465 client->rate = 1000000000;
466 client->connecttime = realtime;
469 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
472 // call the progs to get default spawn parms for the new client
473 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
474 prog->globals.server->self = 0;
475 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
476 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
477 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
479 // set up the entity for this client (including .colormap, .team, etc)
480 PRVM_ED_ClearEdict(client->edict);
483 // don't call SendServerinfo for a fresh botclient because its fields have
484 // not been set up by the qc yet
485 if (client->netconnection)
486 SV_SendServerinfo (client);
488 client->spawned = true;
493 ===============================================================================
497 ===============================================================================
506 void SV_ClearDatagram (void)
508 SZ_Clear (&sv.datagram);
512 =============================================================================
514 The PVS must include a small area around the client to allow head bobbing
515 or other small motion on the client side. Otherwise, a bob might cause an
516 entity that should be visible to not show up, especially when the bob
519 =============================================================================
522 int sv_writeentitiestoclient_pvsbytes;
523 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
525 static int numsendentities;
526 static entity_state_t sendentities[MAX_EDICTS];
527 static entity_state_t *sendentitiesindex[MAX_EDICTS];
529 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
532 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
533 unsigned int customizeentityforclient;
535 vec3_t cullmins, cullmaxs;
539 // EF_NODRAW prevents sending for any reason except for your own
540 // client, so we must keep all clients in this superset
541 effects = (unsigned)ent->fields.server->effects;
543 // we can omit invisible entities with no effects that are not clients
544 // LordHavoc: this could kill tags attached to an invisible entity, I
545 // just hope we never have to support that case
546 i = (int)ent->fields.server->modelindex;
547 modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
550 i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
551 glowsize = (unsigned char)bound(0, i, 255);
552 if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
553 flags |= RENDER_GLOWTRAIL;
555 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
556 light[0] = (unsigned short)bound(0, f, 65535);
557 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
558 light[1] = (unsigned short)bound(0, f, 65535);
559 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
560 light[2] = (unsigned short)bound(0, f, 65535);
561 f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
562 light[3] = (unsigned short)bound(0, f, 65535);
563 lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
564 lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
566 if (gamemode == GAME_TENEBRAE)
568 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
572 lightpflags |= PFLAGS_FULLDYNAMIC;
574 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
578 light[0] = (int)(0.2*256);
579 light[1] = (int)(1.0*256);
580 light[2] = (int)(0.2*256);
582 lightpflags |= PFLAGS_FULLDYNAMIC;
586 specialvisibilityradius = 0;
587 if (lightpflags & PFLAGS_FULLDYNAMIC)
588 specialvisibilityradius = max(specialvisibilityradius, light[3]);
590 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
591 if (flags & RENDER_GLOWTRAIL)
592 specialvisibilityradius = max(specialvisibilityradius, 100);
593 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
595 if (effects & EF_BRIGHTFIELD)
596 specialvisibilityradius = max(specialvisibilityradius, 80);
597 if (effects & EF_MUZZLEFLASH)
598 specialvisibilityradius = max(specialvisibilityradius, 100);
599 if (effects & EF_BRIGHTLIGHT)
600 specialvisibilityradius = max(specialvisibilityradius, 400);
601 if (effects & EF_DIMLIGHT)
602 specialvisibilityradius = max(specialvisibilityradius, 200);
603 if (effects & EF_RED)
604 specialvisibilityradius = max(specialvisibilityradius, 200);
605 if (effects & EF_BLUE)
606 specialvisibilityradius = max(specialvisibilityradius, 200);
607 if (effects & EF_FLAME)
608 specialvisibilityradius = max(specialvisibilityradius, 250);
609 if (effects & EF_STARDUST)
610 specialvisibilityradius = max(specialvisibilityradius, 100);
613 // early culling checks
614 // (final culling is done by SV_MarkWriteEntityStateToClient)
615 customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_customizeentityforclient)->function;
616 if (!customizeentityforclient)
618 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
620 // this 2 billion unit check is actually to detect NAN origins
621 // (we really don't want to send those)
622 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
630 VectorCopy(ent->fields.server->origin, cs->origin);
631 VectorCopy(ent->fields.server->angles, cs->angles);
633 cs->effects = effects;
634 cs->colormap = (unsigned)ent->fields.server->colormap;
635 cs->modelindex = modelindex;
636 cs->skin = (unsigned)ent->fields.server->skin;
637 cs->frame = (unsigned)ent->fields.server->frame;
638 cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict;
639 cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)->edict;
640 cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict;
641 cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict;
642 cs->customizeentityforclient = customizeentityforclient;
643 cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict;
644 cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
645 cs->glowsize = glowsize;
647 // don't need to init cs->colormod because the defaultstate did that for us
648 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
649 val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod);
650 if (val->vector[0] || val->vector[1] || val->vector[2])
652 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
653 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
654 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
657 cs->modelindex = modelindex;
660 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f);
664 cs->alpha = (unsigned char)bound(0, i, 255);
667 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float);
671 cs->alpha = (unsigned char)bound(0, i, 255);
675 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f);
679 cs->scale = (unsigned char)bound(0, i, 255);
683 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_color)->_float);
685 cs->glowcolor = (int)f;
687 if (PRVM_GETEDICTFIELDVALUE(ent, eval_fullbright)->_float)
688 cs->effects |= EF_FULLBRIGHT;
690 if (ent->fields.server->movetype == MOVETYPE_STEP)
691 cs->flags |= RENDER_STEP;
692 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)
693 cs->flags |= RENDER_LOWPRECISION;
694 if (ent->fields.server->colormap >= 1024)
695 cs->flags |= RENDER_COLORMAPPED;
696 if (cs->viewmodelforclient)
697 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
699 cs->light[0] = light[0];
700 cs->light[1] = light[1];
701 cs->light[2] = light[2];
702 cs->light[3] = light[3];
703 cs->lightstyle = lightstyle;
704 cs->lightpflags = lightpflags;
706 cs->specialvisibilityradius = specialvisibilityradius;
708 // calculate the visible box of this entity (don't use the physics box
709 // as that is often smaller than a model, and would not count
710 // specialvisibilityradius)
711 if ((model = sv.models[modelindex]))
713 float scale = cs->scale * (1.0f / 16.0f);
714 if (cs->angles[0] || cs->angles[2]) // pitch and roll
716 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
717 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
719 else if (cs->angles[1])
721 VectorMA(cs->origin, scale, model->yawmins, cullmins);
722 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
726 VectorMA(cs->origin, scale, model->normalmins, cullmins);
727 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
732 // if there is no model (or it could not be loaded), use the physics box
733 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
734 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
736 if (specialvisibilityradius)
738 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
739 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
740 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
741 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
742 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
743 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
745 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
747 VectorCopy(cullmins, ent->priv.server->cullmins);
748 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
749 ent->priv.server->pvs_numclusters = -1;
750 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
752 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
753 if (i <= MAX_ENTITYCLUSTERS)
754 ent->priv.server->pvs_numclusters = i;
761 void SV_PrepareEntitiesForSending(void)
765 // send all entities that touch the pvs
767 sendentitiesindex[0] = NULL;
768 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
769 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
771 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
773 sendentitiesindex[e] = sendentities + numsendentities;
779 static int sententitiesmark = 0;
780 static int sententities[MAX_EDICTS];
781 static int sententitiesconsideration[MAX_EDICTS];
782 static int sv_writeentitiestoclient_culled_pvs;
783 static int sv_writeentitiestoclient_culled_trace;
784 static int sv_writeentitiestoclient_visibleentities;
785 static int sv_writeentitiestoclient_totalentities;
786 //static entity_frame_t sv_writeentitiestoclient_entityframe;
787 static int sv_writeentitiestoclient_clentnum;
788 static vec3_t sv_writeentitiestoclient_testeye;
789 static client_t *sv_writeentitiestoclient_client;
791 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
798 if (sententitiesconsideration[s->number] == sententitiesmark)
800 sententitiesconsideration[s->number] = sententitiesmark;
801 sv_writeentitiestoclient_totalentities++;
803 if (s->customizeentityforclient)
805 prog->globals.server->self = s->number;
806 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
807 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
808 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
812 // never reject player
813 if (s->number != sv_writeentitiestoclient_clentnum)
815 // check various rejection conditions
816 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
818 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
820 if (s->effects & EF_NODRAW)
822 // LordHavoc: only send entities with a model or important effects
823 if (!s->modelindex && s->specialvisibilityradius == 0)
826 // viewmodels don't have visibility checking
827 if (s->viewmodelforclient)
829 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
832 else if (s->tagentity)
834 // tag attached entities simply check their parent
835 if (!sendentitiesindex[s->tagentity])
837 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
838 if (sententities[s->tagentity] != sententitiesmark)
841 // always send world submodels in newer protocols because they don't
842 // generate much traffic (in old protocols they hog bandwidth)
843 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)))
845 // entity has survived every check so far, check if visible
846 ed = PRVM_EDICT_NUM(s->number);
848 // if not touching a visible leaf
849 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
851 if (ed->priv.server->pvs_numclusters < 0)
853 // entity too big for clusters list
854 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
856 sv_writeentitiestoclient_culled_pvs++;
863 // check cached clusters list
864 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
865 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
867 if (i == ed->priv.server->pvs_numclusters)
869 sv_writeentitiestoclient_culled_pvs++;
875 // or not seen by random tracelines
876 if (sv_cullentities_trace.integer && !isbmodel)
878 // LordHavoc: test center first
879 testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
880 testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
881 testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
882 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
883 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
884 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
887 // LordHavoc: test random offsets, to maximize chance of detection
888 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
889 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
890 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
891 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
892 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
893 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
896 if (s->specialvisibilityradius)
898 // LordHavoc: test random offsets, to maximize chance of detection
899 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
900 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
901 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
902 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
903 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
904 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
908 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
910 sv_writeentitiestoclient_culled_trace++;
917 // this just marks it for sending
918 // FIXME: it would be more efficient to send here, but the entity
919 // compressor isn't that flexible
920 sv_writeentitiestoclient_visibleentities++;
921 sententities[s->number] = sententitiesmark;
924 entity_state_t sendstates[MAX_EDICTS];
925 extern int csqc_clent;
927 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
929 int i, numsendstates;
932 // if there isn't enough space to accomplish anything, skip it
933 if (msg->cursize + 25 > msg->maxsize)
936 sv_writeentitiestoclient_client = client;
938 sv_writeentitiestoclient_culled_pvs = 0;
939 sv_writeentitiestoclient_culled_trace = 0;
940 sv_writeentitiestoclient_visibleentities = 0;
941 sv_writeentitiestoclient_totalentities = 0;
943 // find the client's PVS
944 // the real place being tested from
945 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
946 sv_writeentitiestoclient_pvsbytes = 0;
947 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
948 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
950 csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
954 for (i = 0;i < numsendentities;i++)
955 SV_MarkWriteEntityStateToClient(sendentities + i);
958 for (i = 0;i < numsendentities;i++)
960 if (sententities[sendentities[i].number] == sententitiesmark)
962 s = &sendstates[numsendstates++];
963 *s = sendentities[i];
964 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
965 s->flags |= RENDER_EXTERIORMODEL;
969 if (sv_cullentities_stats.integer)
970 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);
972 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
974 if (client->entitydatabase5)
975 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
976 else if (client->entitydatabase4)
977 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
978 else if (client->entitydatabase)
979 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
981 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
990 void SV_CleanupEnts (void)
995 ent = PRVM_NEXT_EDICT(prog->edicts);
996 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
997 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
1002 SV_WriteClientdataToMessage
1006 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1010 prvm_edict_t *other;
1018 // send a damage message
1020 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
1022 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
1023 MSG_WriteByte (msg, svc_damage);
1024 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
1025 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
1026 for (i=0 ; i<3 ; i++)
1027 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
1029 ent->fields.server->dmg_take = 0;
1030 ent->fields.server->dmg_save = 0;
1034 // send the current viewpos offset from the view entity
1036 SV_SetIdealPitch (); // how much to look up / down ideally
1038 // a fixangle might get lost in a dropped packet. Oh well.
1039 if ( ent->fields.server->fixangle )
1041 MSG_WriteByte (msg, svc_setangle);
1042 for (i=0 ; i < 3 ; i++)
1043 MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
1044 ent->fields.server->fixangle = 0;
1047 // stuff the sigil bits into the high bits of items for sbar, or else
1049 val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
1050 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1051 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1053 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1055 VectorClear(punchvector);
1056 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
1057 VectorCopy(val->vector, punchvector);
1059 // cache weapon model name and index in client struct to save time
1060 // (this search can be almost 1% of cpu time!)
1061 s = PRVM_GetString(ent->fields.server->weaponmodel);
1062 if (strcmp(s, client->weaponmodel))
1064 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1065 client->weaponmodelindex = SV_ModelIndex(s, 1);
1069 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
1070 viewzoom = (int)(val->_float * 255.0f);
1076 if ((int)ent->fields.server->flags & FL_ONGROUND)
1077 bits |= SU_ONGROUND;
1078 if (ent->fields.server->waterlevel >= 2)
1080 if (ent->fields.server->idealpitch)
1081 bits |= SU_IDEALPITCH;
1083 for (i=0 ; i<3 ; i++)
1085 if (ent->fields.server->punchangle[i])
1086 bits |= (SU_PUNCH1<<i);
1087 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1089 bits |= (SU_PUNCHVEC1<<i);
1090 if (ent->fields.server->velocity[i])
1091 bits |= (SU_VELOCITY1<<i);
1094 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1095 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1096 stats[STAT_ITEMS] = items;
1097 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1098 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1099 stats[STAT_WEAPON] = client->weaponmodelindex;
1100 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1101 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1102 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1103 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1104 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1105 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1106 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1107 stats[STAT_VIEWZOOM] = viewzoom;
1108 // the QC bumps these itself by sending svc_'s, so we have to keep them
1109 // zero or they'll be corrected by the engine
1110 //stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1111 //stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1112 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1113 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1115 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)
1117 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1119 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1120 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1122 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1123 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1124 if (viewzoom != 255)
1125 bits |= SU_VIEWZOOM;
1130 if (bits >= 16777216)
1134 MSG_WriteByte (msg, svc_clientdata);
1135 MSG_WriteShort (msg, bits);
1136 if (bits & SU_EXTEND1)
1137 MSG_WriteByte(msg, bits >> 16);
1138 if (bits & SU_EXTEND2)
1139 MSG_WriteByte(msg, bits >> 24);
1141 if (bits & SU_VIEWHEIGHT)
1142 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1144 if (bits & SU_IDEALPITCH)
1145 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1147 for (i=0 ; i<3 ; i++)
1149 if (bits & (SU_PUNCH1<<i))
1151 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1152 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1154 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1156 if (bits & (SU_PUNCHVEC1<<i))
1158 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1159 MSG_WriteCoord16i(msg, punchvector[i]);
1161 MSG_WriteCoord32f(msg, punchvector[i]);
1163 if (bits & (SU_VELOCITY1<<i))
1165 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1166 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1168 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1172 if (bits & SU_ITEMS)
1173 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1175 if (sv.protocol == PROTOCOL_DARKPLACES5)
1177 if (bits & SU_WEAPONFRAME)
1178 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1179 if (bits & SU_ARMOR)
1180 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1181 if (bits & SU_WEAPON)
1182 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1183 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1184 MSG_WriteShort (msg, stats[STAT_AMMO]);
1185 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1186 MSG_WriteShort (msg, stats[STAT_NAILS]);
1187 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1188 MSG_WriteShort (msg, stats[STAT_CELLS]);
1189 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1190 if (bits & SU_VIEWZOOM)
1191 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1193 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)
1195 if (bits & SU_WEAPONFRAME)
1196 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1197 if (bits & SU_ARMOR)
1198 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1199 if (bits & SU_WEAPON)
1200 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1201 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1202 MSG_WriteByte (msg, stats[STAT_AMMO]);
1203 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1204 MSG_WriteByte (msg, stats[STAT_NAILS]);
1205 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1206 MSG_WriteByte (msg, stats[STAT_CELLS]);
1207 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1209 for (i = 0;i < 32;i++)
1210 if (stats[STAT_WEAPON] & (1<<i))
1212 MSG_WriteByte (msg, i);
1215 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1216 if (bits & SU_VIEWZOOM)
1218 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1219 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1221 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1227 =======================
1228 SV_SendClientDatagram
1229 =======================
1231 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1232 void SV_SendClientDatagram (client_t *client)
1234 int rate, maxrate, maxsize, maxsize2, downloadsize;
1236 int stats[MAX_CL_STATS];
1238 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1240 // for good singleplayer, send huge packets
1241 maxsize = sizeof(sv_sendclientdatagram_buf);
1242 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1244 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)
1246 // no rate limiting support on older protocols because dp protocols
1247 // 1-4 kick the client off if they overflow, and quake protocol shows
1248 // less than the full entity set if rate limited
1254 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1255 maxrate = max(NET_MINRATE, sv_maxrate.integer);
1256 if (sv_maxrate.integer != maxrate)
1257 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1259 // this rate limiting does not understand sys_ticrate 0
1260 // (but no one should be running that on a server!)
1261 rate = bound(NET_MINRATE, client->rate, maxrate);
1262 rate = (int)(rate * sys_ticrate.value);
1263 maxsize = bound(100, rate, 1400);
1267 // while downloading, limit entity updates to half the packet
1268 // (any leftover space will be used for downloading)
1269 if (host_client->download_file)
1272 msg.data = sv_sendclientdatagram_buf;
1273 msg.maxsize = maxsize;
1276 if (host_client->spawned)
1278 MSG_WriteByte (&msg, svc_time);
1279 MSG_WriteFloat (&msg, sv.time);
1281 // add the client specific data to the datagram
1282 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1283 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1284 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1286 // expand packet size to allow effects to go over the rate limit
1287 // (dropping them is FAR too ugly)
1288 msg.maxsize = maxsize2;
1290 // copy the server datagram if there is space
1291 // FIXME: put in delayed queue of effects to send
1292 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1293 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1295 else if (realtime > client->keepalivetime)
1297 // the player isn't totally in the game yet
1298 // send small keepalive messages if too much time has passed
1299 msg.maxsize = maxsize2;
1300 client->keepalivetime = realtime + 5;
1301 MSG_WriteChar (&msg, svc_nop);
1304 msg.maxsize = maxsize2;
1306 // if a download is active, see if there is room to fit some download data
1308 downloadsize = maxsize * 2 - msg.cursize - 7;
1309 if (host_client->download_file && host_client->download_started && downloadsize > 0)
1311 fs_offset_t downloadstart;
1312 unsigned char data[1400];
1313 downloadstart = FS_Tell(host_client->download_file);
1314 downloadsize = min(downloadsize, (int)sizeof(data));
1315 downloadsize = FS_Read(host_client->download_file, data, downloadsize);
1316 // note this sends empty messages if at the end of the file, which is
1317 // necessary to keep the packet loss logic working
1318 // (the last blocks may be lost and need to be re-sent, and that will
1319 // only occur if the client acks the empty end messages, revealing
1320 // a gap in the download progress, causing the last blocks to be
1322 MSG_WriteChar (&msg, svc_downloaddata);
1323 MSG_WriteLong (&msg, downloadstart);
1324 MSG_WriteShort (&msg, downloadsize);
1325 if (downloadsize > 0)
1326 SZ_Write (&msg, data, downloadsize);
1329 // send the datagram
1330 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1334 =======================
1335 SV_UpdateToReliableMessages
1336 =======================
1338 void SV_UpdateToReliableMessages (void)
1347 // check for changes to be sent over the reliable streams
1348 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1350 // update the host_client fields we care about according to the entity fields
1351 host_client->edict = PRVM_EDICT_NUM(i+1);
1354 name = PRVM_GetString(host_client->edict->fields.server->netname);
1357 // always point the string back at host_client->name to keep it safe
1358 strlcpy (host_client->name, name, sizeof (host_client->name));
1359 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1360 if (strcmp(host_client->old_name, host_client->name))
1362 if (host_client->spawned)
1363 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1364 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1365 // send notification to all clients
1366 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1367 MSG_WriteByte (&sv.reliable_datagram, i);
1368 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1371 // DP_SV_CLIENTCOLORS
1372 // this is always found (since it's added by the progs loader)
1373 if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1374 host_client->colors = (int)val->_float;
1375 if (host_client->old_colors != host_client->colors)
1377 host_client->old_colors = host_client->colors;
1378 // send notification to all clients
1379 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1380 MSG_WriteByte (&sv.reliable_datagram, i);
1381 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1384 // NEXUIZ_PLAYERMODEL
1385 if( eval_playermodel ) {
1386 model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string);
1389 // always point the string back at host_client->name to keep it safe
1390 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1391 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1394 // NEXUIZ_PLAYERSKIN
1395 if( eval_playerskin ) {
1396 skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string);
1399 // always point the string back at host_client->name to keep it safe
1400 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1401 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1405 host_client->frags = (int)host_client->edict->fields.server->frags;
1406 if (host_client->old_frags != host_client->frags)
1408 host_client->old_frags = host_client->frags;
1409 // send notification to all clients
1410 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1411 MSG_WriteByte (&sv.reliable_datagram, i);
1412 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1416 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1417 if (client->netconnection)
1418 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1420 SZ_Clear (&sv.reliable_datagram);
1425 =======================
1426 SV_SendClientMessages
1427 =======================
1429 void SV_SendClientMessages (void)
1431 int i, prepared = false;
1433 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1434 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1436 // update frags, names, etc
1437 SV_UpdateToReliableMessages();
1439 // build individual updates
1440 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1442 if (!host_client->active)
1444 if (!host_client->netconnection)
1447 if (host_client->netconnection->message.overflowed)
1449 SV_DropClient (true); // if the message couldn't send, kick off
1456 // only prepare entities once per frame
1457 SV_PrepareEntitiesForSending();
1459 SV_SendClientDatagram (host_client);
1462 // clear muzzle flashes
1466 void SV_StartDownload_f(void)
1468 if (host_client->download_file)
1469 host_client->download_started = true;
1472 void SV_Download_f(void)
1474 const char *whichpack, *whichpack2, *extension;
1476 if (Cmd_Argc() != 2)
1478 SV_ClientPrintf("usage: download <filename>\n");
1482 if (FS_CheckNastyPath(Cmd_Argv(1), false))
1484 SV_ClientPrintf("Download rejected: nasty filename \"%s\"\n", Cmd_Argv(1));
1488 if (host_client->download_file)
1490 // at this point we'll assume the previous download should be aborted
1491 Con_DPrintf("Download of %s aborted by %s starting a new download\n", host_client->download_name, host_client->name);
1492 Host_ClientCommands("\nstopdownload\n");
1494 // close the file and reset variables
1495 FS_Close(host_client->download_file);
1496 host_client->download_file = NULL;
1497 host_client->download_name[0] = 0;
1498 host_client->download_expectedposition = 0;
1499 host_client->download_started = false;
1502 if (!sv_allowdownloads.integer)
1504 SV_ClientPrintf("Downloads are disabled on this server\n");
1505 Host_ClientCommands("\nstopdownload\n");
1509 strlcpy(host_client->download_name, Cmd_Argv(1), sizeof(host_client->download_name));
1511 // host_client is asking to download a specified file
1512 if (developer.integer >= 100)
1513 Con_Printf("Download request for %s by %s\n", host_client->download_name, host_client->name);
1515 if (!FS_FileExists(host_client->download_name))
1517 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);
1518 Host_ClientCommands("\nstopdownload\n");
1522 // check if the user is trying to download part of registered Quake(r)
1523 whichpack = FS_WhichPack(host_client->download_name);
1524 whichpack2 = FS_WhichPack("gfx/pop.lmp");
1525 if ((whichpack && whichpack2 && !strcasecmp(whichpack, whichpack2)) || FS_IsRegisteredQuakePack(host_client->download_name))
1527 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);
1528 Host_ClientCommands("\nstopdownload\n");
1532 // check if the server has forbidden archive downloads entirely
1533 if (!sv_allowdownloads_inarchive.integer)
1535 whichpack = FS_WhichPack(host_client->download_name);
1538 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);
1539 Host_ClientCommands("\nstopdownload\n");
1544 if (!sv_allowdownloads_archive.integer)
1546 extension = FS_FileExtension(host_client->download_name);
1547 if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
1549 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);
1550 Host_ClientCommands("\nstopdownload\n");
1555 host_client->download_file = FS_Open(host_client->download_name, "rb", true, false);
1556 if (!host_client->download_file)
1558 SV_ClientPrintf("Download rejected: server could not open the file \"%s\"\n", host_client->download_name);
1559 Host_ClientCommands("\nstopdownload\n");
1563 if (FS_FileSize(host_client->download_file) > 1<<30)
1565 SV_ClientPrintf("Download rejected: file \"%s\" is very large\n", host_client->download_name);
1566 Host_ClientCommands("\nstopdownload\n");
1567 FS_Close(host_client->download_file);
1568 host_client->download_file = NULL;
1572 Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
1574 Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name);
1576 host_client->download_expectedposition = 0;
1577 host_client->download_started = false;
1579 // the rest of the download process is handled in SV_SendClientDatagram
1580 // and other code dealing with svc_downloaddata and clc_ackdownloaddata
1582 // no svc_downloaddata messages will be sent until sv_startdownload is
1583 // sent by the client
1587 ==============================================================================
1591 ==============================================================================
1600 int SV_ModelIndex(const char *s, int precachemode)
1602 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1603 char filename[MAX_QPATH];
1607 //if (precachemode == 2)
1609 strlcpy(filename, s, sizeof(filename));
1610 for (i = 2;i < limit;i++)
1612 if (!sv.model_precache[i][0])
1616 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))
1618 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1621 if (precachemode == 1)
1622 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1623 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1624 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1625 if (sv.state != ss_loading)
1627 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1628 MSG_WriteShort(&sv.reliable_datagram, i);
1629 MSG_WriteString(&sv.reliable_datagram, filename);
1633 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1636 if (!strcmp(sv.model_precache[i], filename))
1639 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1649 int SV_SoundIndex(const char *s, int precachemode)
1651 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1652 char filename[MAX_QPATH];
1656 //if (precachemode == 2)
1658 strlcpy(filename, s, sizeof(filename));
1659 for (i = 1;i < limit;i++)
1661 if (!sv.sound_precache[i][0])
1665 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))
1667 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1670 if (precachemode == 1)
1671 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1672 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1673 if (sv.state != ss_loading)
1675 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1676 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1677 MSG_WriteString(&sv.reliable_datagram, filename);
1681 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1684 if (!strcmp(sv.sound_precache[i], filename))
1687 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1697 void SV_CreateBaseline (void)
1699 int i, entnum, large;
1700 prvm_edict_t *svent;
1702 // LordHavoc: clear *all* states (note just active ones)
1703 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1705 // get the current server version
1706 svent = PRVM_EDICT_NUM(entnum);
1708 // LordHavoc: always clear state values, whether the entity is in use or not
1709 svent->priv.server->baseline = defaultstate;
1711 if (svent->priv.server->free)
1713 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1716 // create entity baseline
1717 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1718 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1719 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1720 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1721 if (entnum > 0 && entnum <= svs.maxclients)
1723 svent->priv.server->baseline.colormap = entnum;
1724 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1728 svent->priv.server->baseline.colormap = 0;
1729 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1733 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1736 // add to the message
1738 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1740 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1741 MSG_WriteShort (&sv.signon, entnum);
1745 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1746 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1750 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1751 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1753 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1754 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1755 for (i=0 ; i<3 ; i++)
1757 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1758 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1768 Grabs the current state of each client for saving across the
1769 transition to another level
1772 void SV_SaveSpawnparms (void)
1776 svs.serverflags = (int)prog->globals.server->serverflags;
1778 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1780 if (!host_client->active)
1783 // call the progs to get default spawn parms for the new client
1784 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1785 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1786 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1787 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1791 void SV_IncreaseEdicts(void)
1795 int oldmax_edicts = prog->max_edicts;
1796 void *oldedictsengineprivate = prog->edictprivate;
1797 void *oldedictsfields = prog->edictsfields;
1798 void *oldmoved_edicts = sv.moved_edicts;
1800 if (prog->max_edicts >= MAX_EDICTS)
1803 // links don't survive the transition, so unlink everything
1804 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1806 if (!ent->priv.server->free)
1807 SV_UnlinkEdict(prog->edicts + i);
1808 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1812 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
1813 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1814 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
1815 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1817 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
1818 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
1820 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1822 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1823 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1824 // link every entity except world
1825 if (!ent->priv.server->free)
1826 SV_LinkEdict(ent, false);
1829 PR_Free(oldedictsengineprivate);
1830 PR_Free(oldedictsfields);
1831 PR_Free(oldmoved_edicts);
1838 This is called at the start of each level
1841 extern float scr_centertime_off;
1843 void SV_SpawnServer (const char *server)
1848 model_t *worldmodel;
1849 char modelname[sizeof(sv.modelname)];
1851 Con_DPrintf("SpawnServer: %s\n", server);
1853 if (cls.state != ca_dedicated)
1854 SCR_BeginLoadingPlaque();
1856 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
1857 worldmodel = Mod_ForName(modelname, false, true, true);
1858 if (!worldmodel || !worldmodel->TraceBox)
1860 Con_Printf("Couldn't load map %s\n", modelname);
1864 // let's not have any servers with no name
1865 if (hostname.string[0] == 0)
1866 Cvar_Set ("hostname", "UNNAMED");
1867 scr_centertime_off = 0;
1869 svs.changelevel_issued = false; // now safe to issue another
1871 // make the map a required file for clients
1872 Curl_ClearRequirements();
1873 Curl_RequireFile(modelname);
1876 // tell all connected clients that we are going to a new level
1881 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1883 if (client->netconnection)
1885 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
1886 MSG_WriteString(&client->netconnection->message, "reconnect\n");
1893 NetConn_OpenServerPorts(true);
1897 // make cvars consistant
1900 Cvar_SetValue ("deathmatch", 0);
1901 // LordHavoc: it can be useful to have skills outside the range 0-3...
1902 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
1903 //Cvar_SetValue ("skill", (float)current_skill);
1904 current_skill = (int)(skill.value + 0.5);
1907 // set up the new server
1909 memset (&sv, 0, sizeof(sv));
1910 // if running a local client, make sure it doesn't try to access the last
1911 // level's data which is no longer valiud
1914 if(*sv_random_seed.string)
1916 srand(sv_random_seed.integer);
1917 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);
1924 strlcpy (sv.name, server, sizeof (sv.name));
1926 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
1927 if (sv.protocol == PROTOCOL_UNKNOWN)
1930 Protocol_Names(buffer, sizeof(buffer));
1931 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
1932 sv.protocol = PROTOCOL_QUAKE;
1937 // load progs to get entity field count
1938 //PR_LoadProgs ( sv_progs.string );
1940 // allocate server memory
1941 /*// start out with just enough room for clients and a reasonable estimate of entities
1942 prog->max_edicts = max(svs.maxclients + 1, 512);
1943 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
1945 // prvm_edict_t structures (hidden from progs)
1946 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
1947 // engine private structures (hidden from progs)
1948 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1949 // progs fields, often accessed by server
1950 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
1951 // used by PushMove to move back pushed entities
1952 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1953 /*for (i = 0;i < prog->max_edicts;i++)
1955 ent = prog->edicts + i;
1956 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1957 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1960 // reset client csqc entity versions right away.
1961 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1962 EntityFrameCSQC_InitClientVersions(i, true);
1964 sv.datagram.maxsize = sizeof(sv.datagram_buf);
1965 sv.datagram.cursize = 0;
1966 sv.datagram.data = sv.datagram_buf;
1968 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
1969 sv.reliable_datagram.cursize = 0;
1970 sv.reliable_datagram.data = sv.reliable_datagram_buf;
1972 sv.signon.maxsize = sizeof(sv.signon_buf);
1973 sv.signon.cursize = 0;
1974 sv.signon.data = sv.signon_buf;
1976 // leave slots at start for clients only
1977 //prog->num_edicts = svs.maxclients+1;
1979 sv.state = ss_loading;
1980 prog->allowworldwrites = true;
1983 *prog->time = sv.time = 1.0;
1986 worldmodel->used = true;
1988 strlcpy (sv.name, server, sizeof (sv.name));
1989 strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
1990 sv.worldmodel = worldmodel;
1991 sv.models[1] = sv.worldmodel;
1994 // clear world interaction links
1998 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
2000 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
2001 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
2002 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
2004 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
2005 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
2009 // load the rest of the entities
2011 // AK possible hack since num_edicts is still 0
2012 ent = PRVM_EDICT_NUM(0);
2013 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
2014 ent->priv.server->free = false;
2015 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
2016 ent->fields.server->modelindex = 1; // world model
2017 ent->fields.server->solid = SOLID_BSP;
2018 ent->fields.server->movetype = MOVETYPE_PUSH;
2019 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->mins);
2020 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->maxs);
2021 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->absmin);
2022 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->absmax);
2025 prog->globals.server->coop = coop.integer;
2027 prog->globals.server->deathmatch = deathmatch.integer;
2029 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
2031 // serverflags are for cross level information (sigils)
2032 prog->globals.server->serverflags = svs.serverflags;
2034 // we need to reset the spawned flag on all connected clients here so that
2035 // their thinks don't run during startup (before PutClientInServer)
2036 // we also need to set up the client entities now
2037 // and we need to set the ->edict pointers to point into the progs edicts
2038 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2040 host_client->spawned = false;
2041 host_client->edict = PRVM_EDICT_NUM(i + 1);
2042 PRVM_ED_ClearEdict(host_client->edict);
2045 // load replacement entity file if found
2046 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
2048 Con_Printf("Loaded maps/%s.ent\n", sv.name);
2049 PRVM_ED_LoadFromFile (entities);
2053 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
2056 // LordHavoc: clear world angles (to fix e3m3.bsp)
2057 VectorClear(prog->edicts->fields.server->angles);
2059 // all setup is completed, any further precache statements are errors
2060 sv.state = ss_active;
2061 prog->allowworldwrites = false;
2063 // run two frames to allow everything to settle
2064 for (i = 0;i < 2;i++)
2072 // create a baseline for more efficient communications
2073 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
2074 SV_CreateBaseline ();
2076 // send serverinfo to all connected clients, and set up botclients coming back from a level change
2077 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2079 if (!host_client->active)
2081 if (host_client->netconnection)
2082 SV_SendServerinfo(host_client);
2086 // if client is a botclient coming from a level change, we need to
2087 // set up client info that normally requires networking
2089 // copy spawn parms out of the client_t
2090 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
2091 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
2093 // call the spawn function
2094 host_client->clientconnectcalled = true;
2095 prog->globals.server->time = sv.time;
2096 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2097 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
2098 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
2099 host_client->spawned = true;
2103 Con_DPrint("Server spawned.\n");
2104 NetConn_Heartbeat (2);
2109 /////////////////////////////////////////////////////
2112 void SV_VM_CB_BeginIncreaseEdicts(void)
2117 PRVM_Free( sv.moved_edicts );
2118 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
2120 // links don't survive the transition, so unlink everything
2121 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2123 if (!ent->priv.server->free)
2124 SV_UnlinkEdict(prog->edicts + i);
2125 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
2130 void SV_VM_CB_EndIncreaseEdicts(void)
2135 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2137 // link every entity except world
2138 if (!ent->priv.server->free)
2139 SV_LinkEdict(ent, false);
2143 void SV_VM_CB_InitEdict(prvm_edict_t *e)
2145 // LordHavoc: for consistency set these here
2146 int num = PRVM_NUM_FOR_EDICT(e) - 1;
2148 e->priv.server->move = false; // don't move on first frame
2150 if (num >= 0 && num < svs.maxclients)
2153 // set colormap and team on newly created player entity
2154 e->fields.server->colormap = num + 1;
2155 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
2156 // set netname/clientcolors back to client values so that
2157 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
2159 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
2160 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
2161 val->_float = svs.clients[num].colors;
2162 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
2163 if( eval_playermodel )
2164 PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
2165 if( eval_playerskin )
2166 PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
2170 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
2172 SV_UnlinkEdict (ed); // unlink from world bsp
2174 ed->fields.server->model = 0;
2175 ed->fields.server->takedamage = 0;
2176 ed->fields.server->modelindex = 0;
2177 ed->fields.server->colormap = 0;
2178 ed->fields.server->skin = 0;
2179 ed->fields.server->frame = 0;
2180 VectorClear(ed->fields.server->origin);
2181 VectorClear(ed->fields.server->angles);
2182 ed->fields.server->nextthink = -1;
2183 ed->fields.server->solid = 0;
2186 void SV_VM_CB_CountEdicts(void)
2190 int active, models, solid, step;
2192 active = models = solid = step = 0;
2193 for (i=0 ; i<prog->num_edicts ; i++)
2195 ent = PRVM_EDICT_NUM(i);
2196 if (ent->priv.server->free)
2199 if (ent->fields.server->solid)
2201 if (ent->fields.server->model)
2203 if (ent->fields.server->movetype == MOVETYPE_STEP)
2207 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2208 Con_Printf("active :%3i\n", active);
2209 Con_Printf("view :%3i\n", models);
2210 Con_Printf("touch :%3i\n", solid);
2211 Con_Printf("step :%3i\n", step);
2214 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2216 // remove things from different skill levels or deathmatch
2217 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2219 if (deathmatch.integer)
2221 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2226 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2227 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2228 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2236 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)"};
2237 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2238 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2239 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2240 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2241 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2242 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2243 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2244 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2245 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2246 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2247 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2248 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2249 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2250 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2251 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2252 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2253 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2254 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2255 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2256 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2257 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2258 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2259 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2260 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2261 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2262 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2263 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2264 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2265 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2266 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2267 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2268 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2270 void SV_VM_Init(void)
2272 Cvar_RegisterVariable (&pr_checkextension);
2273 Cvar_RegisterVariable (&nomonsters);
2274 Cvar_RegisterVariable (&gamecfg);
2275 Cvar_RegisterVariable (&scratch1);
2276 Cvar_RegisterVariable (&scratch2);
2277 Cvar_RegisterVariable (&scratch3);
2278 Cvar_RegisterVariable (&scratch4);
2279 Cvar_RegisterVariable (&savedgamecfg);
2280 Cvar_RegisterVariable (&saved1);
2281 Cvar_RegisterVariable (&saved2);
2282 Cvar_RegisterVariable (&saved3);
2283 Cvar_RegisterVariable (&saved4);
2284 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2285 if (gamemode == GAME_NEHAHRA)
2287 Cvar_RegisterVariable (&nehx00);
2288 Cvar_RegisterVariable (&nehx01);
2289 Cvar_RegisterVariable (&nehx02);
2290 Cvar_RegisterVariable (&nehx03);
2291 Cvar_RegisterVariable (&nehx04);
2292 Cvar_RegisterVariable (&nehx05);
2293 Cvar_RegisterVariable (&nehx06);
2294 Cvar_RegisterVariable (&nehx07);
2295 Cvar_RegisterVariable (&nehx08);
2296 Cvar_RegisterVariable (&nehx09);
2297 Cvar_RegisterVariable (&nehx10);
2298 Cvar_RegisterVariable (&nehx11);
2299 Cvar_RegisterVariable (&nehx12);
2300 Cvar_RegisterVariable (&nehx13);
2301 Cvar_RegisterVariable (&nehx14);
2302 Cvar_RegisterVariable (&nehx15);
2303 Cvar_RegisterVariable (&nehx16);
2304 Cvar_RegisterVariable (&nehx17);
2305 Cvar_RegisterVariable (&nehx18);
2306 Cvar_RegisterVariable (&nehx19);
2308 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2311 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
2328 int eval_buttonchat;
2330 int eval_glow_trail;
2331 int eval_glow_color;
2335 int eval_renderamt; // HalfLife support
2336 int eval_rendermode; // HalfLife support
2337 int eval_fullbright;
2338 int eval_ammo_shells1;
2339 int eval_ammo_nails1;
2340 int eval_ammo_lava_nails;
2341 int eval_ammo_rockets1;
2342 int eval_ammo_multi_rockets;
2343 int eval_ammo_cells1;
2344 int eval_ammo_plasma;
2345 int eval_idealpitch;
2346 int eval_pitch_speed;
2347 int eval_viewmodelforclient;
2348 int eval_nodrawtoclient;
2349 int eval_exteriormodeltoclient;
2350 int eval_drawonlytoclient;
2354 int eval_punchvector;
2356 int eval_clientcolors;
2357 int eval_tag_entity;
2363 int eval_cursor_active;
2364 int eval_cursor_screen;
2365 int eval_cursor_trace_start;
2366 int eval_cursor_trace_endpos;
2367 int eval_cursor_trace_ent;
2369 int eval_playermodel;
2370 int eval_playerskin;
2371 int eval_SendEntity;
2373 int eval_customizeentityforclient;
2374 int eval_dphitcontentsmask;
2375 // DRESK - Support for Entity Contents Transition Event
2376 int eval_contentstransition;
2378 int gval_trace_dpstartcontents;
2379 int gval_trace_dphitcontents;
2380 int gval_trace_dphitq3surfaceflags;
2381 int gval_trace_dphittexturename;
2383 mfunction_t *SV_PlayerPhysicsQC;
2384 mfunction_t *EndFrameQC;
2385 //KrimZon - SERVER COMMANDS IN QUAKEC
2386 mfunction_t *SV_ParseClientCommandQC;
2388 void SV_VM_FindEdictFieldOffsets(void)
2390 eval_gravity = PRVM_ED_FindFieldOffset("gravity");
2391 eval_button3 = PRVM_ED_FindFieldOffset("button3");
2392 eval_button4 = PRVM_ED_FindFieldOffset("button4");
2393 eval_button5 = PRVM_ED_FindFieldOffset("button5");
2394 eval_button6 = PRVM_ED_FindFieldOffset("button6");
2395 eval_button7 = PRVM_ED_FindFieldOffset("button7");
2396 eval_button8 = PRVM_ED_FindFieldOffset("button8");
2397 eval_button9 = PRVM_ED_FindFieldOffset("button9");
2398 eval_button10 = PRVM_ED_FindFieldOffset("button10");
2399 eval_button11 = PRVM_ED_FindFieldOffset("button11");
2400 eval_button12 = PRVM_ED_FindFieldOffset("button12");
2401 eval_button13 = PRVM_ED_FindFieldOffset("button13");
2402 eval_button14 = PRVM_ED_FindFieldOffset("button14");
2403 eval_button15 = PRVM_ED_FindFieldOffset("button15");
2404 eval_button16 = PRVM_ED_FindFieldOffset("button16");
2405 eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
2406 eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
2407 eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
2408 eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
2409 eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
2410 eval_items2 = PRVM_ED_FindFieldOffset("items2");
2411 eval_scale = PRVM_ED_FindFieldOffset("scale");
2412 eval_alpha = PRVM_ED_FindFieldOffset("alpha");
2413 eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
2414 eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
2415 eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
2416 eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
2417 eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
2418 eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
2419 eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
2420 eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
2421 eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
2422 eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
2423 eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
2424 eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
2425 eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
2426 eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
2427 eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
2428 eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
2429 eval_ping = PRVM_ED_FindFieldOffset("ping");
2430 eval_movement = PRVM_ED_FindFieldOffset("movement");
2431 eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
2432 eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
2433 eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
2434 eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
2435 eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
2436 eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
2437 eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
2438 eval_color = PRVM_ED_FindFieldOffset("color");
2439 eval_style = PRVM_ED_FindFieldOffset("style");
2440 eval_pflags = PRVM_ED_FindFieldOffset("pflags");
2441 eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
2442 eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
2443 eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
2444 eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
2445 eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
2446 eval_colormod = PRVM_ED_FindFieldOffset("colormod");
2447 eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
2448 eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
2449 eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
2450 eval_Version = PRVM_ED_FindFieldOffset("Version");
2451 eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
2452 eval_dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
2453 // DRESK - Support for Entity Contents Transition Event
2454 eval_contentstransition = PRVM_ED_FindFieldOffset("contentstransition");
2456 // LordHavoc: allowing QuakeC to override the player movement code
2457 SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
2458 // LordHavoc: support for endframe
2459 EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
2460 //KrimZon - SERVER COMMANDS IN QUAKEC
2461 SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
2462 gval_trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
2463 gval_trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
2464 gval_trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
2465 gval_trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
2468 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2470 prvm_required_field_t reqfields[] =
2472 {ev_entity, "cursor_trace_ent"},
2473 {ev_entity, "drawonlytoclient"},
2474 {ev_entity, "exteriormodeltoclient"},
2475 {ev_entity, "nodrawtoclient"},
2476 {ev_entity, "tag_entity"},
2477 {ev_entity, "viewmodelforclient"},
2478 {ev_float, "alpha"},
2479 {ev_float, "ammo_cells1"},
2480 {ev_float, "ammo_lava_nails"},
2481 {ev_float, "ammo_multi_rockets"},
2482 {ev_float, "ammo_nails1"},
2483 {ev_float, "ammo_plasma"},
2484 {ev_float, "ammo_rockets1"},
2485 {ev_float, "ammo_shells1"},
2486 {ev_float, "button3"},
2487 {ev_float, "button4"},
2488 {ev_float, "button5"},
2489 {ev_float, "button6"},
2490 {ev_float, "button7"},
2491 {ev_float, "button8"},
2492 {ev_float, "button9"},
2493 {ev_float, "button10"},
2494 {ev_float, "button11"},
2495 {ev_float, "button12"},
2496 {ev_float, "button13"},
2497 {ev_float, "button14"},
2498 {ev_float, "button15"},
2499 {ev_float, "button16"},
2500 {ev_float, "buttonchat"},
2501 {ev_float, "buttonuse"},
2502 {ev_float, "clientcolors"},
2503 {ev_float, "cursor_active"},
2504 {ev_float, "fullbright"},
2505 {ev_float, "glow_color"},
2506 {ev_float, "glow_size"},
2507 {ev_float, "glow_trail"},
2508 {ev_float, "gravity"},
2509 {ev_float, "idealpitch"},
2510 {ev_float, "items2"},
2511 {ev_float, "light_lev"},
2512 {ev_float, "pflags"},
2514 {ev_float, "pitch_speed"},
2515 {ev_float, "pmodel"},
2516 {ev_float, "renderamt"}, // HalfLife support
2517 {ev_float, "rendermode"}, // HalfLife support
2518 {ev_float, "scale"},
2519 {ev_float, "style"},
2520 {ev_float, "tag_index"},
2521 {ev_float, "Version"},
2522 {ev_float, "viewzoom"},
2523 {ev_vector, "color"},
2524 {ev_vector, "colormod"},
2525 {ev_vector, "cursor_screen"},
2526 {ev_vector, "cursor_trace_endpos"},
2527 {ev_vector, "cursor_trace_start"},
2528 {ev_vector, "movement"},
2529 {ev_vector, "punchvector"},
2530 {ev_string, "playermodel"},
2531 {ev_string, "playerskin"},
2532 {ev_function, "SendEntity"},
2533 {ev_function, "customizeentityforclient"},
2534 // DRESK - Support for Entity Contents Transition Event
2535 {ev_function, "contentstransition"},
2538 void SV_VM_Setup(void)
2540 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
2541 extern cvar_t csqc_progcrc;
2542 unsigned char *csprogsdata;
2543 fs_offset_t csprogsdatasize;
2545 PRVM_InitProg( PRVM_SERVERPROG );
2547 // allocate the mempools
2548 // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
2549 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2550 prog->builtins = vm_sv_builtins;
2551 prog->numbuiltins = vm_sv_numbuiltins;
2552 prog->headercrc = PROGHEADER_CRC;
2553 prog->max_edicts = 512;
2554 prog->limit_edicts = MAX_EDICTS;
2555 prog->reserved_edicts = svs.maxclients;
2556 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2557 prog->name = "server";
2558 prog->extensionstring = vm_sv_extensions;
2559 prog->loadintoworld = true;
2561 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2562 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2563 prog->init_edict = SV_VM_CB_InitEdict;
2564 prog->free_edict = SV_VM_CB_FreeEdict;
2565 prog->count_edicts = SV_VM_CB_CountEdicts;
2566 prog->load_edict = SV_VM_CB_LoadEdict;
2567 prog->init_cmd = VM_SV_Cmd_Init;
2568 prog->reset_cmd = VM_SV_Cmd_Reset;
2569 prog->error_cmd = Host_Error;
2571 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2572 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
2573 SV_VM_FindEdictFieldOffsets();
2575 VM_AutoSentStats_Clear();//[515]: csqc
2576 EntityFrameCSQC_ClearVersions();//[515]: csqc
2580 // 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
2581 sv.csqc_progcrc = -1;
2582 sv.csqc_progname[0] = 0;
2583 csprogsdata = FS_LoadFile(csqc_progname.string, tempmempool, true, &csprogsdatasize);
2586 strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
2587 sv.csqc_progcrc = CRC_Block(csprogsdata, csprogsdatasize);
2588 Mem_Free(csprogsdata);
2589 Con_DPrintf("server detected csqc progs file \"%s\" with crc %i\n", sv.csqc_progname, sv.csqc_progcrc);
2593 void SV_VM_Begin(void)
2596 PRVM_SetProg( PRVM_SERVERPROG );
2598 *prog->time = (float) sv.time;
2601 void SV_VM_End(void)