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"};
40 extern cvar_t sv_random_seed;
42 static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"}; // fast but loose
43 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
44 static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
45 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)"};
47 cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebouncedownslopes", "1", "prevents MOVETYPE_BOUNCE (grenades) from getting stuck when fired down a downward sloping surface"};
48 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"};
49 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)"};
50 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)"};
51 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"};
52 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"};
53 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"};
54 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"};
55 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"};
56 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"};
58 cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
60 // TODO: move these cvars here
61 extern cvar_t sv_clmovement_enable;
62 extern cvar_t sv_clmovement_minping;
63 extern cvar_t sv_clmovement_minping_disabletime;
64 extern cvar_t sv_clmovement_waitforinput;
69 mempool_t *sv_mempool = NULL;
71 //============================================================================
73 extern void SV_Phys_Init (void);
74 extern void SV_World_Init (void);
75 static void SV_SaveEntFile_f(void);
84 // init the csqc progs cvars, since they are updated/used by the server code
85 // TODO: fix this since this is a quick hack to make some of [515]'s broken code run ;) [9/13/2006 Black]
86 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
87 extern cvar_t csqc_progcrc;
88 Cvar_RegisterVariable (&csqc_progname);
89 Cvar_RegisterVariable (&csqc_progcrc);
91 Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
92 Cvar_RegisterVariable (&sv_maxvelocity);
93 Cvar_RegisterVariable (&sv_gravity);
94 Cvar_RegisterVariable (&sv_friction);
95 Cvar_RegisterVariable (&sv_waterfriction);
96 Cvar_RegisterVariable (&sv_edgefriction);
97 Cvar_RegisterVariable (&sv_stopspeed);
98 Cvar_RegisterVariable (&sv_maxspeed);
99 Cvar_RegisterVariable (&sv_maxairspeed);
100 Cvar_RegisterVariable (&sv_accelerate);
101 Cvar_RegisterVariable (&sv_airaccelerate);
102 Cvar_RegisterVariable (&sv_wateraccelerate);
103 Cvar_RegisterVariable (&sv_clmovement_enable);
104 Cvar_RegisterVariable (&sv_clmovement_minping);
105 Cvar_RegisterVariable (&sv_clmovement_minping_disabletime);
106 Cvar_RegisterVariable (&sv_clmovement_waitforinput);
107 Cvar_RegisterVariable (&sv_idealpitchscale);
108 Cvar_RegisterVariable (&sv_aim);
109 Cvar_RegisterVariable (&sv_nostep);
110 Cvar_RegisterVariable (&sv_cullentities_pvs);
111 Cvar_RegisterVariable (&sv_cullentities_trace);
112 Cvar_RegisterVariable (&sv_cullentities_stats);
113 Cvar_RegisterVariable (&sv_entpatch);
114 Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
115 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
116 Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
117 Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
118 Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
119 Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
120 Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
121 Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
122 Cvar_RegisterVariable (&sv_gameplayfix_qwplayerphysics);
123 Cvar_RegisterVariable (&sv_gameplayfix_upwardvelocityclearsongroundflag);
124 Cvar_RegisterVariable (&sv_protocolname);
125 Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
126 Cvar_RegisterVariable (&sv_maxrate);
127 Cvar_RegisterVariable (&sv_progs);
133 sv_mempool = Mem_AllocPool("server", 0, NULL);
136 static void SV_SaveEntFile_f(void)
138 char basename[MAX_QPATH];
139 if (!sv.active || !sv.worldmodel)
141 Con_Print("Not running a server\n");
144 FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
145 FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
150 =============================================================================
154 =============================================================================
161 Make sure the event gets sent to all clients
164 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
168 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
170 MSG_WriteByte (&sv.datagram, svc_particle);
171 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
172 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
173 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
174 for (i=0 ; i<3 ; i++)
175 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
176 MSG_WriteByte (&sv.datagram, count);
177 MSG_WriteByte (&sv.datagram, color);
184 Make sure the event gets sent to all clients
187 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
189 if (modelindex >= 256 || startframe >= 256)
191 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
193 MSG_WriteByte (&sv.datagram, svc_effect2);
194 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
195 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
196 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
197 MSG_WriteShort (&sv.datagram, modelindex);
198 MSG_WriteShort (&sv.datagram, startframe);
199 MSG_WriteByte (&sv.datagram, framecount);
200 MSG_WriteByte (&sv.datagram, framerate);
204 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
206 MSG_WriteByte (&sv.datagram, svc_effect);
207 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
208 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
209 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
210 MSG_WriteByte (&sv.datagram, modelindex);
211 MSG_WriteByte (&sv.datagram, startframe);
212 MSG_WriteByte (&sv.datagram, framecount);
213 MSG_WriteByte (&sv.datagram, framerate);
221 Each entity can have eight independant sound sources, like voice,
224 Channel 0 is an auto-allocate channel, the others override anything
225 already running on that entity/channel pair.
227 An attenuation of 0 will play full volume everywhere in the level.
228 Larger attenuations will drop off. (max 4 attenuation)
232 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
234 int sound_num, field_mask, i, ent;
236 if (volume < 0 || volume > 255)
238 Con_Printf ("SV_StartSound: volume = %i\n", volume);
242 if (attenuation < 0 || attenuation > 4)
244 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
248 if (channel < 0 || channel > 7)
250 Con_Printf ("SV_StartSound: channel = %i\n", channel);
254 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
257 // find precache number for sound
258 sound_num = SV_SoundIndex(sample, 1);
262 ent = PRVM_NUM_FOR_EDICT(entity);
265 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
266 field_mask |= SND_VOLUME;
267 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
268 field_mask |= SND_ATTENUATION;
270 field_mask |= SND_LARGEENTITY;
271 if (sound_num >= 256 || channel >= 8)
272 field_mask |= SND_LARGESOUND;
274 // directed messages go only to the entity they are targeted on
275 MSG_WriteByte (&sv.datagram, svc_sound);
276 MSG_WriteByte (&sv.datagram, field_mask);
277 if (field_mask & SND_VOLUME)
278 MSG_WriteByte (&sv.datagram, volume);
279 if (field_mask & SND_ATTENUATION)
280 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
281 if (field_mask & SND_LARGEENTITY)
283 MSG_WriteShort (&sv.datagram, ent);
284 MSG_WriteByte (&sv.datagram, channel);
287 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
288 if (field_mask & SND_LARGESOUND)
289 MSG_WriteShort (&sv.datagram, sound_num);
291 MSG_WriteByte (&sv.datagram, sound_num);
292 for (i = 0;i < 3;i++)
293 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
297 ==============================================================================
301 ==============================================================================
308 Sends the first message from the server to a connected client.
309 This will be sent on the initial connection and upon each server load.
312 void SV_SendServerinfo (client_t *client)
317 // we know that this client has a netconnection and thus is not a bot
319 // edicts get reallocated on level changes, so we need to update it here
320 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
322 // clear cached stuff that depends on the level
323 client->weaponmodel[0] = 0;
324 client->weaponmodelindex = 0;
326 // LordHavoc: clear entityframe tracking
327 client->latestframenum = 0;
329 if (client->entitydatabase)
330 EntityFrame_FreeDatabase(client->entitydatabase);
331 if (client->entitydatabase4)
332 EntityFrame4_FreeDatabase(client->entitydatabase4);
333 if (client->entitydatabase5)
334 EntityFrame5_FreeDatabase(client->entitydatabase5);
336 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
338 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
339 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
340 else if (sv.protocol == PROTOCOL_DARKPLACES4)
341 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
343 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
346 SZ_Clear (&client->netconnection->message);
347 MSG_WriteByte (&client->netconnection->message, svc_print);
348 dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
349 MSG_WriteString (&client->netconnection->message,message);
351 //[515]: init csprogs according to version of svprogs, check the crc, etc.
352 if (sv.csqc_progcrc >= 0)
355 Con_DPrintf("sending csqc info to client (\"%s\" with crc %i)\n", sv.csqc_progname, sv.csqc_progcrc);
356 //[515]: init stufftext string (it is sent before svc_serverinfo)
357 val = PRVM_GETGLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset("SV_InitCmd"));
358 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
359 MSG_WriteString (&client->netconnection->message, va("csqc_progname %s\n", sv.csqc_progname));
360 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
361 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", sv.csqc_progcrc));
364 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
365 MSG_WriteString (&client->netconnection->message, va("%s\n", PRVM_GetString(val->string)));
369 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
370 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
371 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
373 if (!coop.integer && deathmatch.integer)
374 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
376 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
378 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
380 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
381 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
382 MSG_WriteByte (&client->netconnection->message, 0);
384 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
385 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
386 MSG_WriteByte (&client->netconnection->message, 0);
389 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
390 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
391 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
394 MSG_WriteByte (&client->netconnection->message, svc_setview);
395 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
397 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
398 MSG_WriteByte (&client->netconnection->message, 1);
403 host_client = client;
404 Curl_SendRequirements();
408 client->spawned = false; // need prespawn, spawn, etc
415 Initializes a client_t for a new net connection. This will only be called
416 once for a player each game, not once for each level change.
419 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
423 float spawn_parms[NUM_SPAWN_PARMS];
425 client = svs.clients + clientnum;
427 if(netconnection)//[515]: bots don't play with csqc =)
428 EntityFrameCSQC_InitClientVersions(clientnum, false);
430 // set up the client_t
432 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
433 memset (client, 0, sizeof(*client));
434 client->active = true;
435 client->netconnection = netconnection;
437 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
439 strlcpy(client->name, "unconnected", sizeof(client->name));
440 strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
441 client->spawned = false;
442 client->edict = PRVM_EDICT_NUM(clientnum+1);
443 if (client->netconnection)
444 client->netconnection->message.allowoverflow = true; // we can catch it
445 // updated by receiving "rate" command from client
446 client->rate = NET_MINRATE;
447 // no limits for local player
448 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
449 client->rate = 1000000000;
450 client->connecttime = realtime;
453 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
456 // call the progs to get default spawn parms for the new client
457 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
458 prog->globals.server->self = 0;
459 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
460 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
461 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
463 // set up the entity for this client (including .colormap, .team, etc)
464 PRVM_ED_ClearEdict(client->edict);
467 // don't call SendServerinfo for a fresh botclient because its fields have
468 // not been set up by the qc yet
469 if (client->netconnection)
470 SV_SendServerinfo (client);
472 client->spawned = true;
477 ===============================================================================
481 ===============================================================================
490 void SV_ClearDatagram (void)
492 SZ_Clear (&sv.datagram);
496 =============================================================================
498 The PVS must include a small area around the client to allow head bobbing
499 or other small motion on the client side. Otherwise, a bob might cause an
500 entity that should be visible to not show up, especially when the bob
503 =============================================================================
506 int sv_writeentitiestoclient_pvsbytes;
507 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
509 static int numsendentities;
510 static entity_state_t sendentities[MAX_EDICTS];
511 static entity_state_t *sendentitiesindex[MAX_EDICTS];
513 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
516 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
517 unsigned int customizeentityforclient;
519 vec3_t cullmins, cullmaxs;
523 // EF_NODRAW prevents sending for any reason except for your own
524 // client, so we must keep all clients in this superset
525 effects = (unsigned)ent->fields.server->effects;
527 // we can omit invisible entities with no effects that are not clients
528 // LordHavoc: this could kill tags attached to an invisible entity, I
529 // just hope we never have to support that case
530 i = (int)ent->fields.server->modelindex;
531 modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
534 i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
535 glowsize = (unsigned char)bound(0, i, 255);
536 if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
537 flags |= RENDER_GLOWTRAIL;
539 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
540 light[0] = (unsigned short)bound(0, f, 65535);
541 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
542 light[1] = (unsigned short)bound(0, f, 65535);
543 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
544 light[2] = (unsigned short)bound(0, f, 65535);
545 f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
546 light[3] = (unsigned short)bound(0, f, 65535);
547 lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
548 lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
550 if (gamemode == GAME_TENEBRAE)
552 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
556 lightpflags |= PFLAGS_FULLDYNAMIC;
558 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
562 light[0] = (int)(0.2*256);
563 light[1] = (int)(1.0*256);
564 light[2] = (int)(0.2*256);
566 lightpflags |= PFLAGS_FULLDYNAMIC;
570 specialvisibilityradius = 0;
571 if (lightpflags & PFLAGS_FULLDYNAMIC)
572 specialvisibilityradius = max(specialvisibilityradius, light[3]);
574 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
575 if (flags & RENDER_GLOWTRAIL)
576 specialvisibilityradius = max(specialvisibilityradius, 100);
577 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
579 if (effects & EF_BRIGHTFIELD)
580 specialvisibilityradius = max(specialvisibilityradius, 80);
581 if (effects & EF_MUZZLEFLASH)
582 specialvisibilityradius = max(specialvisibilityradius, 100);
583 if (effects & EF_BRIGHTLIGHT)
584 specialvisibilityradius = max(specialvisibilityradius, 400);
585 if (effects & EF_DIMLIGHT)
586 specialvisibilityradius = max(specialvisibilityradius, 200);
587 if (effects & EF_RED)
588 specialvisibilityradius = max(specialvisibilityradius, 200);
589 if (effects & EF_BLUE)
590 specialvisibilityradius = max(specialvisibilityradius, 200);
591 if (effects & EF_FLAME)
592 specialvisibilityradius = max(specialvisibilityradius, 250);
593 if (effects & EF_STARDUST)
594 specialvisibilityradius = max(specialvisibilityradius, 100);
597 // early culling checks
598 // (final culling is done by SV_MarkWriteEntityStateToClient)
599 customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_customizeentityforclient)->function;
600 if (!customizeentityforclient)
602 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
604 // this 2 billion unit check is actually to detect NAN origins
605 // (we really don't want to send those)
606 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
614 VectorCopy(ent->fields.server->origin, cs->origin);
615 VectorCopy(ent->fields.server->angles, cs->angles);
617 cs->effects = effects;
618 cs->colormap = (unsigned)ent->fields.server->colormap;
619 cs->modelindex = modelindex;
620 cs->skin = (unsigned)ent->fields.server->skin;
621 cs->frame = (unsigned)ent->fields.server->frame;
622 cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict;
623 cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)->edict;
624 cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict;
625 cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict;
626 cs->customizeentityforclient = customizeentityforclient;
627 cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict;
628 cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
629 cs->glowsize = glowsize;
631 // don't need to init cs->colormod because the defaultstate did that for us
632 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
633 val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod);
634 if (val->vector[0] || val->vector[1] || val->vector[2])
636 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
637 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
638 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
641 cs->modelindex = modelindex;
644 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f);
648 cs->alpha = (unsigned char)bound(0, i, 255);
651 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float);
655 cs->alpha = (unsigned char)bound(0, i, 255);
659 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f);
663 cs->scale = (unsigned char)bound(0, i, 255);
667 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_color)->_float);
669 cs->glowcolor = (int)f;
671 if (PRVM_GETEDICTFIELDVALUE(ent, eval_fullbright)->_float)
672 cs->effects |= EF_FULLBRIGHT;
674 if (ent->fields.server->movetype == MOVETYPE_STEP)
675 cs->flags |= RENDER_STEP;
676 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)
677 cs->flags |= RENDER_LOWPRECISION;
678 if (ent->fields.server->colormap >= 1024)
679 cs->flags |= RENDER_COLORMAPPED;
680 if (cs->viewmodelforclient)
681 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
683 cs->light[0] = light[0];
684 cs->light[1] = light[1];
685 cs->light[2] = light[2];
686 cs->light[3] = light[3];
687 cs->lightstyle = lightstyle;
688 cs->lightpflags = lightpflags;
690 cs->specialvisibilityradius = specialvisibilityradius;
692 // calculate the visible box of this entity (don't use the physics box
693 // as that is often smaller than a model, and would not count
694 // specialvisibilityradius)
695 if ((model = sv.models[modelindex]))
697 float scale = cs->scale * (1.0f / 16.0f);
698 if (cs->angles[0] || cs->angles[2]) // pitch and roll
700 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
701 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
703 else if (cs->angles[1])
705 VectorMA(cs->origin, scale, model->yawmins, cullmins);
706 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
710 VectorMA(cs->origin, scale, model->normalmins, cullmins);
711 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
716 // if there is no model (or it could not be loaded), use the physics box
717 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
718 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
720 if (specialvisibilityradius)
722 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
723 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
724 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
725 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
726 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
727 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
729 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
731 VectorCopy(cullmins, ent->priv.server->cullmins);
732 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
733 ent->priv.server->pvs_numclusters = -1;
734 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
736 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
737 if (i <= MAX_ENTITYCLUSTERS)
738 ent->priv.server->pvs_numclusters = i;
745 void SV_PrepareEntitiesForSending(void)
749 // send all entities that touch the pvs
751 sendentitiesindex[0] = NULL;
752 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
753 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
755 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
757 sendentitiesindex[e] = sendentities + numsendentities;
763 static int sententitiesmark = 0;
764 static int sententities[MAX_EDICTS];
765 static int sententitiesconsideration[MAX_EDICTS];
766 static int sv_writeentitiestoclient_culled_pvs;
767 static int sv_writeentitiestoclient_culled_trace;
768 static int sv_writeentitiestoclient_visibleentities;
769 static int sv_writeentitiestoclient_totalentities;
770 //static entity_frame_t sv_writeentitiestoclient_entityframe;
771 static int sv_writeentitiestoclient_clentnum;
772 static vec3_t sv_writeentitiestoclient_testeye;
773 static client_t *sv_writeentitiestoclient_client;
775 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
782 if (sententitiesconsideration[s->number] == sententitiesmark)
784 sententitiesconsideration[s->number] = sententitiesmark;
785 sv_writeentitiestoclient_totalentities++;
787 if (s->customizeentityforclient)
789 prog->globals.server->self = s->number;
790 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
791 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
792 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
796 // never reject player
797 if (s->number != sv_writeentitiestoclient_clentnum)
799 // check various rejection conditions
800 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
802 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
804 if (s->effects & EF_NODRAW)
806 // LordHavoc: only send entities with a model or important effects
807 if (!s->modelindex && s->specialvisibilityradius == 0)
810 // viewmodels don't have visibility checking
811 if (s->viewmodelforclient)
813 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
816 else if (s->tagentity)
818 // tag attached entities simply check their parent
819 if (!sendentitiesindex[s->tagentity])
821 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
822 if (sententities[s->tagentity] != sententitiesmark)
825 // always send world submodels in newer protocols because they don't
826 // generate much traffic (in old protocols they hog bandwidth)
827 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)))
829 // entity has survived every check so far, check if visible
830 ed = PRVM_EDICT_NUM(s->number);
832 // if not touching a visible leaf
833 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
835 if (ed->priv.server->pvs_numclusters < 0)
837 // entity too big for clusters list
838 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
840 sv_writeentitiestoclient_culled_pvs++;
847 // check cached clusters list
848 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
849 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
851 if (i == ed->priv.server->pvs_numclusters)
853 sv_writeentitiestoclient_culled_pvs++;
859 // or not seen by random tracelines
860 if (sv_cullentities_trace.integer && !isbmodel)
862 // LordHavoc: test center first
863 testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
864 testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
865 testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
866 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
867 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
868 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
871 // LordHavoc: test random offsets, to maximize chance of detection
872 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
873 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
874 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
875 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
876 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
877 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
880 if (s->specialvisibilityradius)
882 // LordHavoc: test random offsets, to maximize chance of detection
883 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
884 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
885 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
886 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
887 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
888 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
892 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
894 sv_writeentitiestoclient_culled_trace++;
901 // this just marks it for sending
902 // FIXME: it would be more efficient to send here, but the entity
903 // compressor isn't that flexible
904 sv_writeentitiestoclient_visibleentities++;
905 sententities[s->number] = sententitiesmark;
908 entity_state_t sendstates[MAX_EDICTS];
909 extern int csqc_clent;
911 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
913 int i, numsendstates;
916 // if there isn't enough space to accomplish anything, skip it
917 if (msg->cursize + 25 > msg->maxsize)
920 sv_writeentitiestoclient_client = client;
922 sv_writeentitiestoclient_culled_pvs = 0;
923 sv_writeentitiestoclient_culled_trace = 0;
924 sv_writeentitiestoclient_visibleentities = 0;
925 sv_writeentitiestoclient_totalentities = 0;
927 // find the client's PVS
928 // the real place being tested from
929 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
930 sv_writeentitiestoclient_pvsbytes = 0;
931 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
932 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
934 csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
938 for (i = 0;i < numsendentities;i++)
939 SV_MarkWriteEntityStateToClient(sendentities + i);
942 for (i = 0;i < numsendentities;i++)
944 if (sententities[sendentities[i].number] == sententitiesmark)
946 s = &sendstates[numsendstates++];
947 *s = sendentities[i];
948 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
949 s->flags |= RENDER_EXTERIORMODEL;
953 if (sv_cullentities_stats.integer)
954 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);
956 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
958 if (client->entitydatabase5)
959 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
960 else if (client->entitydatabase4)
961 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
962 else if (client->entitydatabase)
963 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
965 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
974 void SV_CleanupEnts (void)
979 ent = PRVM_NEXT_EDICT(prog->edicts);
980 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
981 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
986 SV_WriteClientdataToMessage
990 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1002 // send a damage message
1004 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
1006 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
1007 MSG_WriteByte (msg, svc_damage);
1008 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
1009 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
1010 for (i=0 ; i<3 ; i++)
1011 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
1013 ent->fields.server->dmg_take = 0;
1014 ent->fields.server->dmg_save = 0;
1018 // send the current viewpos offset from the view entity
1020 SV_SetIdealPitch (); // how much to look up / down ideally
1022 // a fixangle might get lost in a dropped packet. Oh well.
1023 if ( ent->fields.server->fixangle )
1025 MSG_WriteByte (msg, svc_setangle);
1026 for (i=0 ; i < 3 ; i++)
1027 MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
1028 ent->fields.server->fixangle = 0;
1031 // stuff the sigil bits into the high bits of items for sbar, or else
1033 val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
1034 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1035 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1037 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1039 VectorClear(punchvector);
1040 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
1041 VectorCopy(val->vector, punchvector);
1043 // cache weapon model name and index in client struct to save time
1044 // (this search can be almost 1% of cpu time!)
1045 s = PRVM_GetString(ent->fields.server->weaponmodel);
1046 if (strcmp(s, client->weaponmodel))
1048 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1049 client->weaponmodelindex = SV_ModelIndex(s, 1);
1053 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
1054 viewzoom = (int)(val->_float * 255.0f);
1060 if ((int)ent->fields.server->flags & FL_ONGROUND)
1061 bits |= SU_ONGROUND;
1062 if (ent->fields.server->waterlevel >= 2)
1064 if (ent->fields.server->idealpitch)
1065 bits |= SU_IDEALPITCH;
1067 for (i=0 ; i<3 ; i++)
1069 if (ent->fields.server->punchangle[i])
1070 bits |= (SU_PUNCH1<<i);
1071 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1073 bits |= (SU_PUNCHVEC1<<i);
1074 if (ent->fields.server->velocity[i])
1075 bits |= (SU_VELOCITY1<<i);
1078 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1079 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1080 stats[STAT_ITEMS] = items;
1081 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1082 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1083 stats[STAT_WEAPON] = client->weaponmodelindex;
1084 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1085 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1086 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1087 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1088 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1089 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1090 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1091 stats[STAT_VIEWZOOM] = viewzoom;
1092 // the QC bumps these itself by sending svc_'s, so we have to keep them
1093 // zero or they'll be corrected by the engine
1094 //stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1095 //stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1096 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1097 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1099 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)
1101 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1103 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1104 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1106 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1107 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1108 if (viewzoom != 255)
1109 bits |= SU_VIEWZOOM;
1114 if (bits >= 16777216)
1118 MSG_WriteByte (msg, svc_clientdata);
1119 MSG_WriteShort (msg, bits);
1120 if (bits & SU_EXTEND1)
1121 MSG_WriteByte(msg, bits >> 16);
1122 if (bits & SU_EXTEND2)
1123 MSG_WriteByte(msg, bits >> 24);
1125 if (bits & SU_VIEWHEIGHT)
1126 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1128 if (bits & SU_IDEALPITCH)
1129 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1131 for (i=0 ; i<3 ; i++)
1133 if (bits & (SU_PUNCH1<<i))
1135 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1136 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1138 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1140 if (bits & (SU_PUNCHVEC1<<i))
1142 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1143 MSG_WriteCoord16i(msg, punchvector[i]);
1145 MSG_WriteCoord32f(msg, punchvector[i]);
1147 if (bits & (SU_VELOCITY1<<i))
1149 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1150 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1152 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1156 if (bits & SU_ITEMS)
1157 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1159 if (sv.protocol == PROTOCOL_DARKPLACES5)
1161 if (bits & SU_WEAPONFRAME)
1162 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1163 if (bits & SU_ARMOR)
1164 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1165 if (bits & SU_WEAPON)
1166 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1167 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1168 MSG_WriteShort (msg, stats[STAT_AMMO]);
1169 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1170 MSG_WriteShort (msg, stats[STAT_NAILS]);
1171 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1172 MSG_WriteShort (msg, stats[STAT_CELLS]);
1173 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1174 if (bits & SU_VIEWZOOM)
1175 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1177 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)
1179 if (bits & SU_WEAPONFRAME)
1180 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1181 if (bits & SU_ARMOR)
1182 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1183 if (bits & SU_WEAPON)
1184 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1185 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1186 MSG_WriteByte (msg, stats[STAT_AMMO]);
1187 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1188 MSG_WriteByte (msg, stats[STAT_NAILS]);
1189 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1190 MSG_WriteByte (msg, stats[STAT_CELLS]);
1191 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1193 for (i = 0;i < 32;i++)
1194 if (stats[STAT_WEAPON] & (1<<i))
1196 MSG_WriteByte (msg, i);
1199 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1200 if (bits & SU_VIEWZOOM)
1202 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1203 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1205 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1211 =======================
1212 SV_SendClientDatagram
1213 =======================
1215 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1216 void SV_SendClientDatagram (client_t *client)
1218 int rate, maxrate, maxsize, maxsize2;
1220 int stats[MAX_CL_STATS];
1222 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1224 // for good singleplayer, send huge packets
1225 maxsize = sizeof(sv_sendclientdatagram_buf);
1226 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1228 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)
1230 // no rate limiting support on older protocols because dp protocols
1231 // 1-4 kick the client off if they overflow, and quake protocol shows
1232 // less than the full entity set if rate limited
1238 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1239 maxrate = max(NET_MINRATE, sv_maxrate.integer);
1240 if (sv_maxrate.integer != maxrate)
1241 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1243 // this rate limiting does not understand sys_ticrate 0
1244 // (but no one should be running that on a server!)
1245 rate = bound(NET_MINRATE, client->rate, maxrate);
1246 rate = (int)(rate * sys_ticrate.value);
1247 maxsize = bound(100, rate, 1400);
1251 msg.data = sv_sendclientdatagram_buf;
1252 msg.maxsize = maxsize;
1255 if (host_client->spawned)
1257 MSG_WriteByte (&msg, svc_time);
1258 MSG_WriteFloat (&msg, sv.time);
1260 // add the client specific data to the datagram
1261 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1262 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1263 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1265 // expand packet size to allow effects to go over the rate limit
1266 // (dropping them is FAR too ugly)
1267 msg.maxsize = maxsize2;
1269 // copy the server datagram if there is space
1270 // FIXME: put in delayed queue of effects to send
1271 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1272 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1274 else if (realtime > client->keepalivetime)
1276 // the player isn't totally in the game yet
1277 // send small keepalive messages if too much time has passed
1278 client->keepalivetime = realtime + 5;
1279 MSG_WriteChar (&msg, svc_nop);
1282 // send the datagram
1283 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1287 =======================
1288 SV_UpdateToReliableMessages
1289 =======================
1291 void SV_UpdateToReliableMessages (void)
1300 // check for changes to be sent over the reliable streams
1301 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1303 // update the host_client fields we care about according to the entity fields
1304 host_client->edict = PRVM_EDICT_NUM(i+1);
1307 name = PRVM_GetString(host_client->edict->fields.server->netname);
1310 // always point the string back at host_client->name to keep it safe
1311 strlcpy (host_client->name, name, sizeof (host_client->name));
1312 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1313 if (strcmp(host_client->old_name, host_client->name))
1315 if (host_client->spawned)
1316 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1317 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1318 // send notification to all clients
1319 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1320 MSG_WriteByte (&sv.reliable_datagram, i);
1321 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1324 // DP_SV_CLIENTCOLORS
1325 // this is always found (since it's added by the progs loader)
1326 if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1327 host_client->colors = (int)val->_float;
1328 if (host_client->old_colors != host_client->colors)
1330 host_client->old_colors = host_client->colors;
1331 // send notification to all clients
1332 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1333 MSG_WriteByte (&sv.reliable_datagram, i);
1334 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1337 // NEXUIZ_PLAYERMODEL
1338 if( eval_playermodel ) {
1339 model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string);
1342 // always point the string back at host_client->name to keep it safe
1343 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1344 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1347 // NEXUIZ_PLAYERSKIN
1348 if( eval_playerskin ) {
1349 skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string);
1352 // always point the string back at host_client->name to keep it safe
1353 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1354 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1358 host_client->frags = (int)host_client->edict->fields.server->frags;
1359 if (host_client->old_frags != host_client->frags)
1361 host_client->old_frags = host_client->frags;
1362 // send notification to all clients
1363 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1364 MSG_WriteByte (&sv.reliable_datagram, i);
1365 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1369 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1370 if (client->netconnection)
1371 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1373 SZ_Clear (&sv.reliable_datagram);
1378 =======================
1379 SV_SendClientMessages
1380 =======================
1382 void SV_SendClientMessages (void)
1384 int i, prepared = false;
1386 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1387 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1389 // update frags, names, etc
1390 SV_UpdateToReliableMessages();
1392 // build individual updates
1393 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1395 if (!host_client->active)
1397 if (!host_client->netconnection)
1400 if (host_client->netconnection->message.overflowed)
1402 SV_DropClient (true); // if the message couldn't send, kick off
1409 // only prepare entities once per frame
1410 SV_PrepareEntitiesForSending();
1412 SV_SendClientDatagram (host_client);
1415 // clear muzzle flashes
1421 ==============================================================================
1425 ==============================================================================
1434 int SV_ModelIndex(const char *s, int precachemode)
1436 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1437 char filename[MAX_QPATH];
1441 //if (precachemode == 2)
1443 strlcpy(filename, s, sizeof(filename));
1444 for (i = 2;i < limit;i++)
1446 if (!sv.model_precache[i][0])
1450 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))
1452 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1455 if (precachemode == 1)
1456 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1457 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1458 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1459 if (sv.state != ss_loading)
1461 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1462 MSG_WriteShort(&sv.reliable_datagram, i);
1463 MSG_WriteString(&sv.reliable_datagram, filename);
1467 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1470 if (!strcmp(sv.model_precache[i], filename))
1473 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1483 int SV_SoundIndex(const char *s, int precachemode)
1485 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1486 char filename[MAX_QPATH];
1490 //if (precachemode == 2)
1492 strlcpy(filename, s, sizeof(filename));
1493 for (i = 1;i < limit;i++)
1495 if (!sv.sound_precache[i][0])
1499 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))
1501 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1504 if (precachemode == 1)
1505 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1506 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1507 if (sv.state != ss_loading)
1509 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1510 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1511 MSG_WriteString(&sv.reliable_datagram, filename);
1515 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1518 if (!strcmp(sv.sound_precache[i], filename))
1521 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1531 void SV_CreateBaseline (void)
1533 int i, entnum, large;
1534 prvm_edict_t *svent;
1536 // LordHavoc: clear *all* states (note just active ones)
1537 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1539 // get the current server version
1540 svent = PRVM_EDICT_NUM(entnum);
1542 // LordHavoc: always clear state values, whether the entity is in use or not
1543 svent->priv.server->baseline = defaultstate;
1545 if (svent->priv.server->free)
1547 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1550 // create entity baseline
1551 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1552 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1553 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1554 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1555 if (entnum > 0 && entnum <= svs.maxclients)
1557 svent->priv.server->baseline.colormap = entnum;
1558 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1562 svent->priv.server->baseline.colormap = 0;
1563 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1567 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1570 // add to the message
1572 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1574 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1575 MSG_WriteShort (&sv.signon, entnum);
1579 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1580 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1584 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1585 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1587 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1588 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1589 for (i=0 ; i<3 ; i++)
1591 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1592 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1602 Grabs the current state of each client for saving across the
1603 transition to another level
1606 void SV_SaveSpawnparms (void)
1610 svs.serverflags = (int)prog->globals.server->serverflags;
1612 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1614 if (!host_client->active)
1617 // call the progs to get default spawn parms for the new client
1618 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1619 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1620 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1621 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1625 void SV_IncreaseEdicts(void)
1629 int oldmax_edicts = prog->max_edicts;
1630 void *oldedictsengineprivate = prog->edictprivate;
1631 void *oldedictsfields = prog->edictsfields;
1632 void *oldmoved_edicts = sv.moved_edicts;
1634 if (prog->max_edicts >= MAX_EDICTS)
1637 // links don't survive the transition, so unlink everything
1638 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1640 if (!ent->priv.server->free)
1641 SV_UnlinkEdict(prog->edicts + i);
1642 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1646 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
1647 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1648 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
1649 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1651 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
1652 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
1654 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1656 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1657 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1658 // link every entity except world
1659 if (!ent->priv.server->free)
1660 SV_LinkEdict(ent, false);
1663 PR_Free(oldedictsengineprivate);
1664 PR_Free(oldedictsfields);
1665 PR_Free(oldmoved_edicts);
1672 This is called at the start of each level
1675 extern float scr_centertime_off;
1677 void SV_SpawnServer (const char *server)
1682 model_t *worldmodel;
1683 char modelname[sizeof(sv.modelname)];
1685 Con_DPrintf("SpawnServer: %s\n", server);
1687 if (cls.state != ca_dedicated)
1688 SCR_BeginLoadingPlaque();
1690 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
1691 worldmodel = Mod_ForName(modelname, false, true, true);
1692 if (!worldmodel || !worldmodel->TraceBox)
1694 Con_Printf("Couldn't load map %s\n", modelname);
1698 // let's not have any servers with no name
1699 if (hostname.string[0] == 0)
1700 Cvar_Set ("hostname", "UNNAMED");
1701 scr_centertime_off = 0;
1703 svs.changelevel_issued = false; // now safe to issue another
1705 // make the map a required file for clients
1706 Curl_ClearRequirements();
1707 Curl_RequireFile(modelname);
1710 // tell all connected clients that we are going to a new level
1715 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1717 if (client->netconnection)
1719 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
1720 MSG_WriteString(&client->netconnection->message, "reconnect\n");
1727 NetConn_OpenServerPorts(true);
1731 // make cvars consistant
1734 Cvar_SetValue ("deathmatch", 0);
1735 // LordHavoc: it can be useful to have skills outside the range 0-3...
1736 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
1737 //Cvar_SetValue ("skill", (float)current_skill);
1738 current_skill = (int)(skill.value + 0.5);
1741 // set up the new server
1743 memset (&sv, 0, sizeof(sv));
1744 // if running a local client, make sure it doesn't try to access the last
1745 // level's data which is no longer valiud
1748 if(*sv_random_seed.string)
1750 srand(sv_random_seed.integer);
1751 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);
1758 strlcpy (sv.name, server, sizeof (sv.name));
1760 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
1761 if (sv.protocol == PROTOCOL_UNKNOWN)
1764 Protocol_Names(buffer, sizeof(buffer));
1765 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
1766 sv.protocol = PROTOCOL_QUAKE;
1771 // load progs to get entity field count
1772 //PR_LoadProgs ( sv_progs.string );
1774 // allocate server memory
1775 /*// start out with just enough room for clients and a reasonable estimate of entities
1776 prog->max_edicts = max(svs.maxclients + 1, 512);
1777 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
1779 // prvm_edict_t structures (hidden from progs)
1780 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
1781 // engine private structures (hidden from progs)
1782 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1783 // progs fields, often accessed by server
1784 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
1785 // used by PushMove to move back pushed entities
1786 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1787 /*for (i = 0;i < prog->max_edicts;i++)
1789 ent = prog->edicts + i;
1790 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1791 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1794 // reset client csqc entity versions right away.
1795 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1796 EntityFrameCSQC_InitClientVersions(i, true);
1798 sv.datagram.maxsize = sizeof(sv.datagram_buf);
1799 sv.datagram.cursize = 0;
1800 sv.datagram.data = sv.datagram_buf;
1802 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
1803 sv.reliable_datagram.cursize = 0;
1804 sv.reliable_datagram.data = sv.reliable_datagram_buf;
1806 sv.signon.maxsize = sizeof(sv.signon_buf);
1807 sv.signon.cursize = 0;
1808 sv.signon.data = sv.signon_buf;
1810 // leave slots at start for clients only
1811 //prog->num_edicts = svs.maxclients+1;
1813 sv.state = ss_loading;
1814 prog->allowworldwrites = true;
1817 *prog->time = sv.time = 1.0;
1820 worldmodel->used = true;
1822 strlcpy (sv.name, server, sizeof (sv.name));
1823 strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
1824 sv.worldmodel = worldmodel;
1825 sv.models[1] = sv.worldmodel;
1828 // clear world interaction links
1832 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
1834 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
1835 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
1836 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
1838 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
1839 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
1843 // load the rest of the entities
1845 // AK possible hack since num_edicts is still 0
1846 ent = PRVM_EDICT_NUM(0);
1847 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
1848 ent->priv.server->free = false;
1849 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
1850 ent->fields.server->modelindex = 1; // world model
1851 ent->fields.server->solid = SOLID_BSP;
1852 ent->fields.server->movetype = MOVETYPE_PUSH;
1853 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->mins);
1854 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->maxs);
1855 VectorCopy(sv.worldmodel->normalmins, ent->fields.server->absmin);
1856 VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->absmax);
1859 prog->globals.server->coop = coop.integer;
1861 prog->globals.server->deathmatch = deathmatch.integer;
1863 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
1865 // serverflags are for cross level information (sigils)
1866 prog->globals.server->serverflags = svs.serverflags;
1868 // we need to reset the spawned flag on all connected clients here so that
1869 // their thinks don't run during startup (before PutClientInServer)
1870 // we also need to set up the client entities now
1871 // and we need to set the ->edict pointers to point into the progs edicts
1872 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1874 host_client->spawned = false;
1875 host_client->edict = PRVM_EDICT_NUM(i + 1);
1876 PRVM_ED_ClearEdict(host_client->edict);
1879 // load replacement entity file if found
1880 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
1882 Con_Printf("Loaded maps/%s.ent\n", sv.name);
1883 PRVM_ED_LoadFromFile (entities);
1887 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
1890 // LordHavoc: clear world angles (to fix e3m3.bsp)
1891 VectorClear(prog->edicts->fields.server->angles);
1893 // all setup is completed, any further precache statements are errors
1894 sv.state = ss_active;
1895 prog->allowworldwrites = false;
1897 // run two frames to allow everything to settle
1898 for (i = 0;i < 2;i++)
1906 // create a baseline for more efficient communications
1907 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1908 SV_CreateBaseline ();
1910 // send serverinfo to all connected clients, and set up botclients coming back from a level change
1911 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1913 if (!host_client->active)
1915 if (host_client->netconnection)
1916 SV_SendServerinfo(host_client);
1920 // if client is a botclient coming from a level change, we need to
1921 // set up client info that normally requires networking
1923 // copy spawn parms out of the client_t
1924 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
1925 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
1927 // call the spawn function
1928 host_client->clientconnectcalled = true;
1929 prog->globals.server->time = sv.time;
1930 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1931 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1932 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1933 host_client->spawned = true;
1937 Con_DPrint("Server spawned.\n");
1938 NetConn_Heartbeat (2);
1943 /////////////////////////////////////////////////////
1946 void SV_VM_CB_BeginIncreaseEdicts(void)
1951 PRVM_Free( sv.moved_edicts );
1952 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1954 // links don't survive the transition, so unlink everything
1955 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1957 if (!ent->priv.server->free)
1958 SV_UnlinkEdict(prog->edicts + i);
1959 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1964 void SV_VM_CB_EndIncreaseEdicts(void)
1969 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1971 // link every entity except world
1972 if (!ent->priv.server->free)
1973 SV_LinkEdict(ent, false);
1977 void SV_VM_CB_InitEdict(prvm_edict_t *e)
1979 // LordHavoc: for consistency set these here
1980 int num = PRVM_NUM_FOR_EDICT(e) - 1;
1982 e->priv.server->move = false; // don't move on first frame
1984 if (num >= 0 && num < svs.maxclients)
1987 // set colormap and team on newly created player entity
1988 e->fields.server->colormap = num + 1;
1989 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
1990 // set netname/clientcolors back to client values so that
1991 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
1993 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
1994 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
1995 val->_float = svs.clients[num].colors;
1996 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
1997 if( eval_playermodel )
1998 PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
1999 if( eval_playerskin )
2000 PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
2004 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
2006 SV_UnlinkEdict (ed); // unlink from world bsp
2008 ed->fields.server->model = 0;
2009 ed->fields.server->takedamage = 0;
2010 ed->fields.server->modelindex = 0;
2011 ed->fields.server->colormap = 0;
2012 ed->fields.server->skin = 0;
2013 ed->fields.server->frame = 0;
2014 VectorClear(ed->fields.server->origin);
2015 VectorClear(ed->fields.server->angles);
2016 ed->fields.server->nextthink = -1;
2017 ed->fields.server->solid = 0;
2020 void SV_VM_CB_CountEdicts(void)
2024 int active, models, solid, step;
2026 active = models = solid = step = 0;
2027 for (i=0 ; i<prog->num_edicts ; i++)
2029 ent = PRVM_EDICT_NUM(i);
2030 if (ent->priv.server->free)
2033 if (ent->fields.server->solid)
2035 if (ent->fields.server->model)
2037 if (ent->fields.server->movetype == MOVETYPE_STEP)
2041 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2042 Con_Printf("active :%3i\n", active);
2043 Con_Printf("view :%3i\n", models);
2044 Con_Printf("touch :%3i\n", solid);
2045 Con_Printf("step :%3i\n", step);
2048 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2050 // remove things from different skill levels or deathmatch
2051 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2053 if (deathmatch.integer)
2055 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2060 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2061 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2062 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2070 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)"};
2071 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2072 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2073 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2074 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2075 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2076 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2077 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2078 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2079 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2080 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2081 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2082 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2083 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2084 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2085 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2086 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2087 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2088 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2089 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2090 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2091 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2092 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2093 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2094 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2095 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2096 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2097 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2098 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2099 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2100 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2101 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2102 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2104 void SV_VM_Init(void)
2106 Cvar_RegisterVariable (&pr_checkextension);
2107 Cvar_RegisterVariable (&nomonsters);
2108 Cvar_RegisterVariable (&gamecfg);
2109 Cvar_RegisterVariable (&scratch1);
2110 Cvar_RegisterVariable (&scratch2);
2111 Cvar_RegisterVariable (&scratch3);
2112 Cvar_RegisterVariable (&scratch4);
2113 Cvar_RegisterVariable (&savedgamecfg);
2114 Cvar_RegisterVariable (&saved1);
2115 Cvar_RegisterVariable (&saved2);
2116 Cvar_RegisterVariable (&saved3);
2117 Cvar_RegisterVariable (&saved4);
2118 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2119 if (gamemode == GAME_NEHAHRA)
2121 Cvar_RegisterVariable (&nehx00);
2122 Cvar_RegisterVariable (&nehx01);
2123 Cvar_RegisterVariable (&nehx02);
2124 Cvar_RegisterVariable (&nehx03);
2125 Cvar_RegisterVariable (&nehx04);
2126 Cvar_RegisterVariable (&nehx05);
2127 Cvar_RegisterVariable (&nehx06);
2128 Cvar_RegisterVariable (&nehx07);
2129 Cvar_RegisterVariable (&nehx08);
2130 Cvar_RegisterVariable (&nehx09);
2131 Cvar_RegisterVariable (&nehx10);
2132 Cvar_RegisterVariable (&nehx11);
2133 Cvar_RegisterVariable (&nehx12);
2134 Cvar_RegisterVariable (&nehx13);
2135 Cvar_RegisterVariable (&nehx14);
2136 Cvar_RegisterVariable (&nehx15);
2137 Cvar_RegisterVariable (&nehx16);
2138 Cvar_RegisterVariable (&nehx17);
2139 Cvar_RegisterVariable (&nehx18);
2140 Cvar_RegisterVariable (&nehx19);
2142 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2145 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
2162 int eval_buttonchat;
2164 int eval_glow_trail;
2165 int eval_glow_color;
2169 int eval_renderamt; // HalfLife support
2170 int eval_rendermode; // HalfLife support
2171 int eval_fullbright;
2172 int eval_ammo_shells1;
2173 int eval_ammo_nails1;
2174 int eval_ammo_lava_nails;
2175 int eval_ammo_rockets1;
2176 int eval_ammo_multi_rockets;
2177 int eval_ammo_cells1;
2178 int eval_ammo_plasma;
2179 int eval_idealpitch;
2180 int eval_pitch_speed;
2181 int eval_viewmodelforclient;
2182 int eval_nodrawtoclient;
2183 int eval_exteriormodeltoclient;
2184 int eval_drawonlytoclient;
2188 int eval_punchvector;
2190 int eval_clientcolors;
2191 int eval_tag_entity;
2197 int eval_cursor_active;
2198 int eval_cursor_screen;
2199 int eval_cursor_trace_start;
2200 int eval_cursor_trace_endpos;
2201 int eval_cursor_trace_ent;
2203 int eval_playermodel;
2204 int eval_playerskin;
2205 int eval_SendEntity;
2207 int eval_customizeentityforclient;
2208 int eval_dphitcontentsmask;
2209 // DRESK - Support for Entity Contents Transition Event
2210 int eval_contentstransition;
2212 int gval_trace_dpstartcontents;
2213 int gval_trace_dphitcontents;
2214 int gval_trace_dphitq3surfaceflags;
2215 int gval_trace_dphittexturename;
2217 mfunction_t *SV_PlayerPhysicsQC;
2218 mfunction_t *EndFrameQC;
2219 //KrimZon - SERVER COMMANDS IN QUAKEC
2220 mfunction_t *SV_ParseClientCommandQC;
2222 void SV_VM_FindEdictFieldOffsets(void)
2224 eval_gravity = PRVM_ED_FindFieldOffset("gravity");
2225 eval_button3 = PRVM_ED_FindFieldOffset("button3");
2226 eval_button4 = PRVM_ED_FindFieldOffset("button4");
2227 eval_button5 = PRVM_ED_FindFieldOffset("button5");
2228 eval_button6 = PRVM_ED_FindFieldOffset("button6");
2229 eval_button7 = PRVM_ED_FindFieldOffset("button7");
2230 eval_button8 = PRVM_ED_FindFieldOffset("button8");
2231 eval_button9 = PRVM_ED_FindFieldOffset("button9");
2232 eval_button10 = PRVM_ED_FindFieldOffset("button10");
2233 eval_button11 = PRVM_ED_FindFieldOffset("button11");
2234 eval_button12 = PRVM_ED_FindFieldOffset("button12");
2235 eval_button13 = PRVM_ED_FindFieldOffset("button13");
2236 eval_button14 = PRVM_ED_FindFieldOffset("button14");
2237 eval_button15 = PRVM_ED_FindFieldOffset("button15");
2238 eval_button16 = PRVM_ED_FindFieldOffset("button16");
2239 eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
2240 eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
2241 eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
2242 eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
2243 eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
2244 eval_items2 = PRVM_ED_FindFieldOffset("items2");
2245 eval_scale = PRVM_ED_FindFieldOffset("scale");
2246 eval_alpha = PRVM_ED_FindFieldOffset("alpha");
2247 eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
2248 eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
2249 eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
2250 eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
2251 eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
2252 eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
2253 eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
2254 eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
2255 eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
2256 eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
2257 eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
2258 eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
2259 eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
2260 eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
2261 eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
2262 eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
2263 eval_ping = PRVM_ED_FindFieldOffset("ping");
2264 eval_movement = PRVM_ED_FindFieldOffset("movement");
2265 eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
2266 eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
2267 eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
2268 eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
2269 eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
2270 eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
2271 eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
2272 eval_color = PRVM_ED_FindFieldOffset("color");
2273 eval_style = PRVM_ED_FindFieldOffset("style");
2274 eval_pflags = PRVM_ED_FindFieldOffset("pflags");
2275 eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
2276 eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
2277 eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
2278 eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
2279 eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
2280 eval_colormod = PRVM_ED_FindFieldOffset("colormod");
2281 eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
2282 eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
2283 eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
2284 eval_Version = PRVM_ED_FindFieldOffset("Version");
2285 eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
2286 eval_dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
2287 // DRESK - Support for Entity Contents Transition Event
2288 eval_contentstransition = PRVM_ED_FindFieldOffset("contentstransition");
2290 // LordHavoc: allowing QuakeC to override the player movement code
2291 SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
2292 // LordHavoc: support for endframe
2293 EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
2294 //KrimZon - SERVER COMMANDS IN QUAKEC
2295 SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
2296 gval_trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
2297 gval_trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
2298 gval_trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
2299 gval_trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
2302 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2304 prvm_required_field_t reqfields[] =
2306 {ev_entity, "cursor_trace_ent"},
2307 {ev_entity, "drawonlytoclient"},
2308 {ev_entity, "exteriormodeltoclient"},
2309 {ev_entity, "nodrawtoclient"},
2310 {ev_entity, "tag_entity"},
2311 {ev_entity, "viewmodelforclient"},
2312 {ev_float, "alpha"},
2313 {ev_float, "ammo_cells1"},
2314 {ev_float, "ammo_lava_nails"},
2315 {ev_float, "ammo_multi_rockets"},
2316 {ev_float, "ammo_nails1"},
2317 {ev_float, "ammo_plasma"},
2318 {ev_float, "ammo_rockets1"},
2319 {ev_float, "ammo_shells1"},
2320 {ev_float, "button3"},
2321 {ev_float, "button4"},
2322 {ev_float, "button5"},
2323 {ev_float, "button6"},
2324 {ev_float, "button7"},
2325 {ev_float, "button8"},
2326 {ev_float, "button9"},
2327 {ev_float, "button10"},
2328 {ev_float, "button11"},
2329 {ev_float, "button12"},
2330 {ev_float, "button13"},
2331 {ev_float, "button14"},
2332 {ev_float, "button15"},
2333 {ev_float, "button16"},
2334 {ev_float, "buttonchat"},
2335 {ev_float, "buttonuse"},
2336 {ev_float, "clientcolors"},
2337 {ev_float, "cursor_active"},
2338 {ev_float, "fullbright"},
2339 {ev_float, "glow_color"},
2340 {ev_float, "glow_size"},
2341 {ev_float, "glow_trail"},
2342 {ev_float, "gravity"},
2343 {ev_float, "idealpitch"},
2344 {ev_float, "items2"},
2345 {ev_float, "light_lev"},
2346 {ev_float, "pflags"},
2348 {ev_float, "pitch_speed"},
2349 {ev_float, "pmodel"},
2350 {ev_float, "renderamt"}, // HalfLife support
2351 {ev_float, "rendermode"}, // HalfLife support
2352 {ev_float, "scale"},
2353 {ev_float, "style"},
2354 {ev_float, "tag_index"},
2355 {ev_float, "Version"},
2356 {ev_float, "viewzoom"},
2357 {ev_vector, "color"},
2358 {ev_vector, "colormod"},
2359 {ev_vector, "cursor_screen"},
2360 {ev_vector, "cursor_trace_endpos"},
2361 {ev_vector, "cursor_trace_start"},
2362 {ev_vector, "movement"},
2363 {ev_vector, "punchvector"},
2364 {ev_string, "playermodel"},
2365 {ev_string, "playerskin"},
2366 {ev_function, "SendEntity"},
2367 {ev_function, "customizeentityforclient"},
2368 // DRESK - Support for Entity Contents Transition Event
2369 {ev_function, "contentstransition"},
2372 void SV_VM_Setup(void)
2374 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
2375 extern cvar_t csqc_progcrc;
2376 unsigned char *csprogsdata;
2377 fs_offset_t csprogsdatasize;
2379 PRVM_InitProg( PRVM_SERVERPROG );
2381 // allocate the mempools
2382 // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
2383 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2384 prog->builtins = vm_sv_builtins;
2385 prog->numbuiltins = vm_sv_numbuiltins;
2386 prog->headercrc = PROGHEADER_CRC;
2387 prog->max_edicts = 512;
2388 prog->limit_edicts = MAX_EDICTS;
2389 prog->reserved_edicts = svs.maxclients;
2390 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2391 prog->name = "server";
2392 prog->extensionstring = vm_sv_extensions;
2393 prog->loadintoworld = true;
2395 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2396 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2397 prog->init_edict = SV_VM_CB_InitEdict;
2398 prog->free_edict = SV_VM_CB_FreeEdict;
2399 prog->count_edicts = SV_VM_CB_CountEdicts;
2400 prog->load_edict = SV_VM_CB_LoadEdict;
2401 prog->init_cmd = VM_SV_Cmd_Init;
2402 prog->reset_cmd = VM_SV_Cmd_Reset;
2403 prog->error_cmd = Host_Error;
2405 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2406 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
2407 SV_VM_FindEdictFieldOffsets();
2409 VM_AutoSentStats_Clear();//[515]: csqc
2410 EntityFrameCSQC_ClearVersions();//[515]: csqc
2414 // 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
2415 sv.csqc_progcrc = -1;
2416 sv.csqc_progname[0] = 0;
2417 csprogsdata = FS_LoadFile(csqc_progname.string, tempmempool, true, &csprogsdatasize);
2420 strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
2421 sv.csqc_progcrc = CRC_Block(csprogsdata, csprogsdatasize);
2422 Mem_Free(csprogsdata);
2423 Con_DPrintf("server detected csqc progs file \"%s\" with crc %i\n", sv.csqc_progname, sv.csqc_progcrc);
2427 void SV_VM_Begin(void)
2430 PRVM_SetProg( PRVM_SERVERPROG );
2432 *prog->time = (float) sv.time;
2435 void SV_VM_End(void)