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
27 void VM_AutoSentStats_Clear (void);
28 void EntityFrameCSQC_ClearVersions (void);
29 void EntityFrameCSQC_InitClientVersions (int client, qboolean clear);
30 void VM_SV_WriteAutoSentStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats);
31 void EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int numstates, const entity_state_t *states);
34 // select which protocol to host, this is fed to Protocol_EnumForName
35 cvar_t sv_protocolname = {0, "sv_protocolname", "DP7", "selects network protocol to host for (values include QUAKE, QUAKEDP, NEHAHRAMOVIE, DP1 and up)"};
36 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)"};
37 cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "10000", "upper limit on client rate cvar, should reflect your network connection quality"};
39 static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"}; // fast but loose
40 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
41 static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
42 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)"};
44 cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebouncedownslopes", "1", "prevents MOVETYPE_BOUNCE (grenades) from getting stuck when fired down a downward sloping surface"};
45 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"};
46 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)"};
47 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)"};
48 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"};
49 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"};
50 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"};
51 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_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
58 mempool_t *sv_mempool = NULL;
60 //============================================================================
62 extern void SV_Phys_Init (void);
63 extern void SV_World_Init (void);
64 static void SV_SaveEntFile_f(void);
73 Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
74 Cvar_RegisterVariable (&sv_maxvelocity);
75 Cvar_RegisterVariable (&sv_gravity);
76 Cvar_RegisterVariable (&sv_friction);
77 Cvar_RegisterVariable (&sv_waterfriction);
78 Cvar_RegisterVariable (&sv_edgefriction);
79 Cvar_RegisterVariable (&sv_stopspeed);
80 Cvar_RegisterVariable (&sv_maxspeed);
81 Cvar_RegisterVariable (&sv_maxairspeed);
82 Cvar_RegisterVariable (&sv_accelerate);
83 Cvar_RegisterVariable (&sv_airaccelerate);
84 Cvar_RegisterVariable (&sv_wateraccelerate);
85 Cvar_RegisterVariable (&sv_idealpitchscale);
86 Cvar_RegisterVariable (&sv_aim);
87 Cvar_RegisterVariable (&sv_nostep);
88 Cvar_RegisterVariable (&sv_cullentities_pvs);
89 Cvar_RegisterVariable (&sv_cullentities_trace);
90 Cvar_RegisterVariable (&sv_cullentities_stats);
91 Cvar_RegisterVariable (&sv_entpatch);
92 Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
93 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
94 Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
95 Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
96 Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
97 Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
98 Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
99 Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
100 Cvar_RegisterVariable (&sv_protocolname);
101 Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
102 Cvar_RegisterVariable (&sv_maxrate);
103 Cvar_RegisterVariable (&sv_progs);
109 sv_mempool = Mem_AllocPool("server", 0, NULL);
112 static void SV_SaveEntFile_f(void)
114 char basename[MAX_QPATH];
115 if (!sv.active || !sv.worldmodel)
117 Con_Print("Not running a server\n");
120 FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
121 FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
126 =============================================================================
130 =============================================================================
137 Make sure the event gets sent to all clients
140 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
144 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
146 MSG_WriteByte (&sv.datagram, svc_particle);
147 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
148 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
149 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
150 for (i=0 ; i<3 ; i++)
151 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
152 MSG_WriteByte (&sv.datagram, count);
153 MSG_WriteByte (&sv.datagram, color);
160 Make sure the event gets sent to all clients
163 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
165 if (modelindex >= 256 || startframe >= 256)
167 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
169 MSG_WriteByte (&sv.datagram, svc_effect2);
170 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
171 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
172 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
173 MSG_WriteShort (&sv.datagram, modelindex);
174 MSG_WriteShort (&sv.datagram, startframe);
175 MSG_WriteByte (&sv.datagram, framecount);
176 MSG_WriteByte (&sv.datagram, framerate);
180 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
182 MSG_WriteByte (&sv.datagram, svc_effect);
183 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
184 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
185 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
186 MSG_WriteByte (&sv.datagram, modelindex);
187 MSG_WriteByte (&sv.datagram, startframe);
188 MSG_WriteByte (&sv.datagram, framecount);
189 MSG_WriteByte (&sv.datagram, framerate);
197 Each entity can have eight independant sound sources, like voice,
200 Channel 0 is an auto-allocate channel, the others override anything
201 already running on that entity/channel pair.
203 An attenuation of 0 will play full volume everywhere in the level.
204 Larger attenuations will drop off. (max 4 attenuation)
208 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
210 int sound_num, field_mask, i, ent;
212 if (volume < 0 || volume > 255)
214 Con_Printf ("SV_StartSound: volume = %i\n", volume);
218 if (attenuation < 0 || attenuation > 4)
220 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
224 if (channel < 0 || channel > 7)
226 Con_Printf ("SV_StartSound: channel = %i\n", channel);
230 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
233 // find precache number for sound
234 sound_num = SV_SoundIndex(sample, 1);
238 ent = PRVM_NUM_FOR_EDICT(entity);
241 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
242 field_mask |= SND_VOLUME;
243 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
244 field_mask |= SND_ATTENUATION;
246 field_mask |= SND_LARGEENTITY;
247 if (sound_num >= 256 || channel >= 8)
248 field_mask |= SND_LARGESOUND;
250 // directed messages go only to the entity they are targeted on
251 MSG_WriteByte (&sv.datagram, svc_sound);
252 MSG_WriteByte (&sv.datagram, field_mask);
253 if (field_mask & SND_VOLUME)
254 MSG_WriteByte (&sv.datagram, volume);
255 if (field_mask & SND_ATTENUATION)
256 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
257 if (field_mask & SND_LARGEENTITY)
259 MSG_WriteShort (&sv.datagram, ent);
260 MSG_WriteByte (&sv.datagram, channel);
263 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
264 if (field_mask & SND_LARGESOUND)
265 MSG_WriteShort (&sv.datagram, sound_num);
267 MSG_WriteByte (&sv.datagram, sound_num);
268 for (i = 0;i < 3;i++)
269 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
273 ==============================================================================
277 ==============================================================================
280 static const char *SV_InitCmd; //[515]: svprogs able to send cmd to client on connect
281 extern qboolean csqc_loaded;
286 Sends the first message from the server to a connected client.
287 This will be sent on the initial connection and upon each server load.
290 void SV_SendServerinfo (client_t *client)
295 // we know that this client has a netconnection and thus is not a bot
297 // edicts get reallocated on level changes, so we need to update it here
298 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
300 // clear cached stuff that depends on the level
301 client->weaponmodel[0] = 0;
302 client->weaponmodelindex = 0;
304 // LordHavoc: clear entityframe tracking
305 client->latestframenum = 0;
307 if (client->entitydatabase)
308 EntityFrame_FreeDatabase(client->entitydatabase);
309 if (client->entitydatabase4)
310 EntityFrame4_FreeDatabase(client->entitydatabase4);
311 if (client->entitydatabase5)
312 EntityFrame5_FreeDatabase(client->entitydatabase5);
314 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
316 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
317 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
318 else if (sv.protocol == PROTOCOL_DARKPLACES4)
319 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
321 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
324 SZ_Clear (&client->netconnection->message);
325 MSG_WriteByte (&client->netconnection->message, svc_print);
326 dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
327 MSG_WriteString (&client->netconnection->message,message);
329 // FIXME: LordHavoc: this does not work on dedicated servers, needs fixing.
330 //[515]: init csprogs according to version of svprogs, check the crc, etc.
331 if(csqc_loaded && (cls.state == ca_dedicated || PRVM_NUM_FOR_EDICT(client->edict) != 1))
333 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
335 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i;%s\n", csqc_progcrc.integer, SV_InitCmd));
337 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", csqc_progcrc.integer));
340 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
341 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
342 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
344 if (!coop.integer && deathmatch.integer)
345 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
347 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
349 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
351 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
352 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
353 MSG_WriteByte (&client->netconnection->message, 0);
355 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
356 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
357 MSG_WriteByte (&client->netconnection->message, 0);
360 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
361 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
362 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
365 MSG_WriteByte (&client->netconnection->message, svc_setview);
366 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
368 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
369 MSG_WriteByte (&client->netconnection->message, 1);
371 client->spawned = false; // need prespawn, spawn, etc
378 Initializes a client_t for a new net connection. This will only be called
379 once for a player each game, not once for each level change.
382 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
386 float spawn_parms[NUM_SPAWN_PARMS];
388 client = svs.clients + clientnum;
390 if(netconnection)//[515]: bots don't play with csqc =)
391 EntityFrameCSQC_InitClientVersions(clientnum, false);
393 // set up the client_t
395 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
396 memset (client, 0, sizeof(*client));
397 client->active = true;
398 client->netconnection = netconnection;
400 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
402 strcpy(client->name, "unconnected");
403 strcpy(client->old_name, "unconnected");
404 client->spawned = false;
405 client->edict = PRVM_EDICT_NUM(clientnum+1);
406 if (client->netconnection)
407 client->netconnection->message.allowoverflow = true; // we can catch it
408 // updated by receiving "rate" command from client
409 client->rate = NET_MINRATE;
410 // no limits for local player
411 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
412 client->rate = 1000000000;
413 client->connecttime = realtime;
416 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
419 // call the progs to get default spawn parms for the new client
420 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
421 prog->globals.server->self = 0;
422 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
423 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
424 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
426 // set up the entity for this client (including .colormap, .team, etc)
427 PRVM_ED_ClearEdict(client->edict);
430 // don't call SendServerinfo for a fresh botclient because its fields have
431 // not been set up by the qc yet
432 if (client->netconnection)
433 SV_SendServerinfo (client);
435 client->spawned = true;
440 ===============================================================================
444 ===============================================================================
453 void SV_ClearDatagram (void)
455 SZ_Clear (&sv.datagram);
459 =============================================================================
461 The PVS must include a small area around the client to allow head bobbing
462 or other small motion on the client side. Otherwise, a bob might cause an
463 entity that should be visible to not show up, especially when the bob
466 =============================================================================
469 int sv_writeentitiestoclient_pvsbytes;
470 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
472 static int numsendentities;
473 static entity_state_t sendentities[MAX_EDICTS];
474 static entity_state_t *sendentitiesindex[MAX_EDICTS];
476 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
479 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
480 unsigned int customizeentityforclient;
482 vec3_t cullmins, cullmaxs;
486 // EF_NODRAW prevents sending for any reason except for your own
487 // client, so we must keep all clients in this superset
488 effects = (unsigned)ent->fields.server->effects;
490 // we can omit invisible entities with no effects that are not clients
491 // LordHavoc: this could kill tags attached to an invisible entity, I
492 // just hope we never have to support that case
493 i = (int)ent->fields.server->modelindex;
494 modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
497 i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
498 glowsize = (unsigned char)bound(0, i, 255);
499 if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
500 flags |= RENDER_GLOWTRAIL;
502 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
503 light[0] = (unsigned short)bound(0, f, 65535);
504 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
505 light[1] = (unsigned short)bound(0, f, 65535);
506 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
507 light[2] = (unsigned short)bound(0, f, 65535);
508 f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
509 light[3] = (unsigned short)bound(0, f, 65535);
510 lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
511 lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
513 if (gamemode == GAME_TENEBRAE)
515 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
519 lightpflags |= PFLAGS_FULLDYNAMIC;
521 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
525 light[0] = (int)(0.2*256);
526 light[1] = (int)(1.0*256);
527 light[2] = (int)(0.2*256);
529 lightpflags |= PFLAGS_FULLDYNAMIC;
533 specialvisibilityradius = 0;
534 if (lightpflags & PFLAGS_FULLDYNAMIC)
535 specialvisibilityradius = max(specialvisibilityradius, light[3]);
537 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
538 if (flags & RENDER_GLOWTRAIL)
539 specialvisibilityradius = max(specialvisibilityradius, 100);
540 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
542 if (effects & EF_BRIGHTFIELD)
543 specialvisibilityradius = max(specialvisibilityradius, 80);
544 if (effects & EF_MUZZLEFLASH)
545 specialvisibilityradius = max(specialvisibilityradius, 100);
546 if (effects & EF_BRIGHTLIGHT)
547 specialvisibilityradius = max(specialvisibilityradius, 400);
548 if (effects & EF_DIMLIGHT)
549 specialvisibilityradius = max(specialvisibilityradius, 200);
550 if (effects & EF_RED)
551 specialvisibilityradius = max(specialvisibilityradius, 200);
552 if (effects & EF_BLUE)
553 specialvisibilityradius = max(specialvisibilityradius, 200);
554 if (effects & EF_FLAME)
555 specialvisibilityradius = max(specialvisibilityradius, 250);
556 if (effects & EF_STARDUST)
557 specialvisibilityradius = max(specialvisibilityradius, 100);
560 // early culling checks
561 // (final culling is done by SV_MarkWriteEntityStateToClient)
562 customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_customizeentityforclient)->function;
563 if (!customizeentityforclient)
565 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
567 // this 2 billion unit check is actually to detect NAN origins
568 // (we really don't want to send those)
569 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
577 VectorCopy(ent->fields.server->origin, cs->origin);
578 VectorCopy(ent->fields.server->angles, cs->angles);
580 cs->effects = effects;
581 cs->colormap = (unsigned)ent->fields.server->colormap;
582 cs->modelindex = modelindex;
583 cs->skin = (unsigned)ent->fields.server->skin;
584 cs->frame = (unsigned)ent->fields.server->frame;
585 cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict;
586 cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)->edict;
587 cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict;
588 cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict;
589 cs->customizeentityforclient = customizeentityforclient;
590 cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict;
591 cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
592 cs->glowsize = glowsize;
594 // don't need to init cs->colormod because the defaultstate did that for us
595 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
596 val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod);
597 if (val->vector[0] || val->vector[1] || val->vector[2])
599 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
600 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
601 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
604 cs->modelindex = modelindex;
607 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f);
611 cs->alpha = (unsigned char)bound(0, i, 255);
614 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float);
618 cs->alpha = (unsigned char)bound(0, i, 255);
622 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f);
626 cs->scale = (unsigned char)bound(0, i, 255);
630 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_color)->_float);
632 cs->glowcolor = (int)f;
634 if (PRVM_GETEDICTFIELDVALUE(ent, eval_fullbright)->_float)
635 cs->effects |= EF_FULLBRIGHT;
637 if (ent->fields.server->movetype == MOVETYPE_STEP)
638 cs->flags |= RENDER_STEP;
639 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)
640 cs->flags |= RENDER_LOWPRECISION;
641 if (ent->fields.server->colormap >= 1024)
642 cs->flags |= RENDER_COLORMAPPED;
643 if (cs->viewmodelforclient)
644 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
646 cs->light[0] = light[0];
647 cs->light[1] = light[1];
648 cs->light[2] = light[2];
649 cs->light[3] = light[3];
650 cs->lightstyle = lightstyle;
651 cs->lightpflags = lightpflags;
653 cs->specialvisibilityradius = specialvisibilityradius;
655 // calculate the visible box of this entity (don't use the physics box
656 // as that is often smaller than a model, and would not count
657 // specialvisibilityradius)
658 if ((model = sv.models[modelindex]))
660 float scale = cs->scale * (1.0f / 16.0f);
661 if (cs->angles[0] || cs->angles[2]) // pitch and roll
663 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
664 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
666 else if (cs->angles[1])
668 VectorMA(cs->origin, scale, model->yawmins, cullmins);
669 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
673 VectorMA(cs->origin, scale, model->normalmins, cullmins);
674 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
679 // if there is no model (or it could not be loaded), use the physics box
680 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
681 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
683 if (specialvisibilityradius)
685 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
686 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
687 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
688 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
689 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
690 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
692 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
694 VectorCopy(cullmins, ent->priv.server->cullmins);
695 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
696 ent->priv.server->pvs_numclusters = -1;
697 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
699 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
700 if (i <= MAX_ENTITYCLUSTERS)
701 ent->priv.server->pvs_numclusters = i;
708 void SV_PrepareEntitiesForSending(void)
712 // send all entities that touch the pvs
714 sendentitiesindex[0] = NULL;
715 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
716 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
718 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
720 sendentitiesindex[e] = sendentities + numsendentities;
726 static int sententitiesmark = 0;
727 static int sententities[MAX_EDICTS];
728 static int sententitiesconsideration[MAX_EDICTS];
729 static int sv_writeentitiestoclient_culled_pvs;
730 static int sv_writeentitiestoclient_culled_trace;
731 static int sv_writeentitiestoclient_visibleentities;
732 static int sv_writeentitiestoclient_totalentities;
733 //static entity_frame_t sv_writeentitiestoclient_entityframe;
734 static int sv_writeentitiestoclient_clentnum;
735 static vec3_t sv_writeentitiestoclient_testeye;
736 static client_t *sv_writeentitiestoclient_client;
738 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
745 if (sententitiesconsideration[s->number] == sententitiesmark)
747 sententitiesconsideration[s->number] = sententitiesmark;
748 sv_writeentitiestoclient_totalentities++;
750 if (s->customizeentityforclient)
752 prog->globals.server->self = s->number;
753 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
754 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
755 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
759 // never reject player
760 if (s->number != sv_writeentitiestoclient_clentnum)
762 // check various rejection conditions
763 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
765 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
767 if (s->effects & EF_NODRAW)
769 // LordHavoc: only send entities with a model or important effects
770 if (!s->modelindex && s->specialvisibilityradius == 0)
773 // viewmodels don't have visibility checking
774 if (s->viewmodelforclient)
776 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
779 else if (s->tagentity)
781 // tag attached entities simply check their parent
782 if (!sendentitiesindex[s->tagentity])
784 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
785 if (sententities[s->tagentity] != sententitiesmark)
788 // always send world submodels in newer protocols because they don't
789 // generate much traffic (in old protocols they hog bandwidth)
790 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)))
792 // entity has survived every check so far, check if visible
793 ed = PRVM_EDICT_NUM(s->number);
795 // if not touching a visible leaf
796 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
798 if (ed->priv.server->pvs_numclusters < 0)
800 // entity too big for clusters list
801 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
803 sv_writeentitiestoclient_culled_pvs++;
810 // check cached clusters list
811 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
812 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
814 if (i == ed->priv.server->pvs_numclusters)
816 sv_writeentitiestoclient_culled_pvs++;
822 // or not seen by random tracelines
823 if (sv_cullentities_trace.integer && !isbmodel)
825 // LordHavoc: test center first
826 testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
827 testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
828 testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
829 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
830 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
831 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
834 // LordHavoc: test random offsets, to maximize chance of detection
835 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
836 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
837 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
838 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
839 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
840 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
843 if (s->specialvisibilityradius)
845 // LordHavoc: test random offsets, to maximize chance of detection
846 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
847 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
848 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
849 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
850 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
851 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
855 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
857 sv_writeentitiestoclient_culled_trace++;
864 // this just marks it for sending
865 // FIXME: it would be more efficient to send here, but the entity
866 // compressor isn't that flexible
867 sv_writeentitiestoclient_visibleentities++;
868 sententities[s->number] = sententitiesmark;
871 entity_state_t sendstates[MAX_EDICTS];
872 extern int csqc_clent;
874 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
876 int i, numsendstates;
879 // if there isn't enough space to accomplish anything, skip it
880 if (msg->cursize + 25 > msg->maxsize)
883 sv_writeentitiestoclient_client = client;
885 sv_writeentitiestoclient_culled_pvs = 0;
886 sv_writeentitiestoclient_culled_trace = 0;
887 sv_writeentitiestoclient_visibleentities = 0;
888 sv_writeentitiestoclient_totalentities = 0;
890 // find the client's PVS
891 // the real place being tested from
892 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
893 sv_writeentitiestoclient_pvsbytes = 0;
894 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
895 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
897 csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
901 for (i = 0;i < numsendentities;i++)
902 SV_MarkWriteEntityStateToClient(sendentities + i);
905 for (i = 0;i < numsendentities;i++)
907 if (sententities[sendentities[i].number] == sententitiesmark)
909 s = &sendstates[numsendstates++];
910 *s = sendentities[i];
911 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
912 s->flags |= RENDER_EXTERIORMODEL;
916 if (sv_cullentities_stats.integer)
917 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);
919 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
921 if (client->entitydatabase5)
922 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
923 else if (client->entitydatabase4)
924 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
925 else if (client->entitydatabase)
926 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
928 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
937 void SV_CleanupEnts (void)
942 ent = PRVM_NEXT_EDICT(prog->edicts);
943 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
944 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
949 SV_WriteClientdataToMessage
953 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
965 // send a damage message
967 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
969 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
970 MSG_WriteByte (msg, svc_damage);
971 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
972 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
973 for (i=0 ; i<3 ; i++)
974 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
976 ent->fields.server->dmg_take = 0;
977 ent->fields.server->dmg_save = 0;
981 // send the current viewpos offset from the view entity
983 SV_SetIdealPitch (); // how much to look up / down ideally
985 // a fixangle might get lost in a dropped packet. Oh well.
986 if ( ent->fields.server->fixangle )
988 MSG_WriteByte (msg, svc_setangle);
989 for (i=0 ; i < 3 ; i++)
990 MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
991 ent->fields.server->fixangle = 0;
994 // stuff the sigil bits into the high bits of items for sbar, or else
996 val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
997 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
998 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1000 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1002 VectorClear(punchvector);
1003 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
1004 VectorCopy(val->vector, punchvector);
1006 // cache weapon model name and index in client struct to save time
1007 // (this search can be almost 1% of cpu time!)
1008 s = PRVM_GetString(ent->fields.server->weaponmodel);
1009 if (strcmp(s, client->weaponmodel))
1011 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1012 client->weaponmodelindex = SV_ModelIndex(s, 1);
1016 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
1017 viewzoom = (int)(val->_float * 255.0f);
1023 if ((int)ent->fields.server->flags & FL_ONGROUND)
1024 bits |= SU_ONGROUND;
1025 if (ent->fields.server->waterlevel >= 2)
1027 if (ent->fields.server->idealpitch)
1028 bits |= SU_IDEALPITCH;
1030 for (i=0 ; i<3 ; i++)
1032 if (ent->fields.server->punchangle[i])
1033 bits |= (SU_PUNCH1<<i);
1034 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1036 bits |= (SU_PUNCHVEC1<<i);
1037 if (ent->fields.server->velocity[i])
1038 bits |= (SU_VELOCITY1<<i);
1041 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1042 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1043 stats[STAT_ITEMS] = items;
1044 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1045 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1046 stats[STAT_WEAPON] = client->weaponmodelindex;
1047 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1048 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1049 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1050 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1051 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1052 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1053 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1054 stats[STAT_VIEWZOOM] = viewzoom;
1055 // the QC bumps these itself by sending svc_'s, so we have to keep them
1056 // zero or they'll be corrected by the engine
1057 //stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1058 //stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1059 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1060 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1062 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)
1064 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1066 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1067 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1069 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1070 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1071 if (viewzoom != 255)
1072 bits |= SU_VIEWZOOM;
1077 if (bits >= 16777216)
1081 MSG_WriteByte (msg, svc_clientdata);
1082 MSG_WriteShort (msg, bits);
1083 if (bits & SU_EXTEND1)
1084 MSG_WriteByte(msg, bits >> 16);
1085 if (bits & SU_EXTEND2)
1086 MSG_WriteByte(msg, bits >> 24);
1088 if (bits & SU_VIEWHEIGHT)
1089 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1091 if (bits & SU_IDEALPITCH)
1092 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1094 for (i=0 ; i<3 ; i++)
1096 if (bits & (SU_PUNCH1<<i))
1098 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1099 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1101 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1103 if (bits & (SU_PUNCHVEC1<<i))
1105 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1106 MSG_WriteCoord16i(msg, punchvector[i]);
1108 MSG_WriteCoord32f(msg, punchvector[i]);
1110 if (bits & (SU_VELOCITY1<<i))
1112 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1113 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1115 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1119 if (bits & SU_ITEMS)
1120 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1122 if (sv.protocol == PROTOCOL_DARKPLACES5)
1124 if (bits & SU_WEAPONFRAME)
1125 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1126 if (bits & SU_ARMOR)
1127 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1128 if (bits & SU_WEAPON)
1129 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1130 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1131 MSG_WriteShort (msg, stats[STAT_AMMO]);
1132 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1133 MSG_WriteShort (msg, stats[STAT_NAILS]);
1134 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1135 MSG_WriteShort (msg, stats[STAT_CELLS]);
1136 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1137 if (bits & SU_VIEWZOOM)
1138 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1140 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)
1142 if (bits & SU_WEAPONFRAME)
1143 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1144 if (bits & SU_ARMOR)
1145 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1146 if (bits & SU_WEAPON)
1147 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1148 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1149 MSG_WriteByte (msg, stats[STAT_AMMO]);
1150 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1151 MSG_WriteByte (msg, stats[STAT_NAILS]);
1152 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1153 MSG_WriteByte (msg, stats[STAT_CELLS]);
1154 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1156 for (i = 0;i < 32;i++)
1157 if (stats[STAT_WEAPON] & (1<<i))
1159 MSG_WriteByte (msg, i);
1162 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1163 if (bits & SU_VIEWZOOM)
1165 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1166 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1168 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1174 =======================
1175 SV_SendClientDatagram
1176 =======================
1178 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1179 void SV_SendClientDatagram (client_t *client)
1181 int rate, maxrate, maxsize, maxsize2;
1183 int stats[MAX_CL_STATS];
1185 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1187 // for good singleplayer, send huge packets
1188 maxsize = sizeof(sv_sendclientdatagram_buf);
1189 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1191 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)
1193 // no rate limiting support on older protocols because dp protocols
1194 // 1-4 kick the client off if they overflow, and quake protocol shows
1195 // less than the full entity set if rate limited
1201 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1202 maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE);
1203 if (sv_maxrate.integer != maxrate)
1204 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1206 // this rate limiting does not understand sys_ticrate 0
1207 // (but no one should be running that on a server!)
1208 rate = bound(NET_MINRATE, client->rate, maxrate);
1209 rate = (int)(client->rate * sys_ticrate.value);
1210 maxsize = bound(100, rate, 1400);
1214 msg.data = sv_sendclientdatagram_buf;
1215 msg.maxsize = maxsize;
1218 if (host_client->spawned)
1220 MSG_WriteByte (&msg, svc_time);
1221 MSG_WriteFloat (&msg, sv.time);
1223 // add the client specific data to the datagram
1224 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1225 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1226 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1228 // expand packet size to allow effects to go over the rate limit
1229 // (dropping them is FAR too ugly)
1230 msg.maxsize = maxsize2;
1232 // copy the server datagram if there is space
1233 // FIXME: put in delayed queue of effects to send
1234 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1235 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1237 else if (realtime > client->keepalivetime)
1239 // the player isn't totally in the game yet
1240 // send small keepalive messages if too much time has passed
1241 client->keepalivetime = realtime + 5;
1242 MSG_WriteChar (&msg, svc_nop);
1245 // send the datagram
1246 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1250 =======================
1251 SV_UpdateToReliableMessages
1252 =======================
1254 void SV_UpdateToReliableMessages (void)
1263 // check for changes to be sent over the reliable streams
1264 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1266 // update the host_client fields we care about according to the entity fields
1267 host_client->edict = PRVM_EDICT_NUM(i+1);
1270 name = PRVM_GetString(host_client->edict->fields.server->netname);
1273 // always point the string back at host_client->name to keep it safe
1274 strlcpy (host_client->name, name, sizeof (host_client->name));
1275 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1276 if (strcmp(host_client->old_name, host_client->name))
1278 if (host_client->spawned)
1279 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1280 strcpy(host_client->old_name, host_client->name);
1281 // send notification to all clients
1282 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1283 MSG_WriteByte (&sv.reliable_datagram, i);
1284 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1287 // DP_SV_CLIENTCOLORS
1288 // this is always found (since it's added by the progs loader)
1289 if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1290 host_client->colors = (int)val->_float;
1291 if (host_client->old_colors != host_client->colors)
1293 host_client->old_colors = host_client->colors;
1294 // send notification to all clients
1295 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1296 MSG_WriteByte (&sv.reliable_datagram, i);
1297 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1300 // NEXUIZ_PLAYERMODEL
1301 if( eval_playermodel ) {
1302 model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string);
1305 // always point the string back at host_client->name to keep it safe
1306 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1307 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1310 // NEXUIZ_PLAYERSKIN
1311 if( eval_playerskin ) {
1312 skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string);
1315 // always point the string back at host_client->name to keep it safe
1316 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1317 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1321 host_client->frags = (int)host_client->edict->fields.server->frags;
1322 if (host_client->old_frags != host_client->frags)
1324 host_client->old_frags = host_client->frags;
1325 // send notification to all clients
1326 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1327 MSG_WriteByte (&sv.reliable_datagram, i);
1328 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1332 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1333 if (client->netconnection)
1334 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1336 SZ_Clear (&sv.reliable_datagram);
1341 =======================
1342 SV_SendClientMessages
1343 =======================
1345 void SV_SendClientMessages (void)
1347 int i, prepared = false;
1349 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1350 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1352 // update frags, names, etc
1353 SV_UpdateToReliableMessages();
1355 // build individual updates
1356 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1358 if (!host_client->active)
1360 if (!host_client->netconnection)
1363 if (host_client->netconnection->message.overflowed)
1365 SV_DropClient (true); // if the message couldn't send, kick off
1372 // only prepare entities once per frame
1373 SV_PrepareEntitiesForSending();
1375 SV_SendClientDatagram (host_client);
1378 // clear muzzle flashes
1384 ==============================================================================
1388 ==============================================================================
1397 int SV_ModelIndex(const char *s, int precachemode)
1399 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1400 char filename[MAX_QPATH];
1404 //if (precachemode == 2)
1406 strlcpy(filename, s, sizeof(filename));
1407 for (i = 2;i < limit;i++)
1409 if (!sv.model_precache[i][0])
1413 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))
1415 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1418 if (precachemode == 1)
1419 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1420 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1421 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1422 if (sv.state != ss_loading)
1424 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1425 MSG_WriteShort(&sv.reliable_datagram, i);
1426 MSG_WriteString(&sv.reliable_datagram, filename);
1430 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1433 if (!strcmp(sv.model_precache[i], filename))
1436 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1446 int SV_SoundIndex(const char *s, int precachemode)
1448 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1449 char filename[MAX_QPATH];
1453 //if (precachemode == 2)
1455 strlcpy(filename, s, sizeof(filename));
1456 for (i = 1;i < limit;i++)
1458 if (!sv.sound_precache[i][0])
1462 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))
1464 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1467 if (precachemode == 1)
1468 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1469 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1470 if (sv.state != ss_loading)
1472 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1473 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1474 MSG_WriteString(&sv.reliable_datagram, filename);
1478 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1481 if (!strcmp(sv.sound_precache[i], filename))
1484 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1494 void SV_CreateBaseline (void)
1496 int i, entnum, large;
1497 prvm_edict_t *svent;
1499 // LordHavoc: clear *all* states (note just active ones)
1500 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1502 // get the current server version
1503 svent = PRVM_EDICT_NUM(entnum);
1505 // LordHavoc: always clear state values, whether the entity is in use or not
1506 svent->priv.server->baseline = defaultstate;
1508 if (svent->priv.server->free)
1510 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1513 // create entity baseline
1514 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1515 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1516 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1517 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1518 if (entnum > 0 && entnum <= svs.maxclients)
1520 svent->priv.server->baseline.colormap = entnum;
1521 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1525 svent->priv.server->baseline.colormap = 0;
1526 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1530 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1533 // add to the message
1535 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1537 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1538 MSG_WriteShort (&sv.signon, entnum);
1542 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1543 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1547 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1548 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1550 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1551 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1552 for (i=0 ; i<3 ; i++)
1554 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1555 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1565 Grabs the current state of each client for saving across the
1566 transition to another level
1569 void SV_SaveSpawnparms (void)
1573 svs.serverflags = (int)prog->globals.server->serverflags;
1575 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1577 if (!host_client->active)
1580 // call the progs to get default spawn parms for the new client
1581 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1582 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1583 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1584 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1588 void SV_IncreaseEdicts(void)
1592 int oldmax_edicts = prog->max_edicts;
1593 void *oldedictsengineprivate = prog->edictprivate;
1594 void *oldedictsfields = prog->edictsfields;
1595 void *oldmoved_edicts = sv.moved_edicts;
1597 if (prog->max_edicts >= MAX_EDICTS)
1600 // links don't survive the transition, so unlink everything
1601 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1603 if (!ent->priv.server->free)
1604 SV_UnlinkEdict(prog->edicts + i);
1605 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1609 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
1610 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1611 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
1612 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1614 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
1615 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
1617 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1619 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1620 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1621 // link every entity except world
1622 if (!ent->priv.server->free)
1623 SV_LinkEdict(ent, false);
1626 PR_Free(oldedictsengineprivate);
1627 PR_Free(oldedictsfields);
1628 PR_Free(oldmoved_edicts);
1635 This is called at the start of each level
1638 extern float scr_centertime_off;
1640 void SV_SpawnServer (const char *server)
1645 model_t *worldmodel;
1646 char modelname[sizeof(sv.modelname)];
1648 Con_DPrintf("SpawnServer: %s\n", server);
1650 if (cls.state != ca_dedicated)
1651 SCR_BeginLoadingPlaque();
1653 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
1654 worldmodel = Mod_ForName(modelname, false, true, true);
1655 if (!worldmodel || !worldmodel->TraceBox)
1657 Con_Printf("Couldn't load map %s\n", modelname);
1661 // let's not have any servers with no name
1662 if (hostname.string[0] == 0)
1663 Cvar_Set ("hostname", "UNNAMED");
1664 scr_centertime_off = 0;
1666 svs.changelevel_issued = false; // now safe to issue another
1669 // tell all connected clients that we are going to a new level
1674 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1676 if (client->netconnection)
1678 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
1679 MSG_WriteString(&client->netconnection->message, "reconnect\n");
1686 NetConn_OpenServerPorts(true);
1690 // make cvars consistant
1693 Cvar_SetValue ("deathmatch", 0);
1694 // LordHavoc: it can be useful to have skills outside the range 0-3...
1695 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
1696 //Cvar_SetValue ("skill", (float)current_skill);
1697 current_skill = (int)(skill.value + 0.5);
1700 // set up the new server
1702 memset (&sv, 0, sizeof(sv));
1703 // if running a local client, make sure it doesn't try to access the last
1704 // level's data which is no longer valiud
1711 strlcpy (sv.name, server, sizeof (sv.name));
1713 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
1714 if (sv.protocol == PROTOCOL_UNKNOWN)
1717 Protocol_Names(buffer, sizeof(buffer));
1718 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
1719 sv.protocol = PROTOCOL_QUAKE;
1724 // load progs to get entity field count
1725 //PR_LoadProgs ( sv_progs.string );
1727 // allocate server memory
1728 /*// start out with just enough room for clients and a reasonable estimate of entities
1729 prog->max_edicts = max(svs.maxclients + 1, 512);
1730 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
1732 // prvm_edict_t structures (hidden from progs)
1733 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
1734 // engine private structures (hidden from progs)
1735 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1736 // progs fields, often accessed by server
1737 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
1738 // used by PushMove to move back pushed entities
1739 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1740 /*for (i = 0;i < prog->max_edicts;i++)
1742 ent = prog->edicts + i;
1743 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1744 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1747 // reset client csqc entity versions right away.
1748 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1749 EntityFrameCSQC_InitClientVersions(i, true);
1751 sv.datagram.maxsize = sizeof(sv.datagram_buf);
1752 sv.datagram.cursize = 0;
1753 sv.datagram.data = sv.datagram_buf;
1755 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
1756 sv.reliable_datagram.cursize = 0;
1757 sv.reliable_datagram.data = sv.reliable_datagram_buf;
1759 sv.signon.maxsize = sizeof(sv.signon_buf);
1760 sv.signon.cursize = 0;
1761 sv.signon.data = sv.signon_buf;
1763 // leave slots at start for clients only
1764 //prog->num_edicts = svs.maxclients+1;
1766 sv.state = ss_loading;
1767 prog->allowworldwrites = true;
1770 *prog->time = sv.time = 1.0;
1773 worldmodel->used = true;
1775 strlcpy (sv.name, server, sizeof (sv.name));
1776 strcpy(sv.modelname, modelname);
1777 sv.worldmodel = worldmodel;
1778 sv.models[1] = sv.worldmodel;
1781 // clear world interaction links
1785 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
1787 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
1788 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
1789 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
1791 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
1792 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
1796 // load the rest of the entities
1798 // AK possible hack since num_edicts is still 0
1799 ent = PRVM_EDICT_NUM(0);
1800 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
1801 ent->priv.server->free = false;
1802 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
1803 ent->fields.server->modelindex = 1; // world model
1804 ent->fields.server->solid = SOLID_BSP;
1805 ent->fields.server->movetype = MOVETYPE_PUSH;
1808 prog->globals.server->coop = coop.integer;
1810 prog->globals.server->deathmatch = deathmatch.integer;
1812 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
1814 // serverflags are for cross level information (sigils)
1815 prog->globals.server->serverflags = svs.serverflags;
1817 // we need to reset the spawned flag on all connected clients here so that
1818 // their thinks don't run during startup (before PutClientInServer)
1819 // we also need to set up the client entities now
1820 // and we need to set the ->edict pointers to point into the progs edicts
1821 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1823 host_client->spawned = false;
1824 host_client->edict = PRVM_EDICT_NUM(i + 1);
1825 PRVM_ED_ClearEdict(host_client->edict);
1828 // load replacement entity file if found
1829 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
1831 Con_Printf("Loaded maps/%s.ent\n", sv.name);
1832 PRVM_ED_LoadFromFile (entities);
1836 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
1839 // LordHavoc: clear world angles (to fix e3m3.bsp)
1840 VectorClear(prog->edicts->fields.server->angles);
1842 // all setup is completed, any further precache statements are errors
1843 sv.state = ss_active;
1844 prog->allowworldwrites = false;
1846 // run two frames to allow everything to settle
1847 for (i = 0;i < 2;i++)
1855 // create a baseline for more efficient communications
1856 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1857 SV_CreateBaseline ();
1859 // send serverinfo to all connected clients, and set up botclients coming back from a level change
1860 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1862 if (!host_client->active)
1864 if (host_client->netconnection)
1865 SV_SendServerinfo(host_client);
1869 // if client is a botclient coming from a level change, we need to
1870 // set up client info that normally requires networking
1872 // copy spawn parms out of the client_t
1873 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
1874 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
1876 // call the spawn function
1877 host_client->clientconnectcalled = true;
1878 prog->globals.server->time = sv.time;
1879 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1880 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1881 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1882 host_client->spawned = true;
1886 Con_DPrint("Server spawned.\n");
1887 NetConn_Heartbeat (2);
1892 /////////////////////////////////////////////////////
1895 void SV_VM_CB_BeginIncreaseEdicts(void)
1900 PRVM_Free( sv.moved_edicts );
1901 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1903 // links don't survive the transition, so unlink everything
1904 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1906 if (!ent->priv.server->free)
1907 SV_UnlinkEdict(prog->edicts + i);
1908 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1913 void SV_VM_CB_EndIncreaseEdicts(void)
1918 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1920 // link every entity except world
1921 if (!ent->priv.server->free)
1922 SV_LinkEdict(ent, false);
1926 void SV_VM_CB_InitEdict(prvm_edict_t *e)
1928 // LordHavoc: for consistency set these here
1929 int num = PRVM_NUM_FOR_EDICT(e) - 1;
1931 e->priv.server->move = false; // don't move on first frame
1933 if (num >= 0 && num < svs.maxclients)
1936 // set colormap and team on newly created player entity
1937 e->fields.server->colormap = num + 1;
1938 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
1939 // set netname/clientcolors back to client values so that
1940 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
1942 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
1943 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
1944 val->_float = svs.clients[num].colors;
1945 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
1946 if( eval_playermodel )
1947 PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
1948 if( eval_playerskin )
1949 PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
1953 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
1955 SV_UnlinkEdict (ed); // unlink from world bsp
1957 ed->fields.server->model = 0;
1958 ed->fields.server->takedamage = 0;
1959 ed->fields.server->modelindex = 0;
1960 ed->fields.server->colormap = 0;
1961 ed->fields.server->skin = 0;
1962 ed->fields.server->frame = 0;
1963 VectorClear(ed->fields.server->origin);
1964 VectorClear(ed->fields.server->angles);
1965 ed->fields.server->nextthink = -1;
1966 ed->fields.server->solid = 0;
1969 void SV_VM_CB_CountEdicts(void)
1973 int active, models, solid, step;
1975 active = models = solid = step = 0;
1976 for (i=0 ; i<prog->num_edicts ; i++)
1978 ent = PRVM_EDICT_NUM(i);
1979 if (ent->priv.server->free)
1982 if (ent->fields.server->solid)
1984 if (ent->fields.server->model)
1986 if (ent->fields.server->movetype == MOVETYPE_STEP)
1990 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
1991 Con_Printf("active :%3i\n", active);
1992 Con_Printf("view :%3i\n", models);
1993 Con_Printf("touch :%3i\n", solid);
1994 Con_Printf("step :%3i\n", step);
1997 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
1999 // remove things from different skill levels or deathmatch
2000 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2002 if (deathmatch.integer)
2004 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2009 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2010 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2011 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2019 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)"};
2020 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2021 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2022 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2023 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2024 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2025 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2026 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2027 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2028 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2029 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2030 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2031 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2032 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2033 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2034 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2035 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2036 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2037 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2038 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2039 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2040 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2041 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2042 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2043 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2044 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2045 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2046 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2047 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2048 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2049 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2050 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2051 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2053 void SV_VM_Init(void)
2055 Cvar_RegisterVariable (&pr_checkextension);
2056 Cvar_RegisterVariable (&nomonsters);
2057 Cvar_RegisterVariable (&gamecfg);
2058 Cvar_RegisterVariable (&scratch1);
2059 Cvar_RegisterVariable (&scratch2);
2060 Cvar_RegisterVariable (&scratch3);
2061 Cvar_RegisterVariable (&scratch4);
2062 Cvar_RegisterVariable (&savedgamecfg);
2063 Cvar_RegisterVariable (&saved1);
2064 Cvar_RegisterVariable (&saved2);
2065 Cvar_RegisterVariable (&saved3);
2066 Cvar_RegisterVariable (&saved4);
2067 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2068 if (gamemode == GAME_NEHAHRA)
2070 Cvar_RegisterVariable (&nehx00);
2071 Cvar_RegisterVariable (&nehx01);
2072 Cvar_RegisterVariable (&nehx02);
2073 Cvar_RegisterVariable (&nehx03);
2074 Cvar_RegisterVariable (&nehx04);
2075 Cvar_RegisterVariable (&nehx05);
2076 Cvar_RegisterVariable (&nehx06);
2077 Cvar_RegisterVariable (&nehx07);
2078 Cvar_RegisterVariable (&nehx08);
2079 Cvar_RegisterVariable (&nehx09);
2080 Cvar_RegisterVariable (&nehx10);
2081 Cvar_RegisterVariable (&nehx11);
2082 Cvar_RegisterVariable (&nehx12);
2083 Cvar_RegisterVariable (&nehx13);
2084 Cvar_RegisterVariable (&nehx14);
2085 Cvar_RegisterVariable (&nehx15);
2086 Cvar_RegisterVariable (&nehx16);
2087 Cvar_RegisterVariable (&nehx17);
2088 Cvar_RegisterVariable (&nehx18);
2089 Cvar_RegisterVariable (&nehx19);
2091 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2094 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
2111 int eval_buttonchat;
2113 int eval_glow_trail;
2114 int eval_glow_color;
2118 int eval_renderamt; // HalfLife support
2119 int eval_rendermode; // HalfLife support
2120 int eval_fullbright;
2121 int eval_ammo_shells1;
2122 int eval_ammo_nails1;
2123 int eval_ammo_lava_nails;
2124 int eval_ammo_rockets1;
2125 int eval_ammo_multi_rockets;
2126 int eval_ammo_cells1;
2127 int eval_ammo_plasma;
2128 int eval_idealpitch;
2129 int eval_pitch_speed;
2130 int eval_viewmodelforclient;
2131 int eval_nodrawtoclient;
2132 int eval_exteriormodeltoclient;
2133 int eval_drawonlytoclient;
2137 int eval_punchvector;
2139 int eval_clientcolors;
2140 int eval_tag_entity;
2146 int eval_cursor_active;
2147 int eval_cursor_screen;
2148 int eval_cursor_trace_start;
2149 int eval_cursor_trace_endpos;
2150 int eval_cursor_trace_ent;
2152 int eval_playermodel;
2153 int eval_playerskin;
2154 int eval_SendEntity;
2156 int eval_customizeentityforclient;
2157 int eval_dphitcontentsmask;
2159 int gval_trace_dpstartcontents;
2160 int gval_trace_dphitcontents;
2161 int gval_trace_dphitq3surfaceflags;
2162 int gval_trace_dphittexturename;
2164 mfunction_t *SV_PlayerPhysicsQC;
2165 mfunction_t *EndFrameQC;
2166 //KrimZon - SERVER COMMANDS IN QUAKEC
2167 mfunction_t *SV_ParseClientCommandQC;
2169 ddef_t *PRVM_ED_FindGlobal(const char *name);
2171 void SV_VM_FindEdictFieldOffsets(void)
2173 eval_gravity = PRVM_ED_FindFieldOffset("gravity");
2174 eval_button3 = PRVM_ED_FindFieldOffset("button3");
2175 eval_button4 = PRVM_ED_FindFieldOffset("button4");
2176 eval_button5 = PRVM_ED_FindFieldOffset("button5");
2177 eval_button6 = PRVM_ED_FindFieldOffset("button6");
2178 eval_button7 = PRVM_ED_FindFieldOffset("button7");
2179 eval_button8 = PRVM_ED_FindFieldOffset("button8");
2180 eval_button9 = PRVM_ED_FindFieldOffset("button9");
2181 eval_button10 = PRVM_ED_FindFieldOffset("button10");
2182 eval_button11 = PRVM_ED_FindFieldOffset("button11");
2183 eval_button12 = PRVM_ED_FindFieldOffset("button12");
2184 eval_button13 = PRVM_ED_FindFieldOffset("button13");
2185 eval_button14 = PRVM_ED_FindFieldOffset("button14");
2186 eval_button15 = PRVM_ED_FindFieldOffset("button15");
2187 eval_button16 = PRVM_ED_FindFieldOffset("button16");
2188 eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
2189 eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
2190 eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
2191 eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
2192 eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
2193 eval_items2 = PRVM_ED_FindFieldOffset("items2");
2194 eval_scale = PRVM_ED_FindFieldOffset("scale");
2195 eval_alpha = PRVM_ED_FindFieldOffset("alpha");
2196 eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
2197 eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
2198 eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
2199 eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
2200 eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
2201 eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
2202 eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
2203 eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
2204 eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
2205 eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
2206 eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
2207 eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
2208 eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
2209 eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
2210 eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
2211 eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
2212 eval_ping = PRVM_ED_FindFieldOffset("ping");
2213 eval_movement = PRVM_ED_FindFieldOffset("movement");
2214 eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
2215 eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
2216 eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
2217 eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
2218 eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
2219 eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
2220 eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
2221 eval_color = PRVM_ED_FindFieldOffset("color");
2222 eval_style = PRVM_ED_FindFieldOffset("style");
2223 eval_pflags = PRVM_ED_FindFieldOffset("pflags");
2224 eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
2225 eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
2226 eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
2227 eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
2228 eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
2229 eval_colormod = PRVM_ED_FindFieldOffset("colormod");
2230 eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
2231 eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
2232 eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
2233 eval_Version = PRVM_ED_FindFieldOffset("Version");
2234 eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
2235 eval_dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
2237 // LordHavoc: allowing QuakeC to override the player movement code
2238 SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
2239 // LordHavoc: support for endframe
2240 EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
2241 //KrimZon - SERVER COMMANDS IN QUAKEC
2242 SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
2244 //[515]: init stufftext string (it is sent before svc_serverinfo)
2245 if(PRVM_ED_FindGlobal("SV_InitCmd") && PRVM_ED_FindGlobal("SV_InitCmd")->type & ev_string)
2246 SV_InitCmd = PRVM_G_STRING(PRVM_ED_FindGlobal("SV_InitCmd")->ofs);
2250 gval_trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
2251 gval_trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
2252 gval_trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
2253 gval_trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
2256 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2258 prvm_required_field_t reqfields[] =
2260 {ev_entity, "cursor_trace_ent"},
2261 {ev_entity, "drawonlytoclient"},
2262 {ev_entity, "exteriormodeltoclient"},
2263 {ev_entity, "nodrawtoclient"},
2264 {ev_entity, "tag_entity"},
2265 {ev_entity, "viewmodelforclient"},
2266 {ev_float, "alpha"},
2267 {ev_float, "ammo_cells1"},
2268 {ev_float, "ammo_lava_nails"},
2269 {ev_float, "ammo_multi_rockets"},
2270 {ev_float, "ammo_nails1"},
2271 {ev_float, "ammo_plasma"},
2272 {ev_float, "ammo_rockets1"},
2273 {ev_float, "ammo_shells1"},
2274 {ev_float, "button3"},
2275 {ev_float, "button4"},
2276 {ev_float, "button5"},
2277 {ev_float, "button6"},
2278 {ev_float, "button7"},
2279 {ev_float, "button8"},
2280 {ev_float, "button9"},
2281 {ev_float, "button10"},
2282 {ev_float, "button11"},
2283 {ev_float, "button12"},
2284 {ev_float, "button13"},
2285 {ev_float, "button14"},
2286 {ev_float, "button15"},
2287 {ev_float, "button16"},
2288 {ev_float, "buttonchat"},
2289 {ev_float, "buttonuse"},
2290 {ev_float, "clientcolors"},
2291 {ev_float, "cursor_active"},
2292 {ev_float, "fullbright"},
2293 {ev_float, "glow_color"},
2294 {ev_float, "glow_size"},
2295 {ev_float, "glow_trail"},
2296 {ev_float, "gravity"},
2297 {ev_float, "idealpitch"},
2298 {ev_float, "items2"},
2299 {ev_float, "light_lev"},
2300 {ev_float, "pflags"},
2302 {ev_float, "pitch_speed"},
2303 {ev_float, "pmodel"},
2304 {ev_float, "renderamt"}, // HalfLife support
2305 {ev_float, "rendermode"}, // HalfLife support
2306 {ev_float, "scale"},
2307 {ev_float, "style"},
2308 {ev_float, "tag_index"},
2309 {ev_float, "Version"},
2310 {ev_float, "viewzoom"},
2311 {ev_vector, "color"},
2312 {ev_vector, "colormod"},
2313 {ev_vector, "cursor_screen"},
2314 {ev_vector, "cursor_trace_endpos"},
2315 {ev_vector, "cursor_trace_start"},
2316 {ev_vector, "movement"},
2317 {ev_vector, "punchvector"},
2318 {ev_string, "playermodel"},
2319 {ev_string, "playerskin"},
2320 {ev_function, "SendEntity"},
2321 {ev_function, "customizeentityforclient"},
2324 void SV_VM_Setup(void)
2327 PRVM_InitProg( PRVM_SERVERPROG );
2329 // allocate the mempools
2330 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2331 prog->builtins = vm_sv_builtins;
2332 prog->numbuiltins = vm_sv_numbuiltins;
2333 prog->headercrc = PROGHEADER_CRC;
2334 prog->max_edicts = 512;
2335 prog->limit_edicts = MAX_EDICTS;
2336 prog->reserved_edicts = svs.maxclients;
2337 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2338 prog->name = "server";
2339 prog->extensionstring = vm_sv_extensions;
2340 prog->loadintoworld = true;
2342 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2343 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2344 prog->init_edict = SV_VM_CB_InitEdict;
2345 prog->free_edict = SV_VM_CB_FreeEdict;
2346 prog->count_edicts = SV_VM_CB_CountEdicts;
2347 prog->load_edict = SV_VM_CB_LoadEdict;
2348 prog->init_cmd = VM_SV_Cmd_Init;
2349 prog->reset_cmd = VM_SV_Cmd_Reset;
2350 prog->error_cmd = Host_Error;
2352 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2353 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
2354 SV_VM_FindEdictFieldOffsets();
2356 VM_AutoSentStats_Clear();//[515]: csqc
2357 EntityFrameCSQC_ClearVersions();//[515]: csqc
2362 void SV_VM_Begin(void)
2365 PRVM_SetProg( PRVM_SERVERPROG );
2367 *prog->time = (float) sv.time;
2370 void SV_VM_End(void)