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 static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"}; // fast but loose
41 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
42 static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
43 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)"};
45 cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebouncedownslopes", "1", "prevents MOVETYPE_BOUNCE (grenades) from getting stuck when fired down a downward sloping surface"};
46 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"};
47 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)"};
48 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)"};
49 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"};
50 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"};
51 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"};
52 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"};
53 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"};
54 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"};
56 cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
58 // TODO: move these cvars here
59 extern cvar_t sv_clmovement_enable;
60 extern cvar_t sv_clmovement_minping;
61 extern cvar_t sv_clmovement_minping_disabletime;
62 extern cvar_t sv_clmovement_waitforinput;
67 mempool_t *sv_mempool = NULL;
69 //============================================================================
71 extern void SV_Phys_Init (void);
72 extern void SV_World_Init (void);
73 static void SV_SaveEntFile_f(void);
82 // init the csqc progs cvars, since they are updated/used by the server code
83 // TODO: fix this since this is a quick hack to make some of [515]'s broken code run ;) [9/13/2006 Black]
84 extern cvar_t csqc_progname;
85 extern cvar_t csqc_progcrc;
86 Cvar_RegisterVariable (&csqc_progname);
87 Cvar_RegisterVariable (&csqc_progcrc);
89 Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
90 Cvar_RegisterVariable (&sv_maxvelocity);
91 Cvar_RegisterVariable (&sv_gravity);
92 Cvar_RegisterVariable (&sv_friction);
93 Cvar_RegisterVariable (&sv_waterfriction);
94 Cvar_RegisterVariable (&sv_edgefriction);
95 Cvar_RegisterVariable (&sv_stopspeed);
96 Cvar_RegisterVariable (&sv_maxspeed);
97 Cvar_RegisterVariable (&sv_maxairspeed);
98 Cvar_RegisterVariable (&sv_accelerate);
99 Cvar_RegisterVariable (&sv_airaccelerate);
100 Cvar_RegisterVariable (&sv_wateraccelerate);
101 Cvar_RegisterVariable (&sv_clmovement_enable);
102 Cvar_RegisterVariable (&sv_clmovement_minping);
103 Cvar_RegisterVariable (&sv_clmovement_minping_disabletime);
104 Cvar_RegisterVariable (&sv_clmovement_waitforinput);
105 Cvar_RegisterVariable (&sv_idealpitchscale);
106 Cvar_RegisterVariable (&sv_aim);
107 Cvar_RegisterVariable (&sv_nostep);
108 Cvar_RegisterVariable (&sv_cullentities_pvs);
109 Cvar_RegisterVariable (&sv_cullentities_trace);
110 Cvar_RegisterVariable (&sv_cullentities_stats);
111 Cvar_RegisterVariable (&sv_entpatch);
112 Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
113 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
114 Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
115 Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
116 Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
117 Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
118 Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
119 Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
120 Cvar_RegisterVariable (&sv_gameplayfix_qwplayerphysics);
121 Cvar_RegisterVariable (&sv_gameplayfix_upwardvelocityclearsongroundflag);
122 Cvar_RegisterVariable (&sv_protocolname);
123 Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
124 Cvar_RegisterVariable (&sv_maxrate);
125 Cvar_RegisterVariable (&sv_progs);
131 sv_mempool = Mem_AllocPool("server", 0, NULL);
134 static void SV_SaveEntFile_f(void)
136 char basename[MAX_QPATH];
137 if (!sv.active || !sv.worldmodel)
139 Con_Print("Not running a server\n");
142 FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
143 FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
148 =============================================================================
152 =============================================================================
159 Make sure the event gets sent to all clients
162 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
166 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
168 MSG_WriteByte (&sv.datagram, svc_particle);
169 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
170 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
171 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
172 for (i=0 ; i<3 ; i++)
173 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
174 MSG_WriteByte (&sv.datagram, count);
175 MSG_WriteByte (&sv.datagram, color);
182 Make sure the event gets sent to all clients
185 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
187 if (modelindex >= 256 || startframe >= 256)
189 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
191 MSG_WriteByte (&sv.datagram, svc_effect2);
192 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
193 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
194 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
195 MSG_WriteShort (&sv.datagram, modelindex);
196 MSG_WriteShort (&sv.datagram, startframe);
197 MSG_WriteByte (&sv.datagram, framecount);
198 MSG_WriteByte (&sv.datagram, framerate);
202 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
204 MSG_WriteByte (&sv.datagram, svc_effect);
205 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
206 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
207 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
208 MSG_WriteByte (&sv.datagram, modelindex);
209 MSG_WriteByte (&sv.datagram, startframe);
210 MSG_WriteByte (&sv.datagram, framecount);
211 MSG_WriteByte (&sv.datagram, framerate);
219 Each entity can have eight independant sound sources, like voice,
222 Channel 0 is an auto-allocate channel, the others override anything
223 already running on that entity/channel pair.
225 An attenuation of 0 will play full volume everywhere in the level.
226 Larger attenuations will drop off. (max 4 attenuation)
230 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
232 int sound_num, field_mask, i, ent;
234 if (volume < 0 || volume > 255)
236 Con_Printf ("SV_StartSound: volume = %i\n", volume);
240 if (attenuation < 0 || attenuation > 4)
242 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
246 if (channel < 0 || channel > 7)
248 Con_Printf ("SV_StartSound: channel = %i\n", channel);
252 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
255 // find precache number for sound
256 sound_num = SV_SoundIndex(sample, 1);
260 ent = PRVM_NUM_FOR_EDICT(entity);
263 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
264 field_mask |= SND_VOLUME;
265 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
266 field_mask |= SND_ATTENUATION;
268 field_mask |= SND_LARGEENTITY;
269 if (sound_num >= 256 || channel >= 8)
270 field_mask |= SND_LARGESOUND;
272 // directed messages go only to the entity they are targeted on
273 MSG_WriteByte (&sv.datagram, svc_sound);
274 MSG_WriteByte (&sv.datagram, field_mask);
275 if (field_mask & SND_VOLUME)
276 MSG_WriteByte (&sv.datagram, volume);
277 if (field_mask & SND_ATTENUATION)
278 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
279 if (field_mask & SND_LARGEENTITY)
281 MSG_WriteShort (&sv.datagram, ent);
282 MSG_WriteByte (&sv.datagram, channel);
285 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
286 if (field_mask & SND_LARGESOUND)
287 MSG_WriteShort (&sv.datagram, sound_num);
289 MSG_WriteByte (&sv.datagram, sound_num);
290 for (i = 0;i < 3;i++)
291 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
295 ==============================================================================
299 ==============================================================================
302 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
303 extern cvar_t csqc_progcrc;
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 (FS_FileExists(csqc_progname.string))
355 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
356 //[515]: init stufftext string (it is sent before svc_serverinfo)
357 val = PRVM_GETGLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset("SV_InitCmd"));
359 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n%s\n", csqc_progcrc.integer, PRVM_GetString(val->string)));
361 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", csqc_progcrc.integer));
364 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
365 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
366 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
368 if (!coop.integer && deathmatch.integer)
369 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
371 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
373 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
375 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
376 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
377 MSG_WriteByte (&client->netconnection->message, 0);
379 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
380 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
381 MSG_WriteByte (&client->netconnection->message, 0);
384 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
385 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
386 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
389 MSG_WriteByte (&client->netconnection->message, svc_setview);
390 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
392 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
393 MSG_WriteByte (&client->netconnection->message, 1);
398 host_client = client;
399 Curl_SendRequirements();
403 client->spawned = false; // need prespawn, spawn, etc
410 Initializes a client_t for a new net connection. This will only be called
411 once for a player each game, not once for each level change.
414 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
418 float spawn_parms[NUM_SPAWN_PARMS];
420 client = svs.clients + clientnum;
422 if(netconnection)//[515]: bots don't play with csqc =)
423 EntityFrameCSQC_InitClientVersions(clientnum, false);
425 // set up the client_t
427 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
428 memset (client, 0, sizeof(*client));
429 client->active = true;
430 client->netconnection = netconnection;
432 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
434 strlcpy(client->name, "unconnected", sizeof(client->name));
435 strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
436 client->spawned = false;
437 client->edict = PRVM_EDICT_NUM(clientnum+1);
438 if (client->netconnection)
439 client->netconnection->message.allowoverflow = true; // we can catch it
440 // updated by receiving "rate" command from client
441 client->rate = NET_MINRATE;
442 // no limits for local player
443 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
444 client->rate = 1000000000;
445 client->connecttime = realtime;
448 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
451 // call the progs to get default spawn parms for the new client
452 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
453 prog->globals.server->self = 0;
454 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
455 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
456 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
458 // set up the entity for this client (including .colormap, .team, etc)
459 PRVM_ED_ClearEdict(client->edict);
462 // don't call SendServerinfo for a fresh botclient because its fields have
463 // not been set up by the qc yet
464 if (client->netconnection)
465 SV_SendServerinfo (client);
467 client->spawned = true;
472 ===============================================================================
476 ===============================================================================
485 void SV_ClearDatagram (void)
487 SZ_Clear (&sv.datagram);
491 =============================================================================
493 The PVS must include a small area around the client to allow head bobbing
494 or other small motion on the client side. Otherwise, a bob might cause an
495 entity that should be visible to not show up, especially when the bob
498 =============================================================================
501 int sv_writeentitiestoclient_pvsbytes;
502 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
504 static int numsendentities;
505 static entity_state_t sendentities[MAX_EDICTS];
506 static entity_state_t *sendentitiesindex[MAX_EDICTS];
508 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
511 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
512 unsigned int customizeentityforclient;
514 vec3_t cullmins, cullmaxs;
518 // EF_NODRAW prevents sending for any reason except for your own
519 // client, so we must keep all clients in this superset
520 effects = (unsigned)ent->fields.server->effects;
522 // we can omit invisible entities with no effects that are not clients
523 // LordHavoc: this could kill tags attached to an invisible entity, I
524 // just hope we never have to support that case
525 i = (int)ent->fields.server->modelindex;
526 modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
529 i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
530 glowsize = (unsigned char)bound(0, i, 255);
531 if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
532 flags |= RENDER_GLOWTRAIL;
534 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
535 light[0] = (unsigned short)bound(0, f, 65535);
536 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
537 light[1] = (unsigned short)bound(0, f, 65535);
538 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
539 light[2] = (unsigned short)bound(0, f, 65535);
540 f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
541 light[3] = (unsigned short)bound(0, f, 65535);
542 lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
543 lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
545 if (gamemode == GAME_TENEBRAE)
547 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
551 lightpflags |= PFLAGS_FULLDYNAMIC;
553 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
557 light[0] = (int)(0.2*256);
558 light[1] = (int)(1.0*256);
559 light[2] = (int)(0.2*256);
561 lightpflags |= PFLAGS_FULLDYNAMIC;
565 specialvisibilityradius = 0;
566 if (lightpflags & PFLAGS_FULLDYNAMIC)
567 specialvisibilityradius = max(specialvisibilityradius, light[3]);
569 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
570 if (flags & RENDER_GLOWTRAIL)
571 specialvisibilityradius = max(specialvisibilityradius, 100);
572 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
574 if (effects & EF_BRIGHTFIELD)
575 specialvisibilityradius = max(specialvisibilityradius, 80);
576 if (effects & EF_MUZZLEFLASH)
577 specialvisibilityradius = max(specialvisibilityradius, 100);
578 if (effects & EF_BRIGHTLIGHT)
579 specialvisibilityradius = max(specialvisibilityradius, 400);
580 if (effects & EF_DIMLIGHT)
581 specialvisibilityradius = max(specialvisibilityradius, 200);
582 if (effects & EF_RED)
583 specialvisibilityradius = max(specialvisibilityradius, 200);
584 if (effects & EF_BLUE)
585 specialvisibilityradius = max(specialvisibilityradius, 200);
586 if (effects & EF_FLAME)
587 specialvisibilityradius = max(specialvisibilityradius, 250);
588 if (effects & EF_STARDUST)
589 specialvisibilityradius = max(specialvisibilityradius, 100);
592 // early culling checks
593 // (final culling is done by SV_MarkWriteEntityStateToClient)
594 customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_customizeentityforclient)->function;
595 if (!customizeentityforclient)
597 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
599 // this 2 billion unit check is actually to detect NAN origins
600 // (we really don't want to send those)
601 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
609 VectorCopy(ent->fields.server->origin, cs->origin);
610 VectorCopy(ent->fields.server->angles, cs->angles);
612 cs->effects = effects;
613 cs->colormap = (unsigned)ent->fields.server->colormap;
614 cs->modelindex = modelindex;
615 cs->skin = (unsigned)ent->fields.server->skin;
616 cs->frame = (unsigned)ent->fields.server->frame;
617 cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict;
618 cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)->edict;
619 cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict;
620 cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict;
621 cs->customizeentityforclient = customizeentityforclient;
622 cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict;
623 cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
624 cs->glowsize = glowsize;
626 // don't need to init cs->colormod because the defaultstate did that for us
627 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
628 val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod);
629 if (val->vector[0] || val->vector[1] || val->vector[2])
631 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
632 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
633 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
636 cs->modelindex = modelindex;
639 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f);
643 cs->alpha = (unsigned char)bound(0, i, 255);
646 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float);
650 cs->alpha = (unsigned char)bound(0, i, 255);
654 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f);
658 cs->scale = (unsigned char)bound(0, i, 255);
662 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_color)->_float);
664 cs->glowcolor = (int)f;
666 if (PRVM_GETEDICTFIELDVALUE(ent, eval_fullbright)->_float)
667 cs->effects |= EF_FULLBRIGHT;
669 if (ent->fields.server->movetype == MOVETYPE_STEP)
670 cs->flags |= RENDER_STEP;
671 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)
672 cs->flags |= RENDER_LOWPRECISION;
673 if (ent->fields.server->colormap >= 1024)
674 cs->flags |= RENDER_COLORMAPPED;
675 if (cs->viewmodelforclient)
676 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
678 cs->light[0] = light[0];
679 cs->light[1] = light[1];
680 cs->light[2] = light[2];
681 cs->light[3] = light[3];
682 cs->lightstyle = lightstyle;
683 cs->lightpflags = lightpflags;
685 cs->specialvisibilityradius = specialvisibilityradius;
687 // calculate the visible box of this entity (don't use the physics box
688 // as that is often smaller than a model, and would not count
689 // specialvisibilityradius)
690 if ((model = sv.models[modelindex]))
692 float scale = cs->scale * (1.0f / 16.0f);
693 if (cs->angles[0] || cs->angles[2]) // pitch and roll
695 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
696 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
698 else if (cs->angles[1])
700 VectorMA(cs->origin, scale, model->yawmins, cullmins);
701 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
705 VectorMA(cs->origin, scale, model->normalmins, cullmins);
706 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
711 // if there is no model (or it could not be loaded), use the physics box
712 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
713 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
715 if (specialvisibilityradius)
717 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
718 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
719 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
720 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
721 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
722 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
724 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
726 VectorCopy(cullmins, ent->priv.server->cullmins);
727 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
728 ent->priv.server->pvs_numclusters = -1;
729 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
731 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
732 if (i <= MAX_ENTITYCLUSTERS)
733 ent->priv.server->pvs_numclusters = i;
740 void SV_PrepareEntitiesForSending(void)
744 // send all entities that touch the pvs
746 sendentitiesindex[0] = NULL;
747 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
748 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
750 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
752 sendentitiesindex[e] = sendentities + numsendentities;
758 static int sententitiesmark = 0;
759 static int sententities[MAX_EDICTS];
760 static int sententitiesconsideration[MAX_EDICTS];
761 static int sv_writeentitiestoclient_culled_pvs;
762 static int sv_writeentitiestoclient_culled_trace;
763 static int sv_writeentitiestoclient_visibleentities;
764 static int sv_writeentitiestoclient_totalentities;
765 //static entity_frame_t sv_writeentitiestoclient_entityframe;
766 static int sv_writeentitiestoclient_clentnum;
767 static vec3_t sv_writeentitiestoclient_testeye;
768 static client_t *sv_writeentitiestoclient_client;
770 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
777 if (sententitiesconsideration[s->number] == sententitiesmark)
779 sententitiesconsideration[s->number] = sententitiesmark;
780 sv_writeentitiestoclient_totalentities++;
782 if (s->customizeentityforclient)
784 prog->globals.server->self = s->number;
785 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
786 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
787 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
791 // never reject player
792 if (s->number != sv_writeentitiestoclient_clentnum)
794 // check various rejection conditions
795 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
797 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
799 if (s->effects & EF_NODRAW)
801 // LordHavoc: only send entities with a model or important effects
802 if (!s->modelindex && s->specialvisibilityradius == 0)
805 // viewmodels don't have visibility checking
806 if (s->viewmodelforclient)
808 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
811 else if (s->tagentity)
813 // tag attached entities simply check their parent
814 if (!sendentitiesindex[s->tagentity])
816 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
817 if (sententities[s->tagentity] != sententitiesmark)
820 // always send world submodels in newer protocols because they don't
821 // generate much traffic (in old protocols they hog bandwidth)
822 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)))
824 // entity has survived every check so far, check if visible
825 ed = PRVM_EDICT_NUM(s->number);
827 // if not touching a visible leaf
828 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
830 if (ed->priv.server->pvs_numclusters < 0)
832 // entity too big for clusters list
833 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
835 sv_writeentitiestoclient_culled_pvs++;
842 // check cached clusters list
843 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
844 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
846 if (i == ed->priv.server->pvs_numclusters)
848 sv_writeentitiestoclient_culled_pvs++;
854 // or not seen by random tracelines
855 if (sv_cullentities_trace.integer && !isbmodel)
857 // LordHavoc: test center first
858 testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
859 testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
860 testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
861 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
862 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
863 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
866 // LordHavoc: test random offsets, to maximize chance of detection
867 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
868 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
869 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
870 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
871 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
872 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
875 if (s->specialvisibilityradius)
877 // LordHavoc: test random offsets, to maximize chance of detection
878 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
879 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
880 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
881 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
882 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
883 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
887 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
889 sv_writeentitiestoclient_culled_trace++;
896 // this just marks it for sending
897 // FIXME: it would be more efficient to send here, but the entity
898 // compressor isn't that flexible
899 sv_writeentitiestoclient_visibleentities++;
900 sententities[s->number] = sententitiesmark;
903 entity_state_t sendstates[MAX_EDICTS];
904 extern int csqc_clent;
906 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
908 int i, numsendstates;
911 // if there isn't enough space to accomplish anything, skip it
912 if (msg->cursize + 25 > msg->maxsize)
915 sv_writeentitiestoclient_client = client;
917 sv_writeentitiestoclient_culled_pvs = 0;
918 sv_writeentitiestoclient_culled_trace = 0;
919 sv_writeentitiestoclient_visibleentities = 0;
920 sv_writeentitiestoclient_totalentities = 0;
922 // find the client's PVS
923 // the real place being tested from
924 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
925 sv_writeentitiestoclient_pvsbytes = 0;
926 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
927 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
929 csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
933 for (i = 0;i < numsendentities;i++)
934 SV_MarkWriteEntityStateToClient(sendentities + i);
937 for (i = 0;i < numsendentities;i++)
939 if (sententities[sendentities[i].number] == sententitiesmark)
941 s = &sendstates[numsendstates++];
942 *s = sendentities[i];
943 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
944 s->flags |= RENDER_EXTERIORMODEL;
948 if (sv_cullentities_stats.integer)
949 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);
951 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
953 if (client->entitydatabase5)
954 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
955 else if (client->entitydatabase4)
956 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
957 else if (client->entitydatabase)
958 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
960 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
969 void SV_CleanupEnts (void)
974 ent = PRVM_NEXT_EDICT(prog->edicts);
975 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
976 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
981 SV_WriteClientdataToMessage
985 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
997 // send a damage message
999 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
1001 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
1002 MSG_WriteByte (msg, svc_damage);
1003 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
1004 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
1005 for (i=0 ; i<3 ; i++)
1006 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
1008 ent->fields.server->dmg_take = 0;
1009 ent->fields.server->dmg_save = 0;
1013 // send the current viewpos offset from the view entity
1015 SV_SetIdealPitch (); // how much to look up / down ideally
1017 // a fixangle might get lost in a dropped packet. Oh well.
1018 if ( ent->fields.server->fixangle )
1020 MSG_WriteByte (msg, svc_setangle);
1021 for (i=0 ; i < 3 ; i++)
1022 MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
1023 ent->fields.server->fixangle = 0;
1026 // stuff the sigil bits into the high bits of items for sbar, or else
1028 val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
1029 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1030 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1032 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1034 VectorClear(punchvector);
1035 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
1036 VectorCopy(val->vector, punchvector);
1038 // cache weapon model name and index in client struct to save time
1039 // (this search can be almost 1% of cpu time!)
1040 s = PRVM_GetString(ent->fields.server->weaponmodel);
1041 if (strcmp(s, client->weaponmodel))
1043 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1044 client->weaponmodelindex = SV_ModelIndex(s, 1);
1048 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
1049 viewzoom = (int)(val->_float * 255.0f);
1055 if ((int)ent->fields.server->flags & FL_ONGROUND)
1056 bits |= SU_ONGROUND;
1057 if (ent->fields.server->waterlevel >= 2)
1059 if (ent->fields.server->idealpitch)
1060 bits |= SU_IDEALPITCH;
1062 for (i=0 ; i<3 ; i++)
1064 if (ent->fields.server->punchangle[i])
1065 bits |= (SU_PUNCH1<<i);
1066 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1068 bits |= (SU_PUNCHVEC1<<i);
1069 if (ent->fields.server->velocity[i])
1070 bits |= (SU_VELOCITY1<<i);
1073 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1074 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1075 stats[STAT_ITEMS] = items;
1076 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1077 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1078 stats[STAT_WEAPON] = client->weaponmodelindex;
1079 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1080 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1081 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1082 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1083 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1084 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1085 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1086 stats[STAT_VIEWZOOM] = viewzoom;
1087 // the QC bumps these itself by sending svc_'s, so we have to keep them
1088 // zero or they'll be corrected by the engine
1089 //stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1090 //stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1091 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1092 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1094 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)
1096 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1098 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1099 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1101 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1102 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1103 if (viewzoom != 255)
1104 bits |= SU_VIEWZOOM;
1109 if (bits >= 16777216)
1113 MSG_WriteByte (msg, svc_clientdata);
1114 MSG_WriteShort (msg, bits);
1115 if (bits & SU_EXTEND1)
1116 MSG_WriteByte(msg, bits >> 16);
1117 if (bits & SU_EXTEND2)
1118 MSG_WriteByte(msg, bits >> 24);
1120 if (bits & SU_VIEWHEIGHT)
1121 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1123 if (bits & SU_IDEALPITCH)
1124 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1126 for (i=0 ; i<3 ; i++)
1128 if (bits & (SU_PUNCH1<<i))
1130 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1131 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1133 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1135 if (bits & (SU_PUNCHVEC1<<i))
1137 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1138 MSG_WriteCoord16i(msg, punchvector[i]);
1140 MSG_WriteCoord32f(msg, punchvector[i]);
1142 if (bits & (SU_VELOCITY1<<i))
1144 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1145 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1147 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1151 if (bits & SU_ITEMS)
1152 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1154 if (sv.protocol == PROTOCOL_DARKPLACES5)
1156 if (bits & SU_WEAPONFRAME)
1157 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1158 if (bits & SU_ARMOR)
1159 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1160 if (bits & SU_WEAPON)
1161 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1162 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1163 MSG_WriteShort (msg, stats[STAT_AMMO]);
1164 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1165 MSG_WriteShort (msg, stats[STAT_NAILS]);
1166 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1167 MSG_WriteShort (msg, stats[STAT_CELLS]);
1168 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1169 if (bits & SU_VIEWZOOM)
1170 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1172 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)
1174 if (bits & SU_WEAPONFRAME)
1175 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1176 if (bits & SU_ARMOR)
1177 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1178 if (bits & SU_WEAPON)
1179 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1180 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1181 MSG_WriteByte (msg, stats[STAT_AMMO]);
1182 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1183 MSG_WriteByte (msg, stats[STAT_NAILS]);
1184 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1185 MSG_WriteByte (msg, stats[STAT_CELLS]);
1186 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1188 for (i = 0;i < 32;i++)
1189 if (stats[STAT_WEAPON] & (1<<i))
1191 MSG_WriteByte (msg, i);
1194 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1195 if (bits & SU_VIEWZOOM)
1197 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1198 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1200 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1206 =======================
1207 SV_SendClientDatagram
1208 =======================
1210 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1211 void SV_SendClientDatagram (client_t *client)
1213 int rate, maxrate, maxsize, maxsize2;
1215 int stats[MAX_CL_STATS];
1217 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1219 // for good singleplayer, send huge packets
1220 maxsize = sizeof(sv_sendclientdatagram_buf);
1221 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1223 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)
1225 // no rate limiting support on older protocols because dp protocols
1226 // 1-4 kick the client off if they overflow, and quake protocol shows
1227 // less than the full entity set if rate limited
1233 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1234 maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE);
1235 if (sv_maxrate.integer != maxrate)
1236 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1238 // this rate limiting does not understand sys_ticrate 0
1239 // (but no one should be running that on a server!)
1240 rate = bound(NET_MINRATE, client->rate, maxrate);
1241 rate = (int)(client->rate * sys_ticrate.value);
1242 maxsize = bound(100, rate, 1400);
1246 msg.data = sv_sendclientdatagram_buf;
1247 msg.maxsize = maxsize;
1250 if (host_client->spawned)
1252 MSG_WriteByte (&msg, svc_time);
1253 MSG_WriteFloat (&msg, sv.time);
1255 // add the client specific data to the datagram
1256 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1257 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1258 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1260 // expand packet size to allow effects to go over the rate limit
1261 // (dropping them is FAR too ugly)
1262 msg.maxsize = maxsize2;
1264 // copy the server datagram if there is space
1265 // FIXME: put in delayed queue of effects to send
1266 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1267 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1269 else if (realtime > client->keepalivetime)
1271 // the player isn't totally in the game yet
1272 // send small keepalive messages if too much time has passed
1273 client->keepalivetime = realtime + 5;
1274 MSG_WriteChar (&msg, svc_nop);
1277 // send the datagram
1278 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1282 =======================
1283 SV_UpdateToReliableMessages
1284 =======================
1286 void SV_UpdateToReliableMessages (void)
1295 // check for changes to be sent over the reliable streams
1296 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1298 // update the host_client fields we care about according to the entity fields
1299 host_client->edict = PRVM_EDICT_NUM(i+1);
1302 name = PRVM_GetString(host_client->edict->fields.server->netname);
1305 // always point the string back at host_client->name to keep it safe
1306 strlcpy (host_client->name, name, sizeof (host_client->name));
1307 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1308 if (strcmp(host_client->old_name, host_client->name))
1310 if (host_client->spawned)
1311 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1312 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1313 // send notification to all clients
1314 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1315 MSG_WriteByte (&sv.reliable_datagram, i);
1316 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1319 // DP_SV_CLIENTCOLORS
1320 // this is always found (since it's added by the progs loader)
1321 if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1322 host_client->colors = (int)val->_float;
1323 if (host_client->old_colors != host_client->colors)
1325 host_client->old_colors = host_client->colors;
1326 // send notification to all clients
1327 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1328 MSG_WriteByte (&sv.reliable_datagram, i);
1329 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1332 // NEXUIZ_PLAYERMODEL
1333 if( eval_playermodel ) {
1334 model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string);
1337 // always point the string back at host_client->name to keep it safe
1338 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1339 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1342 // NEXUIZ_PLAYERSKIN
1343 if( eval_playerskin ) {
1344 skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string);
1347 // always point the string back at host_client->name to keep it safe
1348 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1349 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1353 host_client->frags = (int)host_client->edict->fields.server->frags;
1354 if (host_client->old_frags != host_client->frags)
1356 host_client->old_frags = host_client->frags;
1357 // send notification to all clients
1358 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1359 MSG_WriteByte (&sv.reliable_datagram, i);
1360 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1364 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1365 if (client->netconnection)
1366 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1368 SZ_Clear (&sv.reliable_datagram);
1373 =======================
1374 SV_SendClientMessages
1375 =======================
1377 void SV_SendClientMessages (void)
1379 int i, prepared = false;
1381 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1382 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1384 // update frags, names, etc
1385 SV_UpdateToReliableMessages();
1387 // build individual updates
1388 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1390 if (!host_client->active)
1392 if (!host_client->netconnection)
1395 if (host_client->netconnection->message.overflowed)
1397 SV_DropClient (true); // if the message couldn't send, kick off
1404 // only prepare entities once per frame
1405 SV_PrepareEntitiesForSending();
1407 SV_SendClientDatagram (host_client);
1410 // clear muzzle flashes
1416 ==============================================================================
1420 ==============================================================================
1429 int SV_ModelIndex(const char *s, int precachemode)
1431 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1432 char filename[MAX_QPATH];
1436 //if (precachemode == 2)
1438 strlcpy(filename, s, sizeof(filename));
1439 for (i = 2;i < limit;i++)
1441 if (!sv.model_precache[i][0])
1445 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))
1447 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1450 if (precachemode == 1)
1451 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1452 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1453 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1454 if (sv.state != ss_loading)
1456 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1457 MSG_WriteShort(&sv.reliable_datagram, i);
1458 MSG_WriteString(&sv.reliable_datagram, filename);
1462 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1465 if (!strcmp(sv.model_precache[i], filename))
1468 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1478 int SV_SoundIndex(const char *s, int precachemode)
1480 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1481 char filename[MAX_QPATH];
1485 //if (precachemode == 2)
1487 strlcpy(filename, s, sizeof(filename));
1488 for (i = 1;i < limit;i++)
1490 if (!sv.sound_precache[i][0])
1494 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))
1496 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1499 if (precachemode == 1)
1500 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1501 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1502 if (sv.state != ss_loading)
1504 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1505 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1506 MSG_WriteString(&sv.reliable_datagram, filename);
1510 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1513 if (!strcmp(sv.sound_precache[i], filename))
1516 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1526 void SV_CreateBaseline (void)
1528 int i, entnum, large;
1529 prvm_edict_t *svent;
1531 // LordHavoc: clear *all* states (note just active ones)
1532 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1534 // get the current server version
1535 svent = PRVM_EDICT_NUM(entnum);
1537 // LordHavoc: always clear state values, whether the entity is in use or not
1538 svent->priv.server->baseline = defaultstate;
1540 if (svent->priv.server->free)
1542 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1545 // create entity baseline
1546 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1547 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1548 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1549 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1550 if (entnum > 0 && entnum <= svs.maxclients)
1552 svent->priv.server->baseline.colormap = entnum;
1553 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1557 svent->priv.server->baseline.colormap = 0;
1558 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1562 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1565 // add to the message
1567 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1569 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1570 MSG_WriteShort (&sv.signon, entnum);
1574 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1575 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1579 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1580 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1582 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1583 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1584 for (i=0 ; i<3 ; i++)
1586 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1587 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1597 Grabs the current state of each client for saving across the
1598 transition to another level
1601 void SV_SaveSpawnparms (void)
1605 svs.serverflags = (int)prog->globals.server->serverflags;
1607 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1609 if (!host_client->active)
1612 // call the progs to get default spawn parms for the new client
1613 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1614 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1615 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1616 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1620 void SV_IncreaseEdicts(void)
1624 int oldmax_edicts = prog->max_edicts;
1625 void *oldedictsengineprivate = prog->edictprivate;
1626 void *oldedictsfields = prog->edictsfields;
1627 void *oldmoved_edicts = sv.moved_edicts;
1629 if (prog->max_edicts >= MAX_EDICTS)
1632 // links don't survive the transition, so unlink everything
1633 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1635 if (!ent->priv.server->free)
1636 SV_UnlinkEdict(prog->edicts + i);
1637 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1641 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
1642 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1643 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
1644 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1646 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
1647 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
1649 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1651 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1652 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1653 // link every entity except world
1654 if (!ent->priv.server->free)
1655 SV_LinkEdict(ent, false);
1658 PR_Free(oldedictsengineprivate);
1659 PR_Free(oldedictsfields);
1660 PR_Free(oldmoved_edicts);
1667 This is called at the start of each level
1670 extern float scr_centertime_off;
1672 void SV_SpawnServer (const char *server)
1677 model_t *worldmodel;
1678 char modelname[sizeof(sv.modelname)];
1680 Con_DPrintf("SpawnServer: %s\n", server);
1682 if (cls.state != ca_dedicated)
1683 SCR_BeginLoadingPlaque();
1685 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
1686 worldmodel = Mod_ForName(modelname, false, true, true);
1687 if (!worldmodel || !worldmodel->TraceBox)
1689 Con_Printf("Couldn't load map %s\n", modelname);
1693 // let's not have any servers with no name
1694 if (hostname.string[0] == 0)
1695 Cvar_Set ("hostname", "UNNAMED");
1696 scr_centertime_off = 0;
1698 svs.changelevel_issued = false; // now safe to issue another
1700 // make the map a required file for clients
1701 Curl_ClearRequirements();
1702 Curl_RequireFile(modelname);
1705 // tell all connected clients that we are going to a new level
1710 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1712 if (client->netconnection)
1714 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
1715 MSG_WriteString(&client->netconnection->message, "reconnect\n");
1722 NetConn_OpenServerPorts(true);
1726 // make cvars consistant
1729 Cvar_SetValue ("deathmatch", 0);
1730 // LordHavoc: it can be useful to have skills outside the range 0-3...
1731 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
1732 //Cvar_SetValue ("skill", (float)current_skill);
1733 current_skill = (int)(skill.value + 0.5);
1736 // set up the new server
1738 memset (&sv, 0, sizeof(sv));
1739 // if running a local client, make sure it doesn't try to access the last
1740 // level's data which is no longer valiud
1747 strlcpy (sv.name, server, sizeof (sv.name));
1749 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
1750 if (sv.protocol == PROTOCOL_UNKNOWN)
1753 Protocol_Names(buffer, sizeof(buffer));
1754 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
1755 sv.protocol = PROTOCOL_QUAKE;
1760 // load progs to get entity field count
1761 //PR_LoadProgs ( sv_progs.string );
1763 // allocate server memory
1764 /*// start out with just enough room for clients and a reasonable estimate of entities
1765 prog->max_edicts = max(svs.maxclients + 1, 512);
1766 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
1768 // prvm_edict_t structures (hidden from progs)
1769 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
1770 // engine private structures (hidden from progs)
1771 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1772 // progs fields, often accessed by server
1773 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
1774 // used by PushMove to move back pushed entities
1775 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1776 /*for (i = 0;i < prog->max_edicts;i++)
1778 ent = prog->edicts + i;
1779 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1780 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1783 // reset client csqc entity versions right away.
1784 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1785 EntityFrameCSQC_InitClientVersions(i, true);
1787 sv.datagram.maxsize = sizeof(sv.datagram_buf);
1788 sv.datagram.cursize = 0;
1789 sv.datagram.data = sv.datagram_buf;
1791 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
1792 sv.reliable_datagram.cursize = 0;
1793 sv.reliable_datagram.data = sv.reliable_datagram_buf;
1795 sv.signon.maxsize = sizeof(sv.signon_buf);
1796 sv.signon.cursize = 0;
1797 sv.signon.data = sv.signon_buf;
1799 // leave slots at start for clients only
1800 //prog->num_edicts = svs.maxclients+1;
1802 sv.state = ss_loading;
1803 prog->allowworldwrites = true;
1806 *prog->time = sv.time = 1.0;
1809 worldmodel->used = true;
1811 strlcpy (sv.name, server, sizeof (sv.name));
1812 strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
1813 sv.worldmodel = worldmodel;
1814 sv.models[1] = sv.worldmodel;
1817 // clear world interaction links
1821 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
1823 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
1824 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
1825 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
1827 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
1828 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
1832 // load the rest of the entities
1834 // AK possible hack since num_edicts is still 0
1835 ent = PRVM_EDICT_NUM(0);
1836 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
1837 ent->priv.server->free = false;
1838 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
1839 ent->fields.server->modelindex = 1; // world model
1840 ent->fields.server->solid = SOLID_BSP;
1841 ent->fields.server->movetype = MOVETYPE_PUSH;
1844 prog->globals.server->coop = coop.integer;
1846 prog->globals.server->deathmatch = deathmatch.integer;
1848 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
1850 // serverflags are for cross level information (sigils)
1851 prog->globals.server->serverflags = svs.serverflags;
1853 // we need to reset the spawned flag on all connected clients here so that
1854 // their thinks don't run during startup (before PutClientInServer)
1855 // we also need to set up the client entities now
1856 // and we need to set the ->edict pointers to point into the progs edicts
1857 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1859 host_client->spawned = false;
1860 host_client->edict = PRVM_EDICT_NUM(i + 1);
1861 PRVM_ED_ClearEdict(host_client->edict);
1864 // load replacement entity file if found
1865 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
1867 Con_Printf("Loaded maps/%s.ent\n", sv.name);
1868 PRVM_ED_LoadFromFile (entities);
1872 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
1875 // LordHavoc: clear world angles (to fix e3m3.bsp)
1876 VectorClear(prog->edicts->fields.server->angles);
1878 // all setup is completed, any further precache statements are errors
1879 sv.state = ss_active;
1880 prog->allowworldwrites = false;
1882 // run two frames to allow everything to settle
1883 for (i = 0;i < 2;i++)
1891 // create a baseline for more efficient communications
1892 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1893 SV_CreateBaseline ();
1895 // send serverinfo to all connected clients, and set up botclients coming back from a level change
1896 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1898 if (!host_client->active)
1900 if (host_client->netconnection)
1901 SV_SendServerinfo(host_client);
1905 // if client is a botclient coming from a level change, we need to
1906 // set up client info that normally requires networking
1908 // copy spawn parms out of the client_t
1909 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
1910 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
1912 // call the spawn function
1913 host_client->clientconnectcalled = true;
1914 prog->globals.server->time = sv.time;
1915 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1916 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1917 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1918 host_client->spawned = true;
1922 Con_DPrint("Server spawned.\n");
1923 NetConn_Heartbeat (2);
1928 /////////////////////////////////////////////////////
1931 void SV_VM_CB_BeginIncreaseEdicts(void)
1936 PRVM_Free( sv.moved_edicts );
1937 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1939 // links don't survive the transition, so unlink everything
1940 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1942 if (!ent->priv.server->free)
1943 SV_UnlinkEdict(prog->edicts + i);
1944 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1949 void SV_VM_CB_EndIncreaseEdicts(void)
1954 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1956 // link every entity except world
1957 if (!ent->priv.server->free)
1958 SV_LinkEdict(ent, false);
1962 void SV_VM_CB_InitEdict(prvm_edict_t *e)
1964 // LordHavoc: for consistency set these here
1965 int num = PRVM_NUM_FOR_EDICT(e) - 1;
1967 e->priv.server->move = false; // don't move on first frame
1969 if (num >= 0 && num < svs.maxclients)
1972 // set colormap and team on newly created player entity
1973 e->fields.server->colormap = num + 1;
1974 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
1975 // set netname/clientcolors back to client values so that
1976 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
1978 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
1979 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
1980 val->_float = svs.clients[num].colors;
1981 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
1982 if( eval_playermodel )
1983 PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
1984 if( eval_playerskin )
1985 PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
1989 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
1991 SV_UnlinkEdict (ed); // unlink from world bsp
1993 ed->fields.server->model = 0;
1994 ed->fields.server->takedamage = 0;
1995 ed->fields.server->modelindex = 0;
1996 ed->fields.server->colormap = 0;
1997 ed->fields.server->skin = 0;
1998 ed->fields.server->frame = 0;
1999 VectorClear(ed->fields.server->origin);
2000 VectorClear(ed->fields.server->angles);
2001 ed->fields.server->nextthink = -1;
2002 ed->fields.server->solid = 0;
2005 void SV_VM_CB_CountEdicts(void)
2009 int active, models, solid, step;
2011 active = models = solid = step = 0;
2012 for (i=0 ; i<prog->num_edicts ; i++)
2014 ent = PRVM_EDICT_NUM(i);
2015 if (ent->priv.server->free)
2018 if (ent->fields.server->solid)
2020 if (ent->fields.server->model)
2022 if (ent->fields.server->movetype == MOVETYPE_STEP)
2026 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2027 Con_Printf("active :%3i\n", active);
2028 Con_Printf("view :%3i\n", models);
2029 Con_Printf("touch :%3i\n", solid);
2030 Con_Printf("step :%3i\n", step);
2033 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2035 // remove things from different skill levels or deathmatch
2036 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2038 if (deathmatch.integer)
2040 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2045 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2046 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2047 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2055 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)"};
2056 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2057 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2058 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2059 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2060 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2061 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2062 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2063 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2064 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2065 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2066 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2067 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2068 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2069 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2070 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2071 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2072 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2073 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2074 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2075 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2076 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2077 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2078 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2079 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2080 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2081 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2082 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2083 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2084 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2085 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2086 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2087 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2089 void SV_VM_Init(void)
2091 Cvar_RegisterVariable (&pr_checkextension);
2092 Cvar_RegisterVariable (&nomonsters);
2093 Cvar_RegisterVariable (&gamecfg);
2094 Cvar_RegisterVariable (&scratch1);
2095 Cvar_RegisterVariable (&scratch2);
2096 Cvar_RegisterVariable (&scratch3);
2097 Cvar_RegisterVariable (&scratch4);
2098 Cvar_RegisterVariable (&savedgamecfg);
2099 Cvar_RegisterVariable (&saved1);
2100 Cvar_RegisterVariable (&saved2);
2101 Cvar_RegisterVariable (&saved3);
2102 Cvar_RegisterVariable (&saved4);
2103 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2104 if (gamemode == GAME_NEHAHRA)
2106 Cvar_RegisterVariable (&nehx00);
2107 Cvar_RegisterVariable (&nehx01);
2108 Cvar_RegisterVariable (&nehx02);
2109 Cvar_RegisterVariable (&nehx03);
2110 Cvar_RegisterVariable (&nehx04);
2111 Cvar_RegisterVariable (&nehx05);
2112 Cvar_RegisterVariable (&nehx06);
2113 Cvar_RegisterVariable (&nehx07);
2114 Cvar_RegisterVariable (&nehx08);
2115 Cvar_RegisterVariable (&nehx09);
2116 Cvar_RegisterVariable (&nehx10);
2117 Cvar_RegisterVariable (&nehx11);
2118 Cvar_RegisterVariable (&nehx12);
2119 Cvar_RegisterVariable (&nehx13);
2120 Cvar_RegisterVariable (&nehx14);
2121 Cvar_RegisterVariable (&nehx15);
2122 Cvar_RegisterVariable (&nehx16);
2123 Cvar_RegisterVariable (&nehx17);
2124 Cvar_RegisterVariable (&nehx18);
2125 Cvar_RegisterVariable (&nehx19);
2127 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2130 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
2147 int eval_buttonchat;
2149 int eval_glow_trail;
2150 int eval_glow_color;
2154 int eval_renderamt; // HalfLife support
2155 int eval_rendermode; // HalfLife support
2156 int eval_fullbright;
2157 int eval_ammo_shells1;
2158 int eval_ammo_nails1;
2159 int eval_ammo_lava_nails;
2160 int eval_ammo_rockets1;
2161 int eval_ammo_multi_rockets;
2162 int eval_ammo_cells1;
2163 int eval_ammo_plasma;
2164 int eval_idealpitch;
2165 int eval_pitch_speed;
2166 int eval_viewmodelforclient;
2167 int eval_nodrawtoclient;
2168 int eval_exteriormodeltoclient;
2169 int eval_drawonlytoclient;
2173 int eval_punchvector;
2175 int eval_clientcolors;
2176 int eval_tag_entity;
2182 int eval_cursor_active;
2183 int eval_cursor_screen;
2184 int eval_cursor_trace_start;
2185 int eval_cursor_trace_endpos;
2186 int eval_cursor_trace_ent;
2188 int eval_playermodel;
2189 int eval_playerskin;
2190 int eval_SendEntity;
2192 int eval_customizeentityforclient;
2193 int eval_dphitcontentsmask;
2195 int gval_trace_dpstartcontents;
2196 int gval_trace_dphitcontents;
2197 int gval_trace_dphitq3surfaceflags;
2198 int gval_trace_dphittexturename;
2200 mfunction_t *SV_PlayerPhysicsQC;
2201 mfunction_t *EndFrameQC;
2202 //KrimZon - SERVER COMMANDS IN QUAKEC
2203 mfunction_t *SV_ParseClientCommandQC;
2205 void SV_VM_FindEdictFieldOffsets(void)
2207 eval_gravity = PRVM_ED_FindFieldOffset("gravity");
2208 eval_button3 = PRVM_ED_FindFieldOffset("button3");
2209 eval_button4 = PRVM_ED_FindFieldOffset("button4");
2210 eval_button5 = PRVM_ED_FindFieldOffset("button5");
2211 eval_button6 = PRVM_ED_FindFieldOffset("button6");
2212 eval_button7 = PRVM_ED_FindFieldOffset("button7");
2213 eval_button8 = PRVM_ED_FindFieldOffset("button8");
2214 eval_button9 = PRVM_ED_FindFieldOffset("button9");
2215 eval_button10 = PRVM_ED_FindFieldOffset("button10");
2216 eval_button11 = PRVM_ED_FindFieldOffset("button11");
2217 eval_button12 = PRVM_ED_FindFieldOffset("button12");
2218 eval_button13 = PRVM_ED_FindFieldOffset("button13");
2219 eval_button14 = PRVM_ED_FindFieldOffset("button14");
2220 eval_button15 = PRVM_ED_FindFieldOffset("button15");
2221 eval_button16 = PRVM_ED_FindFieldOffset("button16");
2222 eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
2223 eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
2224 eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
2225 eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
2226 eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
2227 eval_items2 = PRVM_ED_FindFieldOffset("items2");
2228 eval_scale = PRVM_ED_FindFieldOffset("scale");
2229 eval_alpha = PRVM_ED_FindFieldOffset("alpha");
2230 eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
2231 eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
2232 eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
2233 eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
2234 eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
2235 eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
2236 eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
2237 eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
2238 eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
2239 eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
2240 eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
2241 eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
2242 eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
2243 eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
2244 eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
2245 eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
2246 eval_ping = PRVM_ED_FindFieldOffset("ping");
2247 eval_movement = PRVM_ED_FindFieldOffset("movement");
2248 eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
2249 eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
2250 eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
2251 eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
2252 eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
2253 eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
2254 eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
2255 eval_color = PRVM_ED_FindFieldOffset("color");
2256 eval_style = PRVM_ED_FindFieldOffset("style");
2257 eval_pflags = PRVM_ED_FindFieldOffset("pflags");
2258 eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
2259 eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
2260 eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
2261 eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
2262 eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
2263 eval_colormod = PRVM_ED_FindFieldOffset("colormod");
2264 eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
2265 eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
2266 eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
2267 eval_Version = PRVM_ED_FindFieldOffset("Version");
2268 eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
2269 eval_dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
2271 // LordHavoc: allowing QuakeC to override the player movement code
2272 SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
2273 // LordHavoc: support for endframe
2274 EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
2275 //KrimZon - SERVER COMMANDS IN QUAKEC
2276 SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
2277 gval_trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
2278 gval_trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
2279 gval_trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
2280 gval_trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
2283 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2285 prvm_required_field_t reqfields[] =
2287 {ev_entity, "cursor_trace_ent"},
2288 {ev_entity, "drawonlytoclient"},
2289 {ev_entity, "exteriormodeltoclient"},
2290 {ev_entity, "nodrawtoclient"},
2291 {ev_entity, "tag_entity"},
2292 {ev_entity, "viewmodelforclient"},
2293 {ev_float, "alpha"},
2294 {ev_float, "ammo_cells1"},
2295 {ev_float, "ammo_lava_nails"},
2296 {ev_float, "ammo_multi_rockets"},
2297 {ev_float, "ammo_nails1"},
2298 {ev_float, "ammo_plasma"},
2299 {ev_float, "ammo_rockets1"},
2300 {ev_float, "ammo_shells1"},
2301 {ev_float, "button3"},
2302 {ev_float, "button4"},
2303 {ev_float, "button5"},
2304 {ev_float, "button6"},
2305 {ev_float, "button7"},
2306 {ev_float, "button8"},
2307 {ev_float, "button9"},
2308 {ev_float, "button10"},
2309 {ev_float, "button11"},
2310 {ev_float, "button12"},
2311 {ev_float, "button13"},
2312 {ev_float, "button14"},
2313 {ev_float, "button15"},
2314 {ev_float, "button16"},
2315 {ev_float, "buttonchat"},
2316 {ev_float, "buttonuse"},
2317 {ev_float, "clientcolors"},
2318 {ev_float, "cursor_active"},
2319 {ev_float, "fullbright"},
2320 {ev_float, "glow_color"},
2321 {ev_float, "glow_size"},
2322 {ev_float, "glow_trail"},
2323 {ev_float, "gravity"},
2324 {ev_float, "idealpitch"},
2325 {ev_float, "items2"},
2326 {ev_float, "light_lev"},
2327 {ev_float, "pflags"},
2329 {ev_float, "pitch_speed"},
2330 {ev_float, "pmodel"},
2331 {ev_float, "renderamt"}, // HalfLife support
2332 {ev_float, "rendermode"}, // HalfLife support
2333 {ev_float, "scale"},
2334 {ev_float, "style"},
2335 {ev_float, "tag_index"},
2336 {ev_float, "Version"},
2337 {ev_float, "viewzoom"},
2338 {ev_vector, "color"},
2339 {ev_vector, "colormod"},
2340 {ev_vector, "cursor_screen"},
2341 {ev_vector, "cursor_trace_endpos"},
2342 {ev_vector, "cursor_trace_start"},
2343 {ev_vector, "movement"},
2344 {ev_vector, "punchvector"},
2345 {ev_string, "playermodel"},
2346 {ev_string, "playerskin"},
2347 {ev_function, "SendEntity"},
2348 {ev_function, "customizeentityforclient"},
2351 void SV_VM_Setup(void)
2353 unsigned char *csprogsdata;
2354 fs_offset_t csprogsdatasize;
2355 unsigned int csprogsdatacrc;
2357 PRVM_InitProg( PRVM_SERVERPROG );
2359 // allocate the mempools
2360 // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
2361 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2362 prog->builtins = vm_sv_builtins;
2363 prog->numbuiltins = vm_sv_numbuiltins;
2364 prog->headercrc = PROGHEADER_CRC;
2365 prog->max_edicts = 512;
2366 prog->limit_edicts = MAX_EDICTS;
2367 prog->reserved_edicts = svs.maxclients;
2368 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2369 prog->name = "server";
2370 prog->extensionstring = vm_sv_extensions;
2371 prog->loadintoworld = true;
2373 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2374 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2375 prog->init_edict = SV_VM_CB_InitEdict;
2376 prog->free_edict = SV_VM_CB_FreeEdict;
2377 prog->count_edicts = SV_VM_CB_CountEdicts;
2378 prog->load_edict = SV_VM_CB_LoadEdict;
2379 prog->init_cmd = VM_SV_Cmd_Init;
2380 prog->reset_cmd = VM_SV_Cmd_Reset;
2381 prog->error_cmd = Host_Error;
2383 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2384 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
2385 SV_VM_FindEdictFieldOffsets();
2387 VM_AutoSentStats_Clear();//[515]: csqc
2388 EntityFrameCSQC_ClearVersions();//[515]: csqc
2392 // 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
2394 csprogsdata = FS_LoadFile(csqc_progname.string, tempmempool, true, &csprogsdatasize);
2397 csprogsdatacrc = CRC_Block(csprogsdata, csprogsdatasize);
2398 Mem_Free(csprogsdata);
2400 Cvar_SetValueQuick(&csqc_progcrc, csprogsdatacrc);
2403 void SV_VM_Begin(void)
2406 PRVM_SetProg( PRVM_SERVERPROG );
2408 *prog->time = (float) sv.time;
2411 void SV_VM_End(void)