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; //[515]: csqc crc check and right csprogs name according to progs.dat
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 ==============================================================================
306 Sends the first message from the server to a connected client.
307 This will be sent on the initial connection and upon each server load.
310 void SV_SendServerinfo (client_t *client)
315 // we know that this client has a netconnection and thus is not a bot
317 // edicts get reallocated on level changes, so we need to update it here
318 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
320 // clear cached stuff that depends on the level
321 client->weaponmodel[0] = 0;
322 client->weaponmodelindex = 0;
324 // LordHavoc: clear entityframe tracking
325 client->latestframenum = 0;
327 if (client->entitydatabase)
328 EntityFrame_FreeDatabase(client->entitydatabase);
329 if (client->entitydatabase4)
330 EntityFrame4_FreeDatabase(client->entitydatabase4);
331 if (client->entitydatabase5)
332 EntityFrame5_FreeDatabase(client->entitydatabase5);
334 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
336 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
337 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
338 else if (sv.protocol == PROTOCOL_DARKPLACES4)
339 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
341 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
344 SZ_Clear (&client->netconnection->message);
345 MSG_WriteByte (&client->netconnection->message, svc_print);
346 dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
347 MSG_WriteString (&client->netconnection->message,message);
349 //[515]: init csprogs according to version of svprogs, check the crc, etc.
350 if (sv.csqc_progcrc >= 0)
353 Con_DPrintf("sending csqc info to client (\"%s\" with crc %i)\n", sv.csqc_progname, sv.csqc_progcrc);
354 //[515]: init stufftext string (it is sent before svc_serverinfo)
355 val = PRVM_GETGLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset("SV_InitCmd"));
356 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
357 MSG_WriteString (&client->netconnection->message, va("csqc_progname %s\n", sv.csqc_progname));
358 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
359 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", sv.csqc_progcrc));
362 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
363 MSG_WriteString (&client->netconnection->message, va("%s\n", PRVM_GetString(val->string)));
367 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
368 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
369 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
371 if (!coop.integer && deathmatch.integer)
372 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
374 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
376 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
378 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
379 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
380 MSG_WriteByte (&client->netconnection->message, 0);
382 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
383 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
384 MSG_WriteByte (&client->netconnection->message, 0);
387 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
388 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
389 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
392 MSG_WriteByte (&client->netconnection->message, svc_setview);
393 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
395 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
396 MSG_WriteByte (&client->netconnection->message, 1);
401 host_client = client;
402 Curl_SendRequirements();
406 client->spawned = false; // need prespawn, spawn, etc
413 Initializes a client_t for a new net connection. This will only be called
414 once for a player each game, not once for each level change.
417 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
421 float spawn_parms[NUM_SPAWN_PARMS];
423 client = svs.clients + clientnum;
425 if(netconnection)//[515]: bots don't play with csqc =)
426 EntityFrameCSQC_InitClientVersions(clientnum, false);
428 // set up the client_t
430 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
431 memset (client, 0, sizeof(*client));
432 client->active = true;
433 client->netconnection = netconnection;
435 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
437 strlcpy(client->name, "unconnected", sizeof(client->name));
438 strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
439 client->spawned = false;
440 client->edict = PRVM_EDICT_NUM(clientnum+1);
441 if (client->netconnection)
442 client->netconnection->message.allowoverflow = true; // we can catch it
443 // updated by receiving "rate" command from client
444 client->rate = NET_MINRATE;
445 // no limits for local player
446 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
447 client->rate = 1000000000;
448 client->connecttime = realtime;
451 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
454 // call the progs to get default spawn parms for the new client
455 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
456 prog->globals.server->self = 0;
457 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
458 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
459 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
461 // set up the entity for this client (including .colormap, .team, etc)
462 PRVM_ED_ClearEdict(client->edict);
465 // don't call SendServerinfo for a fresh botclient because its fields have
466 // not been set up by the qc yet
467 if (client->netconnection)
468 SV_SendServerinfo (client);
470 client->spawned = true;
475 ===============================================================================
479 ===============================================================================
488 void SV_ClearDatagram (void)
490 SZ_Clear (&sv.datagram);
494 =============================================================================
496 The PVS must include a small area around the client to allow head bobbing
497 or other small motion on the client side. Otherwise, a bob might cause an
498 entity that should be visible to not show up, especially when the bob
501 =============================================================================
504 int sv_writeentitiestoclient_pvsbytes;
505 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
507 static int numsendentities;
508 static entity_state_t sendentities[MAX_EDICTS];
509 static entity_state_t *sendentitiesindex[MAX_EDICTS];
511 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
514 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
515 unsigned int customizeentityforclient;
517 vec3_t cullmins, cullmaxs;
521 // EF_NODRAW prevents sending for any reason except for your own
522 // client, so we must keep all clients in this superset
523 effects = (unsigned)ent->fields.server->effects;
525 // we can omit invisible entities with no effects that are not clients
526 // LordHavoc: this could kill tags attached to an invisible entity, I
527 // just hope we never have to support that case
528 i = (int)ent->fields.server->modelindex;
529 modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
532 i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
533 glowsize = (unsigned char)bound(0, i, 255);
534 if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
535 flags |= RENDER_GLOWTRAIL;
537 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
538 light[0] = (unsigned short)bound(0, f, 65535);
539 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
540 light[1] = (unsigned short)bound(0, f, 65535);
541 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
542 light[2] = (unsigned short)bound(0, f, 65535);
543 f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
544 light[3] = (unsigned short)bound(0, f, 65535);
545 lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
546 lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
548 if (gamemode == GAME_TENEBRAE)
550 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
554 lightpflags |= PFLAGS_FULLDYNAMIC;
556 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
560 light[0] = (int)(0.2*256);
561 light[1] = (int)(1.0*256);
562 light[2] = (int)(0.2*256);
564 lightpflags |= PFLAGS_FULLDYNAMIC;
568 specialvisibilityradius = 0;
569 if (lightpflags & PFLAGS_FULLDYNAMIC)
570 specialvisibilityradius = max(specialvisibilityradius, light[3]);
572 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
573 if (flags & RENDER_GLOWTRAIL)
574 specialvisibilityradius = max(specialvisibilityradius, 100);
575 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
577 if (effects & EF_BRIGHTFIELD)
578 specialvisibilityradius = max(specialvisibilityradius, 80);
579 if (effects & EF_MUZZLEFLASH)
580 specialvisibilityradius = max(specialvisibilityradius, 100);
581 if (effects & EF_BRIGHTLIGHT)
582 specialvisibilityradius = max(specialvisibilityradius, 400);
583 if (effects & EF_DIMLIGHT)
584 specialvisibilityradius = max(specialvisibilityradius, 200);
585 if (effects & EF_RED)
586 specialvisibilityradius = max(specialvisibilityradius, 200);
587 if (effects & EF_BLUE)
588 specialvisibilityradius = max(specialvisibilityradius, 200);
589 if (effects & EF_FLAME)
590 specialvisibilityradius = max(specialvisibilityradius, 250);
591 if (effects & EF_STARDUST)
592 specialvisibilityradius = max(specialvisibilityradius, 100);
595 // early culling checks
596 // (final culling is done by SV_MarkWriteEntityStateToClient)
597 customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_customizeentityforclient)->function;
598 if (!customizeentityforclient)
600 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
602 // this 2 billion unit check is actually to detect NAN origins
603 // (we really don't want to send those)
604 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
612 VectorCopy(ent->fields.server->origin, cs->origin);
613 VectorCopy(ent->fields.server->angles, cs->angles);
615 cs->effects = effects;
616 cs->colormap = (unsigned)ent->fields.server->colormap;
617 cs->modelindex = modelindex;
618 cs->skin = (unsigned)ent->fields.server->skin;
619 cs->frame = (unsigned)ent->fields.server->frame;
620 cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict;
621 cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)->edict;
622 cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict;
623 cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict;
624 cs->customizeentityforclient = customizeentityforclient;
625 cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict;
626 cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
627 cs->glowsize = glowsize;
629 // don't need to init cs->colormod because the defaultstate did that for us
630 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
631 val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod);
632 if (val->vector[0] || val->vector[1] || val->vector[2])
634 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
635 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
636 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
639 cs->modelindex = modelindex;
642 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f);
646 cs->alpha = (unsigned char)bound(0, i, 255);
649 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float);
653 cs->alpha = (unsigned char)bound(0, i, 255);
657 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f);
661 cs->scale = (unsigned char)bound(0, i, 255);
665 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_color)->_float);
667 cs->glowcolor = (int)f;
669 if (PRVM_GETEDICTFIELDVALUE(ent, eval_fullbright)->_float)
670 cs->effects |= EF_FULLBRIGHT;
672 if (ent->fields.server->movetype == MOVETYPE_STEP)
673 cs->flags |= RENDER_STEP;
674 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)
675 cs->flags |= RENDER_LOWPRECISION;
676 if (ent->fields.server->colormap >= 1024)
677 cs->flags |= RENDER_COLORMAPPED;
678 if (cs->viewmodelforclient)
679 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
681 cs->light[0] = light[0];
682 cs->light[1] = light[1];
683 cs->light[2] = light[2];
684 cs->light[3] = light[3];
685 cs->lightstyle = lightstyle;
686 cs->lightpflags = lightpflags;
688 cs->specialvisibilityradius = specialvisibilityradius;
690 // calculate the visible box of this entity (don't use the physics box
691 // as that is often smaller than a model, and would not count
692 // specialvisibilityradius)
693 if ((model = sv.models[modelindex]))
695 float scale = cs->scale * (1.0f / 16.0f);
696 if (cs->angles[0] || cs->angles[2]) // pitch and roll
698 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
699 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
701 else if (cs->angles[1])
703 VectorMA(cs->origin, scale, model->yawmins, cullmins);
704 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
708 VectorMA(cs->origin, scale, model->normalmins, cullmins);
709 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
714 // if there is no model (or it could not be loaded), use the physics box
715 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
716 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
718 if (specialvisibilityradius)
720 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
721 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
722 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
723 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
724 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
725 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
727 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
729 VectorCopy(cullmins, ent->priv.server->cullmins);
730 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
731 ent->priv.server->pvs_numclusters = -1;
732 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
734 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
735 if (i <= MAX_ENTITYCLUSTERS)
736 ent->priv.server->pvs_numclusters = i;
743 void SV_PrepareEntitiesForSending(void)
747 // send all entities that touch the pvs
749 sendentitiesindex[0] = NULL;
750 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
751 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
753 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
755 sendentitiesindex[e] = sendentities + numsendentities;
761 static int sententitiesmark = 0;
762 static int sententities[MAX_EDICTS];
763 static int sententitiesconsideration[MAX_EDICTS];
764 static int sv_writeentitiestoclient_culled_pvs;
765 static int sv_writeentitiestoclient_culled_trace;
766 static int sv_writeentitiestoclient_visibleentities;
767 static int sv_writeentitiestoclient_totalentities;
768 //static entity_frame_t sv_writeentitiestoclient_entityframe;
769 static int sv_writeentitiestoclient_clentnum;
770 static vec3_t sv_writeentitiestoclient_testeye;
771 static client_t *sv_writeentitiestoclient_client;
773 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
780 if (sententitiesconsideration[s->number] == sententitiesmark)
782 sententitiesconsideration[s->number] = sententitiesmark;
783 sv_writeentitiestoclient_totalentities++;
785 if (s->customizeentityforclient)
787 prog->globals.server->self = s->number;
788 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
789 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
790 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
794 // never reject player
795 if (s->number != sv_writeentitiestoclient_clentnum)
797 // check various rejection conditions
798 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
800 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
802 if (s->effects & EF_NODRAW)
804 // LordHavoc: only send entities with a model or important effects
805 if (!s->modelindex && s->specialvisibilityradius == 0)
808 // viewmodels don't have visibility checking
809 if (s->viewmodelforclient)
811 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
814 else if (s->tagentity)
816 // tag attached entities simply check their parent
817 if (!sendentitiesindex[s->tagentity])
819 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
820 if (sententities[s->tagentity] != sententitiesmark)
823 // always send world submodels in newer protocols because they don't
824 // generate much traffic (in old protocols they hog bandwidth)
825 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)))
827 // entity has survived every check so far, check if visible
828 ed = PRVM_EDICT_NUM(s->number);
830 // if not touching a visible leaf
831 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
833 if (ed->priv.server->pvs_numclusters < 0)
835 // entity too big for clusters list
836 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
838 sv_writeentitiestoclient_culled_pvs++;
845 // check cached clusters list
846 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
847 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
849 if (i == ed->priv.server->pvs_numclusters)
851 sv_writeentitiestoclient_culled_pvs++;
857 // or not seen by random tracelines
858 if (sv_cullentities_trace.integer && !isbmodel)
860 // LordHavoc: test center first
861 testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
862 testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
863 testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
864 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
865 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
866 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
869 // LordHavoc: test random offsets, to maximize chance of detection
870 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
871 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
872 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
873 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
874 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
875 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
878 if (s->specialvisibilityradius)
880 // LordHavoc: test random offsets, to maximize chance of detection
881 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
882 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
883 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
884 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
885 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
886 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
890 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
892 sv_writeentitiestoclient_culled_trace++;
899 // this just marks it for sending
900 // FIXME: it would be more efficient to send here, but the entity
901 // compressor isn't that flexible
902 sv_writeentitiestoclient_visibleentities++;
903 sententities[s->number] = sententitiesmark;
906 entity_state_t sendstates[MAX_EDICTS];
907 extern int csqc_clent;
909 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
911 int i, numsendstates;
914 // if there isn't enough space to accomplish anything, skip it
915 if (msg->cursize + 25 > msg->maxsize)
918 sv_writeentitiestoclient_client = client;
920 sv_writeentitiestoclient_culled_pvs = 0;
921 sv_writeentitiestoclient_culled_trace = 0;
922 sv_writeentitiestoclient_visibleentities = 0;
923 sv_writeentitiestoclient_totalentities = 0;
925 // find the client's PVS
926 // the real place being tested from
927 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
928 sv_writeentitiestoclient_pvsbytes = 0;
929 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
930 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
932 csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
936 for (i = 0;i < numsendentities;i++)
937 SV_MarkWriteEntityStateToClient(sendentities + i);
940 for (i = 0;i < numsendentities;i++)
942 if (sententities[sendentities[i].number] == sententitiesmark)
944 s = &sendstates[numsendstates++];
945 *s = sendentities[i];
946 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
947 s->flags |= RENDER_EXTERIORMODEL;
951 if (sv_cullentities_stats.integer)
952 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);
954 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
956 if (client->entitydatabase5)
957 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
958 else if (client->entitydatabase4)
959 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
960 else if (client->entitydatabase)
961 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
963 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
972 void SV_CleanupEnts (void)
977 ent = PRVM_NEXT_EDICT(prog->edicts);
978 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
979 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
984 SV_WriteClientdataToMessage
988 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1000 // send a damage message
1002 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
1004 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
1005 MSG_WriteByte (msg, svc_damage);
1006 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
1007 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
1008 for (i=0 ; i<3 ; i++)
1009 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
1011 ent->fields.server->dmg_take = 0;
1012 ent->fields.server->dmg_save = 0;
1016 // send the current viewpos offset from the view entity
1018 SV_SetIdealPitch (); // how much to look up / down ideally
1020 // a fixangle might get lost in a dropped packet. Oh well.
1021 if ( ent->fields.server->fixangle )
1023 MSG_WriteByte (msg, svc_setangle);
1024 for (i=0 ; i < 3 ; i++)
1025 MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
1026 ent->fields.server->fixangle = 0;
1029 // stuff the sigil bits into the high bits of items for sbar, or else
1031 val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
1032 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1033 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1035 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1037 VectorClear(punchvector);
1038 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
1039 VectorCopy(val->vector, punchvector);
1041 // cache weapon model name and index in client struct to save time
1042 // (this search can be almost 1% of cpu time!)
1043 s = PRVM_GetString(ent->fields.server->weaponmodel);
1044 if (strcmp(s, client->weaponmodel))
1046 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1047 client->weaponmodelindex = SV_ModelIndex(s, 1);
1051 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
1052 viewzoom = (int)(val->_float * 255.0f);
1058 if ((int)ent->fields.server->flags & FL_ONGROUND)
1059 bits |= SU_ONGROUND;
1060 if (ent->fields.server->waterlevel >= 2)
1062 if (ent->fields.server->idealpitch)
1063 bits |= SU_IDEALPITCH;
1065 for (i=0 ; i<3 ; i++)
1067 if (ent->fields.server->punchangle[i])
1068 bits |= (SU_PUNCH1<<i);
1069 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1071 bits |= (SU_PUNCHVEC1<<i);
1072 if (ent->fields.server->velocity[i])
1073 bits |= (SU_VELOCITY1<<i);
1076 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1077 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1078 stats[STAT_ITEMS] = items;
1079 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1080 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1081 stats[STAT_WEAPON] = client->weaponmodelindex;
1082 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1083 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1084 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1085 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1086 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1087 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1088 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1089 stats[STAT_VIEWZOOM] = viewzoom;
1090 // the QC bumps these itself by sending svc_'s, so we have to keep them
1091 // zero or they'll be corrected by the engine
1092 //stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1093 //stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1094 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1095 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1097 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)
1099 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1101 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1102 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1104 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1105 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1106 if (viewzoom != 255)
1107 bits |= SU_VIEWZOOM;
1112 if (bits >= 16777216)
1116 MSG_WriteByte (msg, svc_clientdata);
1117 MSG_WriteShort (msg, bits);
1118 if (bits & SU_EXTEND1)
1119 MSG_WriteByte(msg, bits >> 16);
1120 if (bits & SU_EXTEND2)
1121 MSG_WriteByte(msg, bits >> 24);
1123 if (bits & SU_VIEWHEIGHT)
1124 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1126 if (bits & SU_IDEALPITCH)
1127 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1129 for (i=0 ; i<3 ; i++)
1131 if (bits & (SU_PUNCH1<<i))
1133 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1134 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1136 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1138 if (bits & (SU_PUNCHVEC1<<i))
1140 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1141 MSG_WriteCoord16i(msg, punchvector[i]);
1143 MSG_WriteCoord32f(msg, punchvector[i]);
1145 if (bits & (SU_VELOCITY1<<i))
1147 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1148 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1150 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1154 if (bits & SU_ITEMS)
1155 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1157 if (sv.protocol == PROTOCOL_DARKPLACES5)
1159 if (bits & SU_WEAPONFRAME)
1160 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1161 if (bits & SU_ARMOR)
1162 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1163 if (bits & SU_WEAPON)
1164 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1165 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1166 MSG_WriteShort (msg, stats[STAT_AMMO]);
1167 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1168 MSG_WriteShort (msg, stats[STAT_NAILS]);
1169 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1170 MSG_WriteShort (msg, stats[STAT_CELLS]);
1171 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1172 if (bits & SU_VIEWZOOM)
1173 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1175 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)
1177 if (bits & SU_WEAPONFRAME)
1178 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1179 if (bits & SU_ARMOR)
1180 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1181 if (bits & SU_WEAPON)
1182 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1183 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1184 MSG_WriteByte (msg, stats[STAT_AMMO]);
1185 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1186 MSG_WriteByte (msg, stats[STAT_NAILS]);
1187 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1188 MSG_WriteByte (msg, stats[STAT_CELLS]);
1189 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1191 for (i = 0;i < 32;i++)
1192 if (stats[STAT_WEAPON] & (1<<i))
1194 MSG_WriteByte (msg, i);
1197 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1198 if (bits & SU_VIEWZOOM)
1200 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1201 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1203 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1209 =======================
1210 SV_SendClientDatagram
1211 =======================
1213 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1214 void SV_SendClientDatagram (client_t *client)
1216 int rate, maxrate, maxsize, maxsize2;
1218 int stats[MAX_CL_STATS];
1220 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1222 // for good singleplayer, send huge packets
1223 maxsize = sizeof(sv_sendclientdatagram_buf);
1224 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1226 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)
1228 // no rate limiting support on older protocols because dp protocols
1229 // 1-4 kick the client off if they overflow, and quake protocol shows
1230 // less than the full entity set if rate limited
1236 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1237 maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE);
1238 if (sv_maxrate.integer != maxrate)
1239 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1241 // this rate limiting does not understand sys_ticrate 0
1242 // (but no one should be running that on a server!)
1243 rate = bound(NET_MINRATE, client->rate, maxrate);
1244 rate = (int)(rate * sys_ticrate.value);
1245 maxsize = bound(100, rate, 1400);
1249 msg.data = sv_sendclientdatagram_buf;
1250 msg.maxsize = maxsize;
1253 if (host_client->spawned)
1255 MSG_WriteByte (&msg, svc_time);
1256 MSG_WriteFloat (&msg, sv.time);
1258 // add the client specific data to the datagram
1259 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1260 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1261 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1263 // expand packet size to allow effects to go over the rate limit
1264 // (dropping them is FAR too ugly)
1265 msg.maxsize = maxsize2;
1267 // copy the server datagram if there is space
1268 // FIXME: put in delayed queue of effects to send
1269 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1270 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1272 else if (realtime > client->keepalivetime)
1274 // the player isn't totally in the game yet
1275 // send small keepalive messages if too much time has passed
1276 client->keepalivetime = realtime + 5;
1277 MSG_WriteChar (&msg, svc_nop);
1280 // send the datagram
1281 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1285 =======================
1286 SV_UpdateToReliableMessages
1287 =======================
1289 void SV_UpdateToReliableMessages (void)
1298 // check for changes to be sent over the reliable streams
1299 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1301 // update the host_client fields we care about according to the entity fields
1302 host_client->edict = PRVM_EDICT_NUM(i+1);
1305 name = PRVM_GetString(host_client->edict->fields.server->netname);
1308 // always point the string back at host_client->name to keep it safe
1309 strlcpy (host_client->name, name, sizeof (host_client->name));
1310 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1311 if (strcmp(host_client->old_name, host_client->name))
1313 if (host_client->spawned)
1314 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1315 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1316 // send notification to all clients
1317 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1318 MSG_WriteByte (&sv.reliable_datagram, i);
1319 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1322 // DP_SV_CLIENTCOLORS
1323 // this is always found (since it's added by the progs loader)
1324 if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1325 host_client->colors = (int)val->_float;
1326 if (host_client->old_colors != host_client->colors)
1328 host_client->old_colors = host_client->colors;
1329 // send notification to all clients
1330 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1331 MSG_WriteByte (&sv.reliable_datagram, i);
1332 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1335 // NEXUIZ_PLAYERMODEL
1336 if( eval_playermodel ) {
1337 model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string);
1340 // always point the string back at host_client->name to keep it safe
1341 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1342 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1345 // NEXUIZ_PLAYERSKIN
1346 if( eval_playerskin ) {
1347 skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string);
1350 // always point the string back at host_client->name to keep it safe
1351 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1352 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1356 host_client->frags = (int)host_client->edict->fields.server->frags;
1357 if (host_client->old_frags != host_client->frags)
1359 host_client->old_frags = host_client->frags;
1360 // send notification to all clients
1361 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1362 MSG_WriteByte (&sv.reliable_datagram, i);
1363 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1367 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1368 if (client->netconnection)
1369 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1371 SZ_Clear (&sv.reliable_datagram);
1376 =======================
1377 SV_SendClientMessages
1378 =======================
1380 void SV_SendClientMessages (void)
1382 int i, prepared = false;
1384 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1385 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1387 // update frags, names, etc
1388 SV_UpdateToReliableMessages();
1390 // build individual updates
1391 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1393 if (!host_client->active)
1395 if (!host_client->netconnection)
1398 if (host_client->netconnection->message.overflowed)
1400 SV_DropClient (true); // if the message couldn't send, kick off
1407 // only prepare entities once per frame
1408 SV_PrepareEntitiesForSending();
1410 SV_SendClientDatagram (host_client);
1413 // clear muzzle flashes
1419 ==============================================================================
1423 ==============================================================================
1432 int SV_ModelIndex(const char *s, int precachemode)
1434 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1435 char filename[MAX_QPATH];
1439 //if (precachemode == 2)
1441 strlcpy(filename, s, sizeof(filename));
1442 for (i = 2;i < limit;i++)
1444 if (!sv.model_precache[i][0])
1448 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))
1450 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1453 if (precachemode == 1)
1454 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1455 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1456 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1457 if (sv.state != ss_loading)
1459 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1460 MSG_WriteShort(&sv.reliable_datagram, i);
1461 MSG_WriteString(&sv.reliable_datagram, filename);
1465 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1468 if (!strcmp(sv.model_precache[i], filename))
1471 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1481 int SV_SoundIndex(const char *s, int precachemode)
1483 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1484 char filename[MAX_QPATH];
1488 //if (precachemode == 2)
1490 strlcpy(filename, s, sizeof(filename));
1491 for (i = 1;i < limit;i++)
1493 if (!sv.sound_precache[i][0])
1497 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))
1499 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1502 if (precachemode == 1)
1503 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1504 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1505 if (sv.state != ss_loading)
1507 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1508 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1509 MSG_WriteString(&sv.reliable_datagram, filename);
1513 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1516 if (!strcmp(sv.sound_precache[i], filename))
1519 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1529 void SV_CreateBaseline (void)
1531 int i, entnum, large;
1532 prvm_edict_t *svent;
1534 // LordHavoc: clear *all* states (note just active ones)
1535 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1537 // get the current server version
1538 svent = PRVM_EDICT_NUM(entnum);
1540 // LordHavoc: always clear state values, whether the entity is in use or not
1541 svent->priv.server->baseline = defaultstate;
1543 if (svent->priv.server->free)
1545 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1548 // create entity baseline
1549 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1550 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1551 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1552 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1553 if (entnum > 0 && entnum <= svs.maxclients)
1555 svent->priv.server->baseline.colormap = entnum;
1556 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1560 svent->priv.server->baseline.colormap = 0;
1561 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1565 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1568 // add to the message
1570 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1572 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1573 MSG_WriteShort (&sv.signon, entnum);
1577 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1578 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1582 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1583 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1585 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1586 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1587 for (i=0 ; i<3 ; i++)
1589 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1590 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1600 Grabs the current state of each client for saving across the
1601 transition to another level
1604 void SV_SaveSpawnparms (void)
1608 svs.serverflags = (int)prog->globals.server->serverflags;
1610 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1612 if (!host_client->active)
1615 // call the progs to get default spawn parms for the new client
1616 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1617 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1618 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1619 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1623 void SV_IncreaseEdicts(void)
1627 int oldmax_edicts = prog->max_edicts;
1628 void *oldedictsengineprivate = prog->edictprivate;
1629 void *oldedictsfields = prog->edictsfields;
1630 void *oldmoved_edicts = sv.moved_edicts;
1632 if (prog->max_edicts >= MAX_EDICTS)
1635 // links don't survive the transition, so unlink everything
1636 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1638 if (!ent->priv.server->free)
1639 SV_UnlinkEdict(prog->edicts + i);
1640 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1644 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
1645 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1646 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
1647 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1649 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
1650 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
1652 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1654 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1655 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1656 // link every entity except world
1657 if (!ent->priv.server->free)
1658 SV_LinkEdict(ent, false);
1661 PR_Free(oldedictsengineprivate);
1662 PR_Free(oldedictsfields);
1663 PR_Free(oldmoved_edicts);
1670 This is called at the start of each level
1673 extern float scr_centertime_off;
1675 void SV_SpawnServer (const char *server)
1680 model_t *worldmodel;
1681 char modelname[sizeof(sv.modelname)];
1683 Con_DPrintf("SpawnServer: %s\n", server);
1685 if (cls.state != ca_dedicated)
1686 SCR_BeginLoadingPlaque();
1688 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
1689 worldmodel = Mod_ForName(modelname, false, true, true);
1690 if (!worldmodel || !worldmodel->TraceBox)
1692 Con_Printf("Couldn't load map %s\n", modelname);
1696 // let's not have any servers with no name
1697 if (hostname.string[0] == 0)
1698 Cvar_Set ("hostname", "UNNAMED");
1699 scr_centertime_off = 0;
1701 svs.changelevel_issued = false; // now safe to issue another
1703 // make the map a required file for clients
1704 Curl_ClearRequirements();
1705 Curl_RequireFile(modelname);
1708 // tell all connected clients that we are going to a new level
1713 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1715 if (client->netconnection)
1717 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
1718 MSG_WriteString(&client->netconnection->message, "reconnect\n");
1725 NetConn_OpenServerPorts(true);
1729 // make cvars consistant
1732 Cvar_SetValue ("deathmatch", 0);
1733 // LordHavoc: it can be useful to have skills outside the range 0-3...
1734 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
1735 //Cvar_SetValue ("skill", (float)current_skill);
1736 current_skill = (int)(skill.value + 0.5);
1739 // set up the new server
1741 memset (&sv, 0, sizeof(sv));
1742 // if running a local client, make sure it doesn't try to access the last
1743 // level's data which is no longer valiud
1750 strlcpy (sv.name, server, sizeof (sv.name));
1752 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
1753 if (sv.protocol == PROTOCOL_UNKNOWN)
1756 Protocol_Names(buffer, sizeof(buffer));
1757 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
1758 sv.protocol = PROTOCOL_QUAKE;
1763 // load progs to get entity field count
1764 //PR_LoadProgs ( sv_progs.string );
1766 // allocate server memory
1767 /*// start out with just enough room for clients and a reasonable estimate of entities
1768 prog->max_edicts = max(svs.maxclients + 1, 512);
1769 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
1771 // prvm_edict_t structures (hidden from progs)
1772 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
1773 // engine private structures (hidden from progs)
1774 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1775 // progs fields, often accessed by server
1776 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
1777 // used by PushMove to move back pushed entities
1778 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1779 /*for (i = 0;i < prog->max_edicts;i++)
1781 ent = prog->edicts + i;
1782 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1783 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1786 // reset client csqc entity versions right away.
1787 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1788 EntityFrameCSQC_InitClientVersions(i, true);
1790 sv.datagram.maxsize = sizeof(sv.datagram_buf);
1791 sv.datagram.cursize = 0;
1792 sv.datagram.data = sv.datagram_buf;
1794 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
1795 sv.reliable_datagram.cursize = 0;
1796 sv.reliable_datagram.data = sv.reliable_datagram_buf;
1798 sv.signon.maxsize = sizeof(sv.signon_buf);
1799 sv.signon.cursize = 0;
1800 sv.signon.data = sv.signon_buf;
1802 // leave slots at start for clients only
1803 //prog->num_edicts = svs.maxclients+1;
1805 sv.state = ss_loading;
1806 prog->allowworldwrites = true;
1809 *prog->time = sv.time = 1.0;
1812 worldmodel->used = true;
1814 strlcpy (sv.name, server, sizeof (sv.name));
1815 strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
1816 sv.worldmodel = worldmodel;
1817 sv.models[1] = sv.worldmodel;
1820 // clear world interaction links
1824 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
1826 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
1827 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
1828 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
1830 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
1831 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
1835 // load the rest of the entities
1837 // AK possible hack since num_edicts is still 0
1838 ent = PRVM_EDICT_NUM(0);
1839 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
1840 ent->priv.server->free = false;
1841 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
1842 ent->fields.server->modelindex = 1; // world model
1843 ent->fields.server->solid = SOLID_BSP;
1844 ent->fields.server->movetype = MOVETYPE_PUSH;
1847 prog->globals.server->coop = coop.integer;
1849 prog->globals.server->deathmatch = deathmatch.integer;
1851 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
1853 // serverflags are for cross level information (sigils)
1854 prog->globals.server->serverflags = svs.serverflags;
1856 // we need to reset the spawned flag on all connected clients here so that
1857 // their thinks don't run during startup (before PutClientInServer)
1858 // we also need to set up the client entities now
1859 // and we need to set the ->edict pointers to point into the progs edicts
1860 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1862 host_client->spawned = false;
1863 host_client->edict = PRVM_EDICT_NUM(i + 1);
1864 PRVM_ED_ClearEdict(host_client->edict);
1867 // load replacement entity file if found
1868 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
1870 Con_Printf("Loaded maps/%s.ent\n", sv.name);
1871 PRVM_ED_LoadFromFile (entities);
1875 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
1878 // LordHavoc: clear world angles (to fix e3m3.bsp)
1879 VectorClear(prog->edicts->fields.server->angles);
1881 // all setup is completed, any further precache statements are errors
1882 sv.state = ss_active;
1883 prog->allowworldwrites = false;
1885 // run two frames to allow everything to settle
1886 for (i = 0;i < 2;i++)
1894 // create a baseline for more efficient communications
1895 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1896 SV_CreateBaseline ();
1898 // send serverinfo to all connected clients, and set up botclients coming back from a level change
1899 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1901 if (!host_client->active)
1903 if (host_client->netconnection)
1904 SV_SendServerinfo(host_client);
1908 // if client is a botclient coming from a level change, we need to
1909 // set up client info that normally requires networking
1911 // copy spawn parms out of the client_t
1912 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
1913 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
1915 // call the spawn function
1916 host_client->clientconnectcalled = true;
1917 prog->globals.server->time = sv.time;
1918 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1919 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1920 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1921 host_client->spawned = true;
1925 Con_DPrint("Server spawned.\n");
1926 NetConn_Heartbeat (2);
1931 /////////////////////////////////////////////////////
1934 void SV_VM_CB_BeginIncreaseEdicts(void)
1939 PRVM_Free( sv.moved_edicts );
1940 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1942 // links don't survive the transition, so unlink everything
1943 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1945 if (!ent->priv.server->free)
1946 SV_UnlinkEdict(prog->edicts + i);
1947 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1952 void SV_VM_CB_EndIncreaseEdicts(void)
1957 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1959 // link every entity except world
1960 if (!ent->priv.server->free)
1961 SV_LinkEdict(ent, false);
1965 void SV_VM_CB_InitEdict(prvm_edict_t *e)
1967 // LordHavoc: for consistency set these here
1968 int num = PRVM_NUM_FOR_EDICT(e) - 1;
1970 e->priv.server->move = false; // don't move on first frame
1972 if (num >= 0 && num < svs.maxclients)
1975 // set colormap and team on newly created player entity
1976 e->fields.server->colormap = num + 1;
1977 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
1978 // set netname/clientcolors back to client values so that
1979 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
1981 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
1982 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
1983 val->_float = svs.clients[num].colors;
1984 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
1985 if( eval_playermodel )
1986 PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
1987 if( eval_playerskin )
1988 PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
1992 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
1994 SV_UnlinkEdict (ed); // unlink from world bsp
1996 ed->fields.server->model = 0;
1997 ed->fields.server->takedamage = 0;
1998 ed->fields.server->modelindex = 0;
1999 ed->fields.server->colormap = 0;
2000 ed->fields.server->skin = 0;
2001 ed->fields.server->frame = 0;
2002 VectorClear(ed->fields.server->origin);
2003 VectorClear(ed->fields.server->angles);
2004 ed->fields.server->nextthink = -1;
2005 ed->fields.server->solid = 0;
2008 void SV_VM_CB_CountEdicts(void)
2012 int active, models, solid, step;
2014 active = models = solid = step = 0;
2015 for (i=0 ; i<prog->num_edicts ; i++)
2017 ent = PRVM_EDICT_NUM(i);
2018 if (ent->priv.server->free)
2021 if (ent->fields.server->solid)
2023 if (ent->fields.server->model)
2025 if (ent->fields.server->movetype == MOVETYPE_STEP)
2029 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2030 Con_Printf("active :%3i\n", active);
2031 Con_Printf("view :%3i\n", models);
2032 Con_Printf("touch :%3i\n", solid);
2033 Con_Printf("step :%3i\n", step);
2036 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2038 // remove things from different skill levels or deathmatch
2039 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2041 if (deathmatch.integer)
2043 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2048 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2049 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2050 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2058 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)"};
2059 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2060 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2061 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2062 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2063 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2064 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2065 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2066 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2067 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2068 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2069 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2070 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2071 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2072 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2073 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2074 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2075 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2076 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2077 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2078 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2079 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2080 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2081 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2082 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2083 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2084 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2085 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2086 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2087 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2088 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2089 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2090 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2092 void SV_VM_Init(void)
2094 Cvar_RegisterVariable (&pr_checkextension);
2095 Cvar_RegisterVariable (&nomonsters);
2096 Cvar_RegisterVariable (&gamecfg);
2097 Cvar_RegisterVariable (&scratch1);
2098 Cvar_RegisterVariable (&scratch2);
2099 Cvar_RegisterVariable (&scratch3);
2100 Cvar_RegisterVariable (&scratch4);
2101 Cvar_RegisterVariable (&savedgamecfg);
2102 Cvar_RegisterVariable (&saved1);
2103 Cvar_RegisterVariable (&saved2);
2104 Cvar_RegisterVariable (&saved3);
2105 Cvar_RegisterVariable (&saved4);
2106 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2107 if (gamemode == GAME_NEHAHRA)
2109 Cvar_RegisterVariable (&nehx00);
2110 Cvar_RegisterVariable (&nehx01);
2111 Cvar_RegisterVariable (&nehx02);
2112 Cvar_RegisterVariable (&nehx03);
2113 Cvar_RegisterVariable (&nehx04);
2114 Cvar_RegisterVariable (&nehx05);
2115 Cvar_RegisterVariable (&nehx06);
2116 Cvar_RegisterVariable (&nehx07);
2117 Cvar_RegisterVariable (&nehx08);
2118 Cvar_RegisterVariable (&nehx09);
2119 Cvar_RegisterVariable (&nehx10);
2120 Cvar_RegisterVariable (&nehx11);
2121 Cvar_RegisterVariable (&nehx12);
2122 Cvar_RegisterVariable (&nehx13);
2123 Cvar_RegisterVariable (&nehx14);
2124 Cvar_RegisterVariable (&nehx15);
2125 Cvar_RegisterVariable (&nehx16);
2126 Cvar_RegisterVariable (&nehx17);
2127 Cvar_RegisterVariable (&nehx18);
2128 Cvar_RegisterVariable (&nehx19);
2130 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2133 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
2150 int eval_buttonchat;
2152 int eval_glow_trail;
2153 int eval_glow_color;
2157 int eval_renderamt; // HalfLife support
2158 int eval_rendermode; // HalfLife support
2159 int eval_fullbright;
2160 int eval_ammo_shells1;
2161 int eval_ammo_nails1;
2162 int eval_ammo_lava_nails;
2163 int eval_ammo_rockets1;
2164 int eval_ammo_multi_rockets;
2165 int eval_ammo_cells1;
2166 int eval_ammo_plasma;
2167 int eval_idealpitch;
2168 int eval_pitch_speed;
2169 int eval_viewmodelforclient;
2170 int eval_nodrawtoclient;
2171 int eval_exteriormodeltoclient;
2172 int eval_drawonlytoclient;
2176 int eval_punchvector;
2178 int eval_clientcolors;
2179 int eval_tag_entity;
2185 int eval_cursor_active;
2186 int eval_cursor_screen;
2187 int eval_cursor_trace_start;
2188 int eval_cursor_trace_endpos;
2189 int eval_cursor_trace_ent;
2191 int eval_playermodel;
2192 int eval_playerskin;
2193 int eval_SendEntity;
2195 int eval_customizeentityforclient;
2196 int eval_dphitcontentsmask;
2197 // DRESK - Support for Entity Contents Transition Event
2198 int eval_contentstransition;
2200 int gval_trace_dpstartcontents;
2201 int gval_trace_dphitcontents;
2202 int gval_trace_dphitq3surfaceflags;
2203 int gval_trace_dphittexturename;
2205 mfunction_t *SV_PlayerPhysicsQC;
2206 mfunction_t *EndFrameQC;
2207 //KrimZon - SERVER COMMANDS IN QUAKEC
2208 mfunction_t *SV_ParseClientCommandQC;
2210 void SV_VM_FindEdictFieldOffsets(void)
2212 eval_gravity = PRVM_ED_FindFieldOffset("gravity");
2213 eval_button3 = PRVM_ED_FindFieldOffset("button3");
2214 eval_button4 = PRVM_ED_FindFieldOffset("button4");
2215 eval_button5 = PRVM_ED_FindFieldOffset("button5");
2216 eval_button6 = PRVM_ED_FindFieldOffset("button6");
2217 eval_button7 = PRVM_ED_FindFieldOffset("button7");
2218 eval_button8 = PRVM_ED_FindFieldOffset("button8");
2219 eval_button9 = PRVM_ED_FindFieldOffset("button9");
2220 eval_button10 = PRVM_ED_FindFieldOffset("button10");
2221 eval_button11 = PRVM_ED_FindFieldOffset("button11");
2222 eval_button12 = PRVM_ED_FindFieldOffset("button12");
2223 eval_button13 = PRVM_ED_FindFieldOffset("button13");
2224 eval_button14 = PRVM_ED_FindFieldOffset("button14");
2225 eval_button15 = PRVM_ED_FindFieldOffset("button15");
2226 eval_button16 = PRVM_ED_FindFieldOffset("button16");
2227 eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
2228 eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
2229 eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
2230 eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
2231 eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
2232 eval_items2 = PRVM_ED_FindFieldOffset("items2");
2233 eval_scale = PRVM_ED_FindFieldOffset("scale");
2234 eval_alpha = PRVM_ED_FindFieldOffset("alpha");
2235 eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
2236 eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
2237 eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
2238 eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
2239 eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
2240 eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
2241 eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
2242 eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
2243 eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
2244 eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
2245 eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
2246 eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
2247 eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
2248 eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
2249 eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
2250 eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
2251 eval_ping = PRVM_ED_FindFieldOffset("ping");
2252 eval_movement = PRVM_ED_FindFieldOffset("movement");
2253 eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
2254 eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
2255 eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
2256 eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
2257 eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
2258 eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
2259 eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
2260 eval_color = PRVM_ED_FindFieldOffset("color");
2261 eval_style = PRVM_ED_FindFieldOffset("style");
2262 eval_pflags = PRVM_ED_FindFieldOffset("pflags");
2263 eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
2264 eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
2265 eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
2266 eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
2267 eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
2268 eval_colormod = PRVM_ED_FindFieldOffset("colormod");
2269 eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
2270 eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
2271 eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
2272 eval_Version = PRVM_ED_FindFieldOffset("Version");
2273 eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
2274 eval_dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
2275 // DRESK - Support for Entity Contents Transition Event
2276 eval_contentstransition = PRVM_ED_FindFieldOffset("contentstransition");
2278 // LordHavoc: allowing QuakeC to override the player movement code
2279 SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
2280 // LordHavoc: support for endframe
2281 EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
2282 //KrimZon - SERVER COMMANDS IN QUAKEC
2283 SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
2284 gval_trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
2285 gval_trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
2286 gval_trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
2287 gval_trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
2290 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2292 prvm_required_field_t reqfields[] =
2294 {ev_entity, "cursor_trace_ent"},
2295 {ev_entity, "drawonlytoclient"},
2296 {ev_entity, "exteriormodeltoclient"},
2297 {ev_entity, "nodrawtoclient"},
2298 {ev_entity, "tag_entity"},
2299 {ev_entity, "viewmodelforclient"},
2300 {ev_float, "alpha"},
2301 {ev_float, "ammo_cells1"},
2302 {ev_float, "ammo_lava_nails"},
2303 {ev_float, "ammo_multi_rockets"},
2304 {ev_float, "ammo_nails1"},
2305 {ev_float, "ammo_plasma"},
2306 {ev_float, "ammo_rockets1"},
2307 {ev_float, "ammo_shells1"},
2308 {ev_float, "button3"},
2309 {ev_float, "button4"},
2310 {ev_float, "button5"},
2311 {ev_float, "button6"},
2312 {ev_float, "button7"},
2313 {ev_float, "button8"},
2314 {ev_float, "button9"},
2315 {ev_float, "button10"},
2316 {ev_float, "button11"},
2317 {ev_float, "button12"},
2318 {ev_float, "button13"},
2319 {ev_float, "button14"},
2320 {ev_float, "button15"},
2321 {ev_float, "button16"},
2322 {ev_float, "buttonchat"},
2323 {ev_float, "buttonuse"},
2324 {ev_float, "clientcolors"},
2325 {ev_float, "cursor_active"},
2326 {ev_float, "fullbright"},
2327 {ev_float, "glow_color"},
2328 {ev_float, "glow_size"},
2329 {ev_float, "glow_trail"},
2330 {ev_float, "gravity"},
2331 {ev_float, "idealpitch"},
2332 {ev_float, "items2"},
2333 {ev_float, "light_lev"},
2334 {ev_float, "pflags"},
2336 {ev_float, "pitch_speed"},
2337 {ev_float, "pmodel"},
2338 {ev_float, "renderamt"}, // HalfLife support
2339 {ev_float, "rendermode"}, // HalfLife support
2340 {ev_float, "scale"},
2341 {ev_float, "style"},
2342 {ev_float, "tag_index"},
2343 {ev_float, "Version"},
2344 {ev_float, "viewzoom"},
2345 {ev_vector, "color"},
2346 {ev_vector, "colormod"},
2347 {ev_vector, "cursor_screen"},
2348 {ev_vector, "cursor_trace_endpos"},
2349 {ev_vector, "cursor_trace_start"},
2350 {ev_vector, "movement"},
2351 {ev_vector, "punchvector"},
2352 {ev_string, "playermodel"},
2353 {ev_string, "playerskin"},
2354 {ev_function, "SendEntity"},
2355 {ev_function, "customizeentityforclient"},
2356 // DRESK - Support for Entity Contents Transition Event
2357 {ev_function, "contentstransition"},
2360 void SV_VM_Setup(void)
2362 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
2363 extern cvar_t csqc_progcrc;
2364 unsigned char *csprogsdata;
2365 fs_offset_t csprogsdatasize;
2367 PRVM_InitProg( PRVM_SERVERPROG );
2369 // allocate the mempools
2370 // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
2371 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2372 prog->builtins = vm_sv_builtins;
2373 prog->numbuiltins = vm_sv_numbuiltins;
2374 prog->headercrc = PROGHEADER_CRC;
2375 prog->max_edicts = 512;
2376 prog->limit_edicts = MAX_EDICTS;
2377 prog->reserved_edicts = svs.maxclients;
2378 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2379 prog->name = "server";
2380 prog->extensionstring = vm_sv_extensions;
2381 prog->loadintoworld = true;
2383 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2384 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2385 prog->init_edict = SV_VM_CB_InitEdict;
2386 prog->free_edict = SV_VM_CB_FreeEdict;
2387 prog->count_edicts = SV_VM_CB_CountEdicts;
2388 prog->load_edict = SV_VM_CB_LoadEdict;
2389 prog->init_cmd = VM_SV_Cmd_Init;
2390 prog->reset_cmd = VM_SV_Cmd_Reset;
2391 prog->error_cmd = Host_Error;
2393 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2394 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
2395 SV_VM_FindEdictFieldOffsets();
2397 VM_AutoSentStats_Clear();//[515]: csqc
2398 EntityFrameCSQC_ClearVersions();//[515]: csqc
2402 // 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
2403 sv.csqc_progcrc = -1;
2404 sv.csqc_progname[0] = 0;
2405 csprogsdata = FS_LoadFile(csqc_progname.string, tempmempool, true, &csprogsdatasize);
2408 strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
2409 sv.csqc_progcrc = CRC_Block(csprogsdata, csprogsdatasize);
2410 Mem_Free(csprogsdata);
2411 Con_DPrintf("server detected csqc progs file \"%s\" with crc %i\n", sv.csqc_progname, sv.csqc_progcrc);
2415 void SV_VM_Begin(void)
2418 PRVM_SetProg( PRVM_SERVERPROG );
2420 *prog->time = (float) sv.time;
2423 void SV_VM_End(void)