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 Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
83 Cvar_RegisterVariable (&sv_maxvelocity);
84 Cvar_RegisterVariable (&sv_gravity);
85 Cvar_RegisterVariable (&sv_friction);
86 Cvar_RegisterVariable (&sv_waterfriction);
87 Cvar_RegisterVariable (&sv_edgefriction);
88 Cvar_RegisterVariable (&sv_stopspeed);
89 Cvar_RegisterVariable (&sv_maxspeed);
90 Cvar_RegisterVariable (&sv_maxairspeed);
91 Cvar_RegisterVariable (&sv_accelerate);
92 Cvar_RegisterVariable (&sv_airaccelerate);
93 Cvar_RegisterVariable (&sv_wateraccelerate);
94 Cvar_RegisterVariable (&sv_clmovement_enable);
95 Cvar_RegisterVariable (&sv_clmovement_minping);
96 Cvar_RegisterVariable (&sv_clmovement_minping_disabletime);
97 Cvar_RegisterVariable (&sv_clmovement_waitforinput);
98 Cvar_RegisterVariable (&sv_idealpitchscale);
99 Cvar_RegisterVariable (&sv_aim);
100 Cvar_RegisterVariable (&sv_nostep);
101 Cvar_RegisterVariable (&sv_cullentities_pvs);
102 Cvar_RegisterVariable (&sv_cullentities_trace);
103 Cvar_RegisterVariable (&sv_cullentities_stats);
104 Cvar_RegisterVariable (&sv_entpatch);
105 Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
106 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
107 Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
108 Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
109 Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
110 Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
111 Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
112 Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
113 Cvar_RegisterVariable (&sv_gameplayfix_qwplayerphysics);
114 Cvar_RegisterVariable (&sv_gameplayfix_upwardvelocityclearsongroundflag);
115 Cvar_RegisterVariable (&sv_protocolname);
116 Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
117 Cvar_RegisterVariable (&sv_maxrate);
118 Cvar_RegisterVariable (&sv_progs);
124 sv_mempool = Mem_AllocPool("server", 0, NULL);
127 static void SV_SaveEntFile_f(void)
129 char basename[MAX_QPATH];
130 if (!sv.active || !sv.worldmodel)
132 Con_Print("Not running a server\n");
135 FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
136 FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
141 =============================================================================
145 =============================================================================
152 Make sure the event gets sent to all clients
155 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
159 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
161 MSG_WriteByte (&sv.datagram, svc_particle);
162 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
163 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
164 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
165 for (i=0 ; i<3 ; i++)
166 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
167 MSG_WriteByte (&sv.datagram, count);
168 MSG_WriteByte (&sv.datagram, color);
175 Make sure the event gets sent to all clients
178 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
180 if (modelindex >= 256 || startframe >= 256)
182 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
184 MSG_WriteByte (&sv.datagram, svc_effect2);
185 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
186 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
187 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
188 MSG_WriteShort (&sv.datagram, modelindex);
189 MSG_WriteShort (&sv.datagram, startframe);
190 MSG_WriteByte (&sv.datagram, framecount);
191 MSG_WriteByte (&sv.datagram, framerate);
195 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
197 MSG_WriteByte (&sv.datagram, svc_effect);
198 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
199 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
200 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
201 MSG_WriteByte (&sv.datagram, modelindex);
202 MSG_WriteByte (&sv.datagram, startframe);
203 MSG_WriteByte (&sv.datagram, framecount);
204 MSG_WriteByte (&sv.datagram, framerate);
212 Each entity can have eight independant sound sources, like voice,
215 Channel 0 is an auto-allocate channel, the others override anything
216 already running on that entity/channel pair.
218 An attenuation of 0 will play full volume everywhere in the level.
219 Larger attenuations will drop off. (max 4 attenuation)
223 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
225 int sound_num, field_mask, i, ent;
227 if (volume < 0 || volume > 255)
229 Con_Printf ("SV_StartSound: volume = %i\n", volume);
233 if (attenuation < 0 || attenuation > 4)
235 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
239 if (channel < 0 || channel > 7)
241 Con_Printf ("SV_StartSound: channel = %i\n", channel);
245 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
248 // find precache number for sound
249 sound_num = SV_SoundIndex(sample, 1);
253 ent = PRVM_NUM_FOR_EDICT(entity);
256 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
257 field_mask |= SND_VOLUME;
258 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
259 field_mask |= SND_ATTENUATION;
261 field_mask |= SND_LARGEENTITY;
262 if (sound_num >= 256 || channel >= 8)
263 field_mask |= SND_LARGESOUND;
265 // directed messages go only to the entity they are targeted on
266 MSG_WriteByte (&sv.datagram, svc_sound);
267 MSG_WriteByte (&sv.datagram, field_mask);
268 if (field_mask & SND_VOLUME)
269 MSG_WriteByte (&sv.datagram, volume);
270 if (field_mask & SND_ATTENUATION)
271 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
272 if (field_mask & SND_LARGEENTITY)
274 MSG_WriteShort (&sv.datagram, ent);
275 MSG_WriteByte (&sv.datagram, channel);
278 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
279 if (field_mask & SND_LARGESOUND)
280 MSG_WriteShort (&sv.datagram, sound_num);
282 MSG_WriteByte (&sv.datagram, sound_num);
283 for (i = 0;i < 3;i++)
284 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
288 ==============================================================================
292 ==============================================================================
295 extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
296 extern cvar_t csqc_progcrc;
301 Sends the first message from the server to a connected client.
302 This will be sent on the initial connection and upon each server load.
305 void SV_SendServerinfo (client_t *client)
310 // we know that this client has a netconnection and thus is not a bot
312 // edicts get reallocated on level changes, so we need to update it here
313 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
315 // clear cached stuff that depends on the level
316 client->weaponmodel[0] = 0;
317 client->weaponmodelindex = 0;
319 // LordHavoc: clear entityframe tracking
320 client->latestframenum = 0;
322 if (client->entitydatabase)
323 EntityFrame_FreeDatabase(client->entitydatabase);
324 if (client->entitydatabase4)
325 EntityFrame4_FreeDatabase(client->entitydatabase4);
326 if (client->entitydatabase5)
327 EntityFrame5_FreeDatabase(client->entitydatabase5);
329 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
331 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
332 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
333 else if (sv.protocol == PROTOCOL_DARKPLACES4)
334 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
336 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
339 SZ_Clear (&client->netconnection->message);
340 MSG_WriteByte (&client->netconnection->message, svc_print);
341 dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
342 MSG_WriteString (&client->netconnection->message,message);
344 //[515]: init csprogs according to version of svprogs, check the crc, etc.
345 if (FS_FileExists(csqc_progname.string))
348 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
349 //[515]: init stufftext string (it is sent before svc_serverinfo)
350 val = PRVM_GETGLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset("SV_InitCmd"));
352 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n%s\n", csqc_progcrc.integer, PRVM_GetString(val->string)));
354 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", csqc_progcrc.integer));
357 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
358 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
359 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
361 if (!coop.integer && deathmatch.integer)
362 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
364 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
366 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
368 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
369 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
370 MSG_WriteByte (&client->netconnection->message, 0);
372 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
373 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
374 MSG_WriteByte (&client->netconnection->message, 0);
377 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
378 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
379 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
382 MSG_WriteByte (&client->netconnection->message, svc_setview);
383 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
385 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
386 MSG_WriteByte (&client->netconnection->message, 1);
391 host_client = client;
392 Curl_SendRequirements();
396 client->spawned = false; // need prespawn, spawn, etc
403 Initializes a client_t for a new net connection. This will only be called
404 once for a player each game, not once for each level change.
407 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
411 float spawn_parms[NUM_SPAWN_PARMS];
413 client = svs.clients + clientnum;
415 if(netconnection)//[515]: bots don't play with csqc =)
416 EntityFrameCSQC_InitClientVersions(clientnum, false);
418 // set up the client_t
420 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
421 memset (client, 0, sizeof(*client));
422 client->active = true;
423 client->netconnection = netconnection;
425 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
427 strlcpy(client->name, "unconnected", sizeof(client->name));
428 strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
429 client->spawned = false;
430 client->edict = PRVM_EDICT_NUM(clientnum+1);
431 if (client->netconnection)
432 client->netconnection->message.allowoverflow = true; // we can catch it
433 // updated by receiving "rate" command from client
434 client->rate = NET_MINRATE;
435 // no limits for local player
436 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
437 client->rate = 1000000000;
438 client->connecttime = realtime;
441 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
444 // call the progs to get default spawn parms for the new client
445 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
446 prog->globals.server->self = 0;
447 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
448 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
449 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
451 // set up the entity for this client (including .colormap, .team, etc)
452 PRVM_ED_ClearEdict(client->edict);
455 // don't call SendServerinfo for a fresh botclient because its fields have
456 // not been set up by the qc yet
457 if (client->netconnection)
458 SV_SendServerinfo (client);
460 client->spawned = true;
465 ===============================================================================
469 ===============================================================================
478 void SV_ClearDatagram (void)
480 SZ_Clear (&sv.datagram);
484 =============================================================================
486 The PVS must include a small area around the client to allow head bobbing
487 or other small motion on the client side. Otherwise, a bob might cause an
488 entity that should be visible to not show up, especially when the bob
491 =============================================================================
494 int sv_writeentitiestoclient_pvsbytes;
495 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
497 static int numsendentities;
498 static entity_state_t sendentities[MAX_EDICTS];
499 static entity_state_t *sendentitiesindex[MAX_EDICTS];
501 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
504 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
505 unsigned int customizeentityforclient;
507 vec3_t cullmins, cullmaxs;
511 // EF_NODRAW prevents sending for any reason except for your own
512 // client, so we must keep all clients in this superset
513 effects = (unsigned)ent->fields.server->effects;
515 // we can omit invisible entities with no effects that are not clients
516 // LordHavoc: this could kill tags attached to an invisible entity, I
517 // just hope we never have to support that case
518 i = (int)ent->fields.server->modelindex;
519 modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
522 i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
523 glowsize = (unsigned char)bound(0, i, 255);
524 if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
525 flags |= RENDER_GLOWTRAIL;
527 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
528 light[0] = (unsigned short)bound(0, f, 65535);
529 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
530 light[1] = (unsigned short)bound(0, f, 65535);
531 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
532 light[2] = (unsigned short)bound(0, f, 65535);
533 f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
534 light[3] = (unsigned short)bound(0, f, 65535);
535 lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
536 lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
538 if (gamemode == GAME_TENEBRAE)
540 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
544 lightpflags |= PFLAGS_FULLDYNAMIC;
546 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
550 light[0] = (int)(0.2*256);
551 light[1] = (int)(1.0*256);
552 light[2] = (int)(0.2*256);
554 lightpflags |= PFLAGS_FULLDYNAMIC;
558 specialvisibilityradius = 0;
559 if (lightpflags & PFLAGS_FULLDYNAMIC)
560 specialvisibilityradius = max(specialvisibilityradius, light[3]);
562 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
563 if (flags & RENDER_GLOWTRAIL)
564 specialvisibilityradius = max(specialvisibilityradius, 100);
565 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
567 if (effects & EF_BRIGHTFIELD)
568 specialvisibilityradius = max(specialvisibilityradius, 80);
569 if (effects & EF_MUZZLEFLASH)
570 specialvisibilityradius = max(specialvisibilityradius, 100);
571 if (effects & EF_BRIGHTLIGHT)
572 specialvisibilityradius = max(specialvisibilityradius, 400);
573 if (effects & EF_DIMLIGHT)
574 specialvisibilityradius = max(specialvisibilityradius, 200);
575 if (effects & EF_RED)
576 specialvisibilityradius = max(specialvisibilityradius, 200);
577 if (effects & EF_BLUE)
578 specialvisibilityradius = max(specialvisibilityradius, 200);
579 if (effects & EF_FLAME)
580 specialvisibilityradius = max(specialvisibilityradius, 250);
581 if (effects & EF_STARDUST)
582 specialvisibilityradius = max(specialvisibilityradius, 100);
585 // early culling checks
586 // (final culling is done by SV_MarkWriteEntityStateToClient)
587 customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_customizeentityforclient)->function;
588 if (!customizeentityforclient)
590 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
592 // this 2 billion unit check is actually to detect NAN origins
593 // (we really don't want to send those)
594 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
602 VectorCopy(ent->fields.server->origin, cs->origin);
603 VectorCopy(ent->fields.server->angles, cs->angles);
605 cs->effects = effects;
606 cs->colormap = (unsigned)ent->fields.server->colormap;
607 cs->modelindex = modelindex;
608 cs->skin = (unsigned)ent->fields.server->skin;
609 cs->frame = (unsigned)ent->fields.server->frame;
610 cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict;
611 cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)->edict;
612 cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict;
613 cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict;
614 cs->customizeentityforclient = customizeentityforclient;
615 cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict;
616 cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
617 cs->glowsize = glowsize;
619 // don't need to init cs->colormod because the defaultstate did that for us
620 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
621 val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod);
622 if (val->vector[0] || val->vector[1] || val->vector[2])
624 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
625 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
626 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
629 cs->modelindex = modelindex;
632 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f);
636 cs->alpha = (unsigned char)bound(0, i, 255);
639 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float);
643 cs->alpha = (unsigned char)bound(0, i, 255);
647 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f);
651 cs->scale = (unsigned char)bound(0, i, 255);
655 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_color)->_float);
657 cs->glowcolor = (int)f;
659 if (PRVM_GETEDICTFIELDVALUE(ent, eval_fullbright)->_float)
660 cs->effects |= EF_FULLBRIGHT;
662 if (ent->fields.server->movetype == MOVETYPE_STEP)
663 cs->flags |= RENDER_STEP;
664 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)
665 cs->flags |= RENDER_LOWPRECISION;
666 if (ent->fields.server->colormap >= 1024)
667 cs->flags |= RENDER_COLORMAPPED;
668 if (cs->viewmodelforclient)
669 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
671 cs->light[0] = light[0];
672 cs->light[1] = light[1];
673 cs->light[2] = light[2];
674 cs->light[3] = light[3];
675 cs->lightstyle = lightstyle;
676 cs->lightpflags = lightpflags;
678 cs->specialvisibilityradius = specialvisibilityradius;
680 // calculate the visible box of this entity (don't use the physics box
681 // as that is often smaller than a model, and would not count
682 // specialvisibilityradius)
683 if ((model = sv.models[modelindex]))
685 float scale = cs->scale * (1.0f / 16.0f);
686 if (cs->angles[0] || cs->angles[2]) // pitch and roll
688 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
689 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
691 else if (cs->angles[1])
693 VectorMA(cs->origin, scale, model->yawmins, cullmins);
694 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
698 VectorMA(cs->origin, scale, model->normalmins, cullmins);
699 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
704 // if there is no model (or it could not be loaded), use the physics box
705 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
706 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
708 if (specialvisibilityradius)
710 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
711 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
712 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
713 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
714 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
715 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
717 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
719 VectorCopy(cullmins, ent->priv.server->cullmins);
720 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
721 ent->priv.server->pvs_numclusters = -1;
722 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
724 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
725 if (i <= MAX_ENTITYCLUSTERS)
726 ent->priv.server->pvs_numclusters = i;
733 void SV_PrepareEntitiesForSending(void)
737 // send all entities that touch the pvs
739 sendentitiesindex[0] = NULL;
740 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
741 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
743 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
745 sendentitiesindex[e] = sendentities + numsendentities;
751 static int sententitiesmark = 0;
752 static int sententities[MAX_EDICTS];
753 static int sententitiesconsideration[MAX_EDICTS];
754 static int sv_writeentitiestoclient_culled_pvs;
755 static int sv_writeentitiestoclient_culled_trace;
756 static int sv_writeentitiestoclient_visibleentities;
757 static int sv_writeentitiestoclient_totalentities;
758 //static entity_frame_t sv_writeentitiestoclient_entityframe;
759 static int sv_writeentitiestoclient_clentnum;
760 static vec3_t sv_writeentitiestoclient_testeye;
761 static client_t *sv_writeentitiestoclient_client;
763 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
770 if (sententitiesconsideration[s->number] == sententitiesmark)
772 sententitiesconsideration[s->number] = sententitiesmark;
773 sv_writeentitiestoclient_totalentities++;
775 if (s->customizeentityforclient)
777 prog->globals.server->self = s->number;
778 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
779 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
780 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
784 // never reject player
785 if (s->number != sv_writeentitiestoclient_clentnum)
787 // check various rejection conditions
788 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
790 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
792 if (s->effects & EF_NODRAW)
794 // LordHavoc: only send entities with a model or important effects
795 if (!s->modelindex && s->specialvisibilityradius == 0)
798 // viewmodels don't have visibility checking
799 if (s->viewmodelforclient)
801 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
804 else if (s->tagentity)
806 // tag attached entities simply check their parent
807 if (!sendentitiesindex[s->tagentity])
809 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
810 if (sententities[s->tagentity] != sententitiesmark)
813 // always send world submodels in newer protocols because they don't
814 // generate much traffic (in old protocols they hog bandwidth)
815 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)))
817 // entity has survived every check so far, check if visible
818 ed = PRVM_EDICT_NUM(s->number);
820 // if not touching a visible leaf
821 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
823 if (ed->priv.server->pvs_numclusters < 0)
825 // entity too big for clusters list
826 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
828 sv_writeentitiestoclient_culled_pvs++;
835 // check cached clusters list
836 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
837 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
839 if (i == ed->priv.server->pvs_numclusters)
841 sv_writeentitiestoclient_culled_pvs++;
847 // or not seen by random tracelines
848 if (sv_cullentities_trace.integer && !isbmodel)
850 // LordHavoc: test center first
851 testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
852 testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
853 testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
854 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
855 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
856 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
859 // LordHavoc: test random offsets, to maximize chance of detection
860 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
861 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
862 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
863 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
864 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
865 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
868 if (s->specialvisibilityradius)
870 // LordHavoc: test random offsets, to maximize chance of detection
871 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
872 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
873 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
874 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
875 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
876 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
880 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
882 sv_writeentitiestoclient_culled_trace++;
889 // this just marks it for sending
890 // FIXME: it would be more efficient to send here, but the entity
891 // compressor isn't that flexible
892 sv_writeentitiestoclient_visibleentities++;
893 sententities[s->number] = sententitiesmark;
896 entity_state_t sendstates[MAX_EDICTS];
897 extern int csqc_clent;
899 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
901 int i, numsendstates;
904 // if there isn't enough space to accomplish anything, skip it
905 if (msg->cursize + 25 > msg->maxsize)
908 sv_writeentitiestoclient_client = client;
910 sv_writeentitiestoclient_culled_pvs = 0;
911 sv_writeentitiestoclient_culled_trace = 0;
912 sv_writeentitiestoclient_visibleentities = 0;
913 sv_writeentitiestoclient_totalentities = 0;
915 // find the client's PVS
916 // the real place being tested from
917 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
918 sv_writeentitiestoclient_pvsbytes = 0;
919 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
920 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
922 csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
926 for (i = 0;i < numsendentities;i++)
927 SV_MarkWriteEntityStateToClient(sendentities + i);
930 for (i = 0;i < numsendentities;i++)
932 if (sententities[sendentities[i].number] == sententitiesmark)
934 s = &sendstates[numsendstates++];
935 *s = sendentities[i];
936 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
937 s->flags |= RENDER_EXTERIORMODEL;
941 if (sv_cullentities_stats.integer)
942 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);
944 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
946 if (client->entitydatabase5)
947 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
948 else if (client->entitydatabase4)
949 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
950 else if (client->entitydatabase)
951 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
953 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
962 void SV_CleanupEnts (void)
967 ent = PRVM_NEXT_EDICT(prog->edicts);
968 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
969 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
974 SV_WriteClientdataToMessage
978 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
990 // send a damage message
992 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
994 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
995 MSG_WriteByte (msg, svc_damage);
996 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
997 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
998 for (i=0 ; i<3 ; i++)
999 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
1001 ent->fields.server->dmg_take = 0;
1002 ent->fields.server->dmg_save = 0;
1006 // send the current viewpos offset from the view entity
1008 SV_SetIdealPitch (); // how much to look up / down ideally
1010 // a fixangle might get lost in a dropped packet. Oh well.
1011 if ( ent->fields.server->fixangle )
1013 MSG_WriteByte (msg, svc_setangle);
1014 for (i=0 ; i < 3 ; i++)
1015 MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
1016 ent->fields.server->fixangle = 0;
1019 // stuff the sigil bits into the high bits of items for sbar, or else
1021 val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
1022 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1023 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1025 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1027 VectorClear(punchvector);
1028 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
1029 VectorCopy(val->vector, punchvector);
1031 // cache weapon model name and index in client struct to save time
1032 // (this search can be almost 1% of cpu time!)
1033 s = PRVM_GetString(ent->fields.server->weaponmodel);
1034 if (strcmp(s, client->weaponmodel))
1036 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1037 client->weaponmodelindex = SV_ModelIndex(s, 1);
1041 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
1042 viewzoom = (int)(val->_float * 255.0f);
1048 if ((int)ent->fields.server->flags & FL_ONGROUND)
1049 bits |= SU_ONGROUND;
1050 if (ent->fields.server->waterlevel >= 2)
1052 if (ent->fields.server->idealpitch)
1053 bits |= SU_IDEALPITCH;
1055 for (i=0 ; i<3 ; i++)
1057 if (ent->fields.server->punchangle[i])
1058 bits |= (SU_PUNCH1<<i);
1059 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1061 bits |= (SU_PUNCHVEC1<<i);
1062 if (ent->fields.server->velocity[i])
1063 bits |= (SU_VELOCITY1<<i);
1066 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1067 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1068 stats[STAT_ITEMS] = items;
1069 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1070 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1071 stats[STAT_WEAPON] = client->weaponmodelindex;
1072 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1073 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1074 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1075 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1076 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1077 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1078 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1079 stats[STAT_VIEWZOOM] = viewzoom;
1080 // the QC bumps these itself by sending svc_'s, so we have to keep them
1081 // zero or they'll be corrected by the engine
1082 //stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1083 //stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1084 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1085 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1087 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)
1089 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1091 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1092 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1094 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1095 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1096 if (viewzoom != 255)
1097 bits |= SU_VIEWZOOM;
1102 if (bits >= 16777216)
1106 MSG_WriteByte (msg, svc_clientdata);
1107 MSG_WriteShort (msg, bits);
1108 if (bits & SU_EXTEND1)
1109 MSG_WriteByte(msg, bits >> 16);
1110 if (bits & SU_EXTEND2)
1111 MSG_WriteByte(msg, bits >> 24);
1113 if (bits & SU_VIEWHEIGHT)
1114 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1116 if (bits & SU_IDEALPITCH)
1117 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1119 for (i=0 ; i<3 ; i++)
1121 if (bits & (SU_PUNCH1<<i))
1123 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1124 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1126 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1128 if (bits & (SU_PUNCHVEC1<<i))
1130 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1131 MSG_WriteCoord16i(msg, punchvector[i]);
1133 MSG_WriteCoord32f(msg, punchvector[i]);
1135 if (bits & (SU_VELOCITY1<<i))
1137 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1138 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1140 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1144 if (bits & SU_ITEMS)
1145 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1147 if (sv.protocol == PROTOCOL_DARKPLACES5)
1149 if (bits & SU_WEAPONFRAME)
1150 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1151 if (bits & SU_ARMOR)
1152 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1153 if (bits & SU_WEAPON)
1154 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1155 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1156 MSG_WriteShort (msg, stats[STAT_AMMO]);
1157 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1158 MSG_WriteShort (msg, stats[STAT_NAILS]);
1159 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1160 MSG_WriteShort (msg, stats[STAT_CELLS]);
1161 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1162 if (bits & SU_VIEWZOOM)
1163 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1165 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)
1167 if (bits & SU_WEAPONFRAME)
1168 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1169 if (bits & SU_ARMOR)
1170 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1171 if (bits & SU_WEAPON)
1172 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1173 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1174 MSG_WriteByte (msg, stats[STAT_AMMO]);
1175 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1176 MSG_WriteByte (msg, stats[STAT_NAILS]);
1177 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1178 MSG_WriteByte (msg, stats[STAT_CELLS]);
1179 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1181 for (i = 0;i < 32;i++)
1182 if (stats[STAT_WEAPON] & (1<<i))
1184 MSG_WriteByte (msg, i);
1187 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1188 if (bits & SU_VIEWZOOM)
1190 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1191 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1193 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1199 =======================
1200 SV_SendClientDatagram
1201 =======================
1203 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1204 void SV_SendClientDatagram (client_t *client)
1206 int rate, maxrate, maxsize, maxsize2;
1208 int stats[MAX_CL_STATS];
1210 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1212 // for good singleplayer, send huge packets
1213 maxsize = sizeof(sv_sendclientdatagram_buf);
1214 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1216 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)
1218 // no rate limiting support on older protocols because dp protocols
1219 // 1-4 kick the client off if they overflow, and quake protocol shows
1220 // less than the full entity set if rate limited
1226 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1227 maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE);
1228 if (sv_maxrate.integer != maxrate)
1229 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1231 // this rate limiting does not understand sys_ticrate 0
1232 // (but no one should be running that on a server!)
1233 rate = bound(NET_MINRATE, client->rate, maxrate);
1234 rate = (int)(client->rate * sys_ticrate.value);
1235 maxsize = bound(100, rate, 1400);
1239 msg.data = sv_sendclientdatagram_buf;
1240 msg.maxsize = maxsize;
1243 if (host_client->spawned)
1245 MSG_WriteByte (&msg, svc_time);
1246 MSG_WriteFloat (&msg, sv.time);
1248 // add the client specific data to the datagram
1249 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1250 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1251 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1253 // expand packet size to allow effects to go over the rate limit
1254 // (dropping them is FAR too ugly)
1255 msg.maxsize = maxsize2;
1257 // copy the server datagram if there is space
1258 // FIXME: put in delayed queue of effects to send
1259 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1260 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1262 else if (realtime > client->keepalivetime)
1264 // the player isn't totally in the game yet
1265 // send small keepalive messages if too much time has passed
1266 client->keepalivetime = realtime + 5;
1267 MSG_WriteChar (&msg, svc_nop);
1270 // send the datagram
1271 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1275 =======================
1276 SV_UpdateToReliableMessages
1277 =======================
1279 void SV_UpdateToReliableMessages (void)
1288 // check for changes to be sent over the reliable streams
1289 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1291 // update the host_client fields we care about according to the entity fields
1292 host_client->edict = PRVM_EDICT_NUM(i+1);
1295 name = PRVM_GetString(host_client->edict->fields.server->netname);
1298 // always point the string back at host_client->name to keep it safe
1299 strlcpy (host_client->name, name, sizeof (host_client->name));
1300 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1301 if (strcmp(host_client->old_name, host_client->name))
1303 if (host_client->spawned)
1304 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1305 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1306 // send notification to all clients
1307 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1308 MSG_WriteByte (&sv.reliable_datagram, i);
1309 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1312 // DP_SV_CLIENTCOLORS
1313 // this is always found (since it's added by the progs loader)
1314 if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1315 host_client->colors = (int)val->_float;
1316 if (host_client->old_colors != host_client->colors)
1318 host_client->old_colors = host_client->colors;
1319 // send notification to all clients
1320 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1321 MSG_WriteByte (&sv.reliable_datagram, i);
1322 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1325 // NEXUIZ_PLAYERMODEL
1326 if( eval_playermodel ) {
1327 model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string);
1330 // always point the string back at host_client->name to keep it safe
1331 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1332 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1335 // NEXUIZ_PLAYERSKIN
1336 if( eval_playerskin ) {
1337 skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string);
1340 // always point the string back at host_client->name to keep it safe
1341 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1342 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1346 host_client->frags = (int)host_client->edict->fields.server->frags;
1347 if (host_client->old_frags != host_client->frags)
1349 host_client->old_frags = host_client->frags;
1350 // send notification to all clients
1351 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1352 MSG_WriteByte (&sv.reliable_datagram, i);
1353 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1357 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1358 if (client->netconnection)
1359 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1361 SZ_Clear (&sv.reliable_datagram);
1366 =======================
1367 SV_SendClientMessages
1368 =======================
1370 void SV_SendClientMessages (void)
1372 int i, prepared = false;
1374 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1375 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1377 // update frags, names, etc
1378 SV_UpdateToReliableMessages();
1380 // build individual updates
1381 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1383 if (!host_client->active)
1385 if (!host_client->netconnection)
1388 if (host_client->netconnection->message.overflowed)
1390 SV_DropClient (true); // if the message couldn't send, kick off
1397 // only prepare entities once per frame
1398 SV_PrepareEntitiesForSending();
1400 SV_SendClientDatagram (host_client);
1403 // clear muzzle flashes
1409 ==============================================================================
1413 ==============================================================================
1422 int SV_ModelIndex(const char *s, int precachemode)
1424 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1425 char filename[MAX_QPATH];
1429 //if (precachemode == 2)
1431 strlcpy(filename, s, sizeof(filename));
1432 for (i = 2;i < limit;i++)
1434 if (!sv.model_precache[i][0])
1438 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))
1440 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1443 if (precachemode == 1)
1444 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1445 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1446 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1447 if (sv.state != ss_loading)
1449 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1450 MSG_WriteShort(&sv.reliable_datagram, i);
1451 MSG_WriteString(&sv.reliable_datagram, filename);
1455 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1458 if (!strcmp(sv.model_precache[i], filename))
1461 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1471 int SV_SoundIndex(const char *s, int precachemode)
1473 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1474 char filename[MAX_QPATH];
1478 //if (precachemode == 2)
1480 strlcpy(filename, s, sizeof(filename));
1481 for (i = 1;i < limit;i++)
1483 if (!sv.sound_precache[i][0])
1487 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))
1489 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1492 if (precachemode == 1)
1493 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1494 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1495 if (sv.state != ss_loading)
1497 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1498 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1499 MSG_WriteString(&sv.reliable_datagram, filename);
1503 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1506 if (!strcmp(sv.sound_precache[i], filename))
1509 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1519 void SV_CreateBaseline (void)
1521 int i, entnum, large;
1522 prvm_edict_t *svent;
1524 // LordHavoc: clear *all* states (note just active ones)
1525 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1527 // get the current server version
1528 svent = PRVM_EDICT_NUM(entnum);
1530 // LordHavoc: always clear state values, whether the entity is in use or not
1531 svent->priv.server->baseline = defaultstate;
1533 if (svent->priv.server->free)
1535 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1538 // create entity baseline
1539 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1540 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1541 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1542 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1543 if (entnum > 0 && entnum <= svs.maxclients)
1545 svent->priv.server->baseline.colormap = entnum;
1546 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1550 svent->priv.server->baseline.colormap = 0;
1551 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1555 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1558 // add to the message
1560 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1562 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1563 MSG_WriteShort (&sv.signon, entnum);
1567 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1568 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1572 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1573 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1575 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1576 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1577 for (i=0 ; i<3 ; i++)
1579 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1580 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1590 Grabs the current state of each client for saving across the
1591 transition to another level
1594 void SV_SaveSpawnparms (void)
1598 svs.serverflags = (int)prog->globals.server->serverflags;
1600 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1602 if (!host_client->active)
1605 // call the progs to get default spawn parms for the new client
1606 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1607 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1608 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1609 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1613 void SV_IncreaseEdicts(void)
1617 int oldmax_edicts = prog->max_edicts;
1618 void *oldedictsengineprivate = prog->edictprivate;
1619 void *oldedictsfields = prog->edictsfields;
1620 void *oldmoved_edicts = sv.moved_edicts;
1622 if (prog->max_edicts >= MAX_EDICTS)
1625 // links don't survive the transition, so unlink everything
1626 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1628 if (!ent->priv.server->free)
1629 SV_UnlinkEdict(prog->edicts + i);
1630 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1634 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
1635 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1636 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
1637 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1639 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
1640 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
1642 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1644 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1645 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1646 // link every entity except world
1647 if (!ent->priv.server->free)
1648 SV_LinkEdict(ent, false);
1651 PR_Free(oldedictsengineprivate);
1652 PR_Free(oldedictsfields);
1653 PR_Free(oldmoved_edicts);
1660 This is called at the start of each level
1663 extern float scr_centertime_off;
1665 void SV_SpawnServer (const char *server)
1670 model_t *worldmodel;
1671 char modelname[sizeof(sv.modelname)];
1673 Con_DPrintf("SpawnServer: %s\n", server);
1675 if (cls.state != ca_dedicated)
1676 SCR_BeginLoadingPlaque();
1678 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
1679 worldmodel = Mod_ForName(modelname, false, true, true);
1680 if (!worldmodel || !worldmodel->TraceBox)
1682 Con_Printf("Couldn't load map %s\n", modelname);
1686 // let's not have any servers with no name
1687 if (hostname.string[0] == 0)
1688 Cvar_Set ("hostname", "UNNAMED");
1689 scr_centertime_off = 0;
1691 svs.changelevel_issued = false; // now safe to issue another
1693 // make the map a required file for clients
1694 Curl_ClearRequirements();
1695 Curl_RequireFile(modelname);
1698 // tell all connected clients that we are going to a new level
1703 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1705 if (client->netconnection)
1707 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
1708 MSG_WriteString(&client->netconnection->message, "reconnect\n");
1715 NetConn_OpenServerPorts(true);
1719 // make cvars consistant
1722 Cvar_SetValue ("deathmatch", 0);
1723 // LordHavoc: it can be useful to have skills outside the range 0-3...
1724 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
1725 //Cvar_SetValue ("skill", (float)current_skill);
1726 current_skill = (int)(skill.value + 0.5);
1729 // set up the new server
1731 memset (&sv, 0, sizeof(sv));
1732 // if running a local client, make sure it doesn't try to access the last
1733 // level's data which is no longer valiud
1740 strlcpy (sv.name, server, sizeof (sv.name));
1742 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
1743 if (sv.protocol == PROTOCOL_UNKNOWN)
1746 Protocol_Names(buffer, sizeof(buffer));
1747 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
1748 sv.protocol = PROTOCOL_QUAKE;
1753 // load progs to get entity field count
1754 //PR_LoadProgs ( sv_progs.string );
1756 // allocate server memory
1757 /*// start out with just enough room for clients and a reasonable estimate of entities
1758 prog->max_edicts = max(svs.maxclients + 1, 512);
1759 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
1761 // prvm_edict_t structures (hidden from progs)
1762 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
1763 // engine private structures (hidden from progs)
1764 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1765 // progs fields, often accessed by server
1766 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
1767 // used by PushMove to move back pushed entities
1768 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1769 /*for (i = 0;i < prog->max_edicts;i++)
1771 ent = prog->edicts + i;
1772 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1773 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1776 // reset client csqc entity versions right away.
1777 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1778 EntityFrameCSQC_InitClientVersions(i, true);
1780 sv.datagram.maxsize = sizeof(sv.datagram_buf);
1781 sv.datagram.cursize = 0;
1782 sv.datagram.data = sv.datagram_buf;
1784 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
1785 sv.reliable_datagram.cursize = 0;
1786 sv.reliable_datagram.data = sv.reliable_datagram_buf;
1788 sv.signon.maxsize = sizeof(sv.signon_buf);
1789 sv.signon.cursize = 0;
1790 sv.signon.data = sv.signon_buf;
1792 // leave slots at start for clients only
1793 //prog->num_edicts = svs.maxclients+1;
1795 sv.state = ss_loading;
1796 prog->allowworldwrites = true;
1799 *prog->time = sv.time = 1.0;
1802 worldmodel->used = true;
1804 strlcpy (sv.name, server, sizeof (sv.name));
1805 strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
1806 sv.worldmodel = worldmodel;
1807 sv.models[1] = sv.worldmodel;
1810 // clear world interaction links
1814 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
1816 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
1817 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
1818 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
1820 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
1821 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
1825 // load the rest of the entities
1827 // AK possible hack since num_edicts is still 0
1828 ent = PRVM_EDICT_NUM(0);
1829 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
1830 ent->priv.server->free = false;
1831 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
1832 ent->fields.server->modelindex = 1; // world model
1833 ent->fields.server->solid = SOLID_BSP;
1834 ent->fields.server->movetype = MOVETYPE_PUSH;
1837 prog->globals.server->coop = coop.integer;
1839 prog->globals.server->deathmatch = deathmatch.integer;
1841 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
1843 // serverflags are for cross level information (sigils)
1844 prog->globals.server->serverflags = svs.serverflags;
1846 // we need to reset the spawned flag on all connected clients here so that
1847 // their thinks don't run during startup (before PutClientInServer)
1848 // we also need to set up the client entities now
1849 // and we need to set the ->edict pointers to point into the progs edicts
1850 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1852 host_client->spawned = false;
1853 host_client->edict = PRVM_EDICT_NUM(i + 1);
1854 PRVM_ED_ClearEdict(host_client->edict);
1857 // load replacement entity file if found
1858 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
1860 Con_Printf("Loaded maps/%s.ent\n", sv.name);
1861 PRVM_ED_LoadFromFile (entities);
1865 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
1868 // LordHavoc: clear world angles (to fix e3m3.bsp)
1869 VectorClear(prog->edicts->fields.server->angles);
1871 // all setup is completed, any further precache statements are errors
1872 sv.state = ss_active;
1873 prog->allowworldwrites = false;
1875 // run two frames to allow everything to settle
1876 for (i = 0;i < 2;i++)
1884 // create a baseline for more efficient communications
1885 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1886 SV_CreateBaseline ();
1888 // send serverinfo to all connected clients, and set up botclients coming back from a level change
1889 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1891 if (!host_client->active)
1893 if (host_client->netconnection)
1894 SV_SendServerinfo(host_client);
1898 // if client is a botclient coming from a level change, we need to
1899 // set up client info that normally requires networking
1901 // copy spawn parms out of the client_t
1902 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
1903 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
1905 // call the spawn function
1906 host_client->clientconnectcalled = true;
1907 prog->globals.server->time = sv.time;
1908 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1909 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1910 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1911 host_client->spawned = true;
1915 Con_DPrint("Server spawned.\n");
1916 NetConn_Heartbeat (2);
1921 /////////////////////////////////////////////////////
1924 void SV_VM_CB_BeginIncreaseEdicts(void)
1929 PRVM_Free( sv.moved_edicts );
1930 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1932 // links don't survive the transition, so unlink everything
1933 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1935 if (!ent->priv.server->free)
1936 SV_UnlinkEdict(prog->edicts + i);
1937 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1942 void SV_VM_CB_EndIncreaseEdicts(void)
1947 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1949 // link every entity except world
1950 if (!ent->priv.server->free)
1951 SV_LinkEdict(ent, false);
1955 void SV_VM_CB_InitEdict(prvm_edict_t *e)
1957 // LordHavoc: for consistency set these here
1958 int num = PRVM_NUM_FOR_EDICT(e) - 1;
1960 e->priv.server->move = false; // don't move on first frame
1962 if (num >= 0 && num < svs.maxclients)
1965 // set colormap and team on newly created player entity
1966 e->fields.server->colormap = num + 1;
1967 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
1968 // set netname/clientcolors back to client values so that
1969 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
1971 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
1972 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
1973 val->_float = svs.clients[num].colors;
1974 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
1975 if( eval_playermodel )
1976 PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
1977 if( eval_playerskin )
1978 PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
1982 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
1984 SV_UnlinkEdict (ed); // unlink from world bsp
1986 ed->fields.server->model = 0;
1987 ed->fields.server->takedamage = 0;
1988 ed->fields.server->modelindex = 0;
1989 ed->fields.server->colormap = 0;
1990 ed->fields.server->skin = 0;
1991 ed->fields.server->frame = 0;
1992 VectorClear(ed->fields.server->origin);
1993 VectorClear(ed->fields.server->angles);
1994 ed->fields.server->nextthink = -1;
1995 ed->fields.server->solid = 0;
1998 void SV_VM_CB_CountEdicts(void)
2002 int active, models, solid, step;
2004 active = models = solid = step = 0;
2005 for (i=0 ; i<prog->num_edicts ; i++)
2007 ent = PRVM_EDICT_NUM(i);
2008 if (ent->priv.server->free)
2011 if (ent->fields.server->solid)
2013 if (ent->fields.server->model)
2015 if (ent->fields.server->movetype == MOVETYPE_STEP)
2019 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2020 Con_Printf("active :%3i\n", active);
2021 Con_Printf("view :%3i\n", models);
2022 Con_Printf("touch :%3i\n", solid);
2023 Con_Printf("step :%3i\n", step);
2026 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2028 // remove things from different skill levels or deathmatch
2029 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2031 if (deathmatch.integer)
2033 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2038 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2039 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2040 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2048 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)"};
2049 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2050 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2051 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2052 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2053 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2054 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2055 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2056 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2057 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2058 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2059 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2060 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2061 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2062 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2063 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2064 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2065 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2066 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2067 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2068 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2069 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2070 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2071 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2072 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2073 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2074 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2075 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2076 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2077 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2078 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2079 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2080 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2082 void SV_VM_Init(void)
2084 Cvar_RegisterVariable (&pr_checkextension);
2085 Cvar_RegisterVariable (&nomonsters);
2086 Cvar_RegisterVariable (&gamecfg);
2087 Cvar_RegisterVariable (&scratch1);
2088 Cvar_RegisterVariable (&scratch2);
2089 Cvar_RegisterVariable (&scratch3);
2090 Cvar_RegisterVariable (&scratch4);
2091 Cvar_RegisterVariable (&savedgamecfg);
2092 Cvar_RegisterVariable (&saved1);
2093 Cvar_RegisterVariable (&saved2);
2094 Cvar_RegisterVariable (&saved3);
2095 Cvar_RegisterVariable (&saved4);
2096 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2097 if (gamemode == GAME_NEHAHRA)
2099 Cvar_RegisterVariable (&nehx00);
2100 Cvar_RegisterVariable (&nehx01);
2101 Cvar_RegisterVariable (&nehx02);
2102 Cvar_RegisterVariable (&nehx03);
2103 Cvar_RegisterVariable (&nehx04);
2104 Cvar_RegisterVariable (&nehx05);
2105 Cvar_RegisterVariable (&nehx06);
2106 Cvar_RegisterVariable (&nehx07);
2107 Cvar_RegisterVariable (&nehx08);
2108 Cvar_RegisterVariable (&nehx09);
2109 Cvar_RegisterVariable (&nehx10);
2110 Cvar_RegisterVariable (&nehx11);
2111 Cvar_RegisterVariable (&nehx12);
2112 Cvar_RegisterVariable (&nehx13);
2113 Cvar_RegisterVariable (&nehx14);
2114 Cvar_RegisterVariable (&nehx15);
2115 Cvar_RegisterVariable (&nehx16);
2116 Cvar_RegisterVariable (&nehx17);
2117 Cvar_RegisterVariable (&nehx18);
2118 Cvar_RegisterVariable (&nehx19);
2120 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2123 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
2140 int eval_buttonchat;
2142 int eval_glow_trail;
2143 int eval_glow_color;
2147 int eval_renderamt; // HalfLife support
2148 int eval_rendermode; // HalfLife support
2149 int eval_fullbright;
2150 int eval_ammo_shells1;
2151 int eval_ammo_nails1;
2152 int eval_ammo_lava_nails;
2153 int eval_ammo_rockets1;
2154 int eval_ammo_multi_rockets;
2155 int eval_ammo_cells1;
2156 int eval_ammo_plasma;
2157 int eval_idealpitch;
2158 int eval_pitch_speed;
2159 int eval_viewmodelforclient;
2160 int eval_nodrawtoclient;
2161 int eval_exteriormodeltoclient;
2162 int eval_drawonlytoclient;
2166 int eval_punchvector;
2168 int eval_clientcolors;
2169 int eval_tag_entity;
2175 int eval_cursor_active;
2176 int eval_cursor_screen;
2177 int eval_cursor_trace_start;
2178 int eval_cursor_trace_endpos;
2179 int eval_cursor_trace_ent;
2181 int eval_playermodel;
2182 int eval_playerskin;
2183 int eval_SendEntity;
2185 int eval_customizeentityforclient;
2186 int eval_dphitcontentsmask;
2188 int gval_trace_dpstartcontents;
2189 int gval_trace_dphitcontents;
2190 int gval_trace_dphitq3surfaceflags;
2191 int gval_trace_dphittexturename;
2193 mfunction_t *SV_PlayerPhysicsQC;
2194 mfunction_t *EndFrameQC;
2195 //KrimZon - SERVER COMMANDS IN QUAKEC
2196 mfunction_t *SV_ParseClientCommandQC;
2198 void SV_VM_FindEdictFieldOffsets(void)
2200 eval_gravity = PRVM_ED_FindFieldOffset("gravity");
2201 eval_button3 = PRVM_ED_FindFieldOffset("button3");
2202 eval_button4 = PRVM_ED_FindFieldOffset("button4");
2203 eval_button5 = PRVM_ED_FindFieldOffset("button5");
2204 eval_button6 = PRVM_ED_FindFieldOffset("button6");
2205 eval_button7 = PRVM_ED_FindFieldOffset("button7");
2206 eval_button8 = PRVM_ED_FindFieldOffset("button8");
2207 eval_button9 = PRVM_ED_FindFieldOffset("button9");
2208 eval_button10 = PRVM_ED_FindFieldOffset("button10");
2209 eval_button11 = PRVM_ED_FindFieldOffset("button11");
2210 eval_button12 = PRVM_ED_FindFieldOffset("button12");
2211 eval_button13 = PRVM_ED_FindFieldOffset("button13");
2212 eval_button14 = PRVM_ED_FindFieldOffset("button14");
2213 eval_button15 = PRVM_ED_FindFieldOffset("button15");
2214 eval_button16 = PRVM_ED_FindFieldOffset("button16");
2215 eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
2216 eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
2217 eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
2218 eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
2219 eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
2220 eval_items2 = PRVM_ED_FindFieldOffset("items2");
2221 eval_scale = PRVM_ED_FindFieldOffset("scale");
2222 eval_alpha = PRVM_ED_FindFieldOffset("alpha");
2223 eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
2224 eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
2225 eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
2226 eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
2227 eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
2228 eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
2229 eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
2230 eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
2231 eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
2232 eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
2233 eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
2234 eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
2235 eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
2236 eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
2237 eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
2238 eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
2239 eval_ping = PRVM_ED_FindFieldOffset("ping");
2240 eval_movement = PRVM_ED_FindFieldOffset("movement");
2241 eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
2242 eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
2243 eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
2244 eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
2245 eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
2246 eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
2247 eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
2248 eval_color = PRVM_ED_FindFieldOffset("color");
2249 eval_style = PRVM_ED_FindFieldOffset("style");
2250 eval_pflags = PRVM_ED_FindFieldOffset("pflags");
2251 eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
2252 eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
2253 eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
2254 eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
2255 eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
2256 eval_colormod = PRVM_ED_FindFieldOffset("colormod");
2257 eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
2258 eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
2259 eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
2260 eval_Version = PRVM_ED_FindFieldOffset("Version");
2261 eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
2262 eval_dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
2264 // LordHavoc: allowing QuakeC to override the player movement code
2265 SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
2266 // LordHavoc: support for endframe
2267 EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
2268 //KrimZon - SERVER COMMANDS IN QUAKEC
2269 SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
2270 gval_trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
2271 gval_trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
2272 gval_trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
2273 gval_trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
2276 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2278 prvm_required_field_t reqfields[] =
2280 {ev_entity, "cursor_trace_ent"},
2281 {ev_entity, "drawonlytoclient"},
2282 {ev_entity, "exteriormodeltoclient"},
2283 {ev_entity, "nodrawtoclient"},
2284 {ev_entity, "tag_entity"},
2285 {ev_entity, "viewmodelforclient"},
2286 {ev_float, "alpha"},
2287 {ev_float, "ammo_cells1"},
2288 {ev_float, "ammo_lava_nails"},
2289 {ev_float, "ammo_multi_rockets"},
2290 {ev_float, "ammo_nails1"},
2291 {ev_float, "ammo_plasma"},
2292 {ev_float, "ammo_rockets1"},
2293 {ev_float, "ammo_shells1"},
2294 {ev_float, "button3"},
2295 {ev_float, "button4"},
2296 {ev_float, "button5"},
2297 {ev_float, "button6"},
2298 {ev_float, "button7"},
2299 {ev_float, "button8"},
2300 {ev_float, "button9"},
2301 {ev_float, "button10"},
2302 {ev_float, "button11"},
2303 {ev_float, "button12"},
2304 {ev_float, "button13"},
2305 {ev_float, "button14"},
2306 {ev_float, "button15"},
2307 {ev_float, "button16"},
2308 {ev_float, "buttonchat"},
2309 {ev_float, "buttonuse"},
2310 {ev_float, "clientcolors"},
2311 {ev_float, "cursor_active"},
2312 {ev_float, "fullbright"},
2313 {ev_float, "glow_color"},
2314 {ev_float, "glow_size"},
2315 {ev_float, "glow_trail"},
2316 {ev_float, "gravity"},
2317 {ev_float, "idealpitch"},
2318 {ev_float, "items2"},
2319 {ev_float, "light_lev"},
2320 {ev_float, "pflags"},
2322 {ev_float, "pitch_speed"},
2323 {ev_float, "pmodel"},
2324 {ev_float, "renderamt"}, // HalfLife support
2325 {ev_float, "rendermode"}, // HalfLife support
2326 {ev_float, "scale"},
2327 {ev_float, "style"},
2328 {ev_float, "tag_index"},
2329 {ev_float, "Version"},
2330 {ev_float, "viewzoom"},
2331 {ev_vector, "color"},
2332 {ev_vector, "colormod"},
2333 {ev_vector, "cursor_screen"},
2334 {ev_vector, "cursor_trace_endpos"},
2335 {ev_vector, "cursor_trace_start"},
2336 {ev_vector, "movement"},
2337 {ev_vector, "punchvector"},
2338 {ev_string, "playermodel"},
2339 {ev_string, "playerskin"},
2340 {ev_function, "SendEntity"},
2341 {ev_function, "customizeentityforclient"},
2344 void SV_VM_Setup(void)
2346 unsigned char *csprogsdata;
2347 fs_offset_t csprogsdatasize;
2348 unsigned int csprogsdatacrc;
2350 PRVM_InitProg( PRVM_SERVERPROG );
2352 // allocate the mempools
2353 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2354 prog->builtins = vm_sv_builtins;
2355 prog->numbuiltins = vm_sv_numbuiltins;
2356 prog->headercrc = PROGHEADER_CRC;
2357 prog->max_edicts = 512;
2358 prog->limit_edicts = MAX_EDICTS;
2359 prog->reserved_edicts = svs.maxclients;
2360 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2361 prog->name = "server";
2362 prog->extensionstring = vm_sv_extensions;
2363 prog->loadintoworld = true;
2365 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2366 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2367 prog->init_edict = SV_VM_CB_InitEdict;
2368 prog->free_edict = SV_VM_CB_FreeEdict;
2369 prog->count_edicts = SV_VM_CB_CountEdicts;
2370 prog->load_edict = SV_VM_CB_LoadEdict;
2371 prog->init_cmd = VM_SV_Cmd_Init;
2372 prog->reset_cmd = VM_SV_Cmd_Reset;
2373 prog->error_cmd = Host_Error;
2375 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2376 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
2377 SV_VM_FindEdictFieldOffsets();
2379 VM_AutoSentStats_Clear();//[515]: csqc
2380 EntityFrameCSQC_ClearVersions();//[515]: csqc
2384 // 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
2386 csprogsdata = FS_LoadFile(csqc_progname.string, tempmempool, true, &csprogsdatasize);
2389 csprogsdatacrc = CRC_Block(csprogsdata, csprogsdatasize);
2390 Mem_Free(csprogsdata);
2392 Cvar_SetValueQuick(&csqc_progcrc, csprogsdatacrc);
2395 void SV_VM_Begin(void)
2398 PRVM_SetProg( PRVM_SERVERPROG );
2400 *prog->time = (float) sv.time;
2403 void SV_VM_End(void)