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", "1", "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_edgefriction);
78 Cvar_RegisterVariable (&sv_stopspeed);
79 Cvar_RegisterVariable (&sv_maxspeed);
80 Cvar_RegisterVariable (&sv_maxairspeed);
81 Cvar_RegisterVariable (&sv_accelerate);
82 Cvar_RegisterVariable (&sv_idealpitchscale);
83 Cvar_RegisterVariable (&sv_aim);
84 Cvar_RegisterVariable (&sv_nostep);
85 Cvar_RegisterVariable (&sv_cullentities_pvs);
86 Cvar_RegisterVariable (&sv_cullentities_trace);
87 Cvar_RegisterVariable (&sv_cullentities_stats);
88 Cvar_RegisterVariable (&sv_entpatch);
89 Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
90 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
91 Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
92 Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
93 Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
94 Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
95 Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
96 Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
97 Cvar_RegisterVariable (&sv_protocolname);
98 Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
99 Cvar_RegisterVariable (&sv_maxrate);
100 Cvar_RegisterVariable (&sv_progs);
106 sv_mempool = Mem_AllocPool("server", 0, NULL);
109 static void SV_SaveEntFile_f(void)
111 char basename[MAX_QPATH];
112 if (!sv.active || !sv.worldmodel)
114 Con_Print("Not running a server\n");
117 FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
118 FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
123 =============================================================================
127 =============================================================================
134 Make sure the event gets sent to all clients
137 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
141 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
143 MSG_WriteByte (&sv.datagram, svc_particle);
144 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
145 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
146 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
147 for (i=0 ; i<3 ; i++)
154 MSG_WriteChar (&sv.datagram, v);
156 MSG_WriteByte (&sv.datagram, count);
157 MSG_WriteByte (&sv.datagram, color);
164 Make sure the event gets sent to all clients
167 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
169 if (modelindex >= 256 || startframe >= 256)
171 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
173 MSG_WriteByte (&sv.datagram, svc_effect2);
174 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
175 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
176 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
177 MSG_WriteShort (&sv.datagram, modelindex);
178 MSG_WriteShort (&sv.datagram, startframe);
179 MSG_WriteByte (&sv.datagram, framecount);
180 MSG_WriteByte (&sv.datagram, framerate);
184 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
186 MSG_WriteByte (&sv.datagram, svc_effect);
187 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
188 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
189 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
190 MSG_WriteByte (&sv.datagram, modelindex);
191 MSG_WriteByte (&sv.datagram, startframe);
192 MSG_WriteByte (&sv.datagram, framecount);
193 MSG_WriteByte (&sv.datagram, framerate);
201 Each entity can have eight independant sound sources, like voice,
204 Channel 0 is an auto-allocate channel, the others override anything
205 already running on that entity/channel pair.
207 An attenuation of 0 will play full volume everywhere in the level.
208 Larger attenuations will drop off. (max 4 attenuation)
212 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
214 int sound_num, field_mask, i, ent;
216 if (volume < 0 || volume > 255)
218 Con_Printf ("SV_StartSound: volume = %i\n", volume);
222 if (attenuation < 0 || attenuation > 4)
224 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
228 if (channel < 0 || channel > 7)
230 Con_Printf ("SV_StartSound: channel = %i\n", channel);
234 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
237 // find precache number for sound
238 sound_num = SV_SoundIndex(sample, 1);
242 ent = PRVM_NUM_FOR_EDICT(entity);
245 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
246 field_mask |= SND_VOLUME;
247 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
248 field_mask |= SND_ATTENUATION;
250 field_mask |= SND_LARGEENTITY;
251 if (sound_num >= 256 || channel >= 8)
252 field_mask |= SND_LARGESOUND;
254 // directed messages go only to the entity they are targeted on
255 MSG_WriteByte (&sv.datagram, svc_sound);
256 MSG_WriteByte (&sv.datagram, field_mask);
257 if (field_mask & SND_VOLUME)
258 MSG_WriteByte (&sv.datagram, volume);
259 if (field_mask & SND_ATTENUATION)
260 MSG_WriteByte (&sv.datagram, attenuation*64);
261 if (field_mask & SND_LARGEENTITY)
263 MSG_WriteShort (&sv.datagram, ent);
264 MSG_WriteByte (&sv.datagram, channel);
267 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
268 if (field_mask & SND_LARGESOUND)
269 MSG_WriteShort (&sv.datagram, sound_num);
271 MSG_WriteByte (&sv.datagram, sound_num);
272 for (i = 0;i < 3;i++)
273 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
277 ==============================================================================
281 ==============================================================================
284 static const char *SV_InitCmd; //[515]: svprogs able to send cmd to client on connect
285 extern qboolean csqc_loaded;
290 Sends the first message from the server to a connected client.
291 This will be sent on the initial connection and upon each server load.
294 void SV_SendServerinfo (client_t *client)
299 // we know that this client has a netconnection and thus is not a bot
301 // edicts get reallocated on level changes, so we need to update it here
302 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
304 // clear cached stuff that depends on the level
305 client->weaponmodel[0] = 0;
306 client->weaponmodelindex = 0;
308 // LordHavoc: clear entityframe tracking
309 client->latestframenum = 0;
311 SZ_Clear (&client->netconnection->message);
312 MSG_WriteByte (&client->netconnection->message, svc_print);
313 dpsnprintf (message, sizeof (message), "\002\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
314 MSG_WriteString (&client->netconnection->message,message);
316 // FIXME: LordHavoc: this does not work on dedicated servers, needs fixing.
317 //[515]: init csprogs according to version of svprogs, check the crc, etc.
318 if(csqc_loaded && (cls.state == ca_dedicated || PRVM_NUM_FOR_EDICT(client->edict) != 1))
320 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
322 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i;%s\n", csqc_progcrc.integer, SV_InitCmd));
324 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", csqc_progcrc.integer));
327 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
328 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
329 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
331 if (!coop.integer && deathmatch.integer)
332 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
334 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
336 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
338 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
339 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
340 MSG_WriteByte (&client->netconnection->message, 0);
342 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
343 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
344 MSG_WriteByte (&client->netconnection->message, 0);
347 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
348 MSG_WriteByte (&client->netconnection->message, prog->edicts->fields.server->sounds);
349 MSG_WriteByte (&client->netconnection->message, prog->edicts->fields.server->sounds);
352 MSG_WriteByte (&client->netconnection->message, svc_setview);
353 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
355 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
356 MSG_WriteByte (&client->netconnection->message, 1);
358 client->sendsignon = true;
359 client->spawned = false; // need prespawn, spawn, etc
366 Initializes a client_t for a new net connection. This will only be called
367 once for a player each game, not once for each level change.
370 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
374 float spawn_parms[NUM_SPAWN_PARMS];
376 client = svs.clients + clientnum;
378 if(netconnection)//[515]: bots don't play with csqc =)
379 EntityFrameCSQC_InitClientVersions(clientnum, false);
381 // set up the client_t
383 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
384 memset (client, 0, sizeof(*client));
385 client->active = true;
386 client->netconnection = netconnection;
388 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
390 strcpy(client->name, "unconnected");
391 strcpy(client->old_name, "unconnected");
392 client->spawned = false;
393 client->edict = PRVM_EDICT_NUM(clientnum+1);
394 if (client->netconnection)
395 client->netconnection->message.allowoverflow = true; // we can catch it
396 // updated by receiving "rate" command from client
397 client->rate = NET_MINRATE;
398 // no limits for local player
399 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
400 client->rate = 1000000000;
401 client->connecttime = realtime;
404 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
407 // call the progs to get default spawn parms for the new client
408 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
409 prog->globals.server->self = 0;
410 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
411 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
412 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
415 // set up the entity for this client (including .colormap, .team, etc)
416 PRVM_ED_ClearEdict(client->edict);
418 // don't call SendServerinfo for a fresh botclient because its fields have
419 // not been set up by the qc yet
420 if (client->netconnection)
422 SV_SendServerinfo (client);
423 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
425 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
426 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
427 else if (sv.protocol == PROTOCOL_DARKPLACES4)
428 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
430 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
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
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 = val->vector[0] * 32.0f;cs->colormod[0] = bound(0, i, 255);
600 i = val->vector[1] * 32.0f;cs->colormod[1] = bound(0, i, 255);
601 i = 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 VectorCopy(cs->origin, cullmins);
680 VectorCopy(cs->origin, cullmaxs);
682 if (specialvisibilityradius)
684 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
685 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
686 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
687 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
688 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
689 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
691 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
693 VectorCopy(cullmins, ent->priv.server->cullmins);
694 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
695 ent->priv.server->pvs_numclusters = -1;
696 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
698 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
699 if (i <= MAX_ENTITYCLUSTERS)
700 ent->priv.server->pvs_numclusters = i;
707 void SV_PrepareEntitiesForSending(void)
711 // send all entities that touch the pvs
713 sendentitiesindex[0] = NULL;
714 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
715 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
717 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
719 sendentitiesindex[e] = sendentities + numsendentities;
725 static int sententitiesmark = 0;
726 static int sententities[MAX_EDICTS];
727 static int sententitiesconsideration[MAX_EDICTS];
728 static int sv_writeentitiestoclient_culled_pvs;
729 static int sv_writeentitiestoclient_culled_trace;
730 static int sv_writeentitiestoclient_visibleentities;
731 static int sv_writeentitiestoclient_totalentities;
732 //static entity_frame_t sv_writeentitiestoclient_entityframe;
733 static int sv_writeentitiestoclient_clentnum;
734 static vec3_t sv_writeentitiestoclient_testeye;
735 static client_t *sv_writeentitiestoclient_client;
737 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
744 if (sententitiesconsideration[s->number] == sententitiesmark)
746 sententitiesconsideration[s->number] = sententitiesmark;
747 sv_writeentitiestoclient_totalentities++;
749 if (s->customizeentityforclient)
751 prog->globals.server->self = s->number;
752 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
753 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
754 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
758 // never reject player
759 if (s->number != sv_writeentitiestoclient_clentnum)
761 // check various rejection conditions
762 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
764 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
766 if (s->effects & EF_NODRAW)
768 // LordHavoc: only send entities with a model or important effects
769 if (!s->modelindex && s->specialvisibilityradius == 0)
772 // viewmodels don't have visibility checking
773 if (s->viewmodelforclient)
775 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
778 else if (s->tagentity)
780 // tag attached entities simply check their parent
781 if (!sendentitiesindex[s->tagentity])
783 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
784 if (sententities[s->tagentity] != sententitiesmark)
787 // always send world submodels in newer protocols because they don't
788 // generate much traffic (in old protocols they hog bandwidth)
789 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)))
791 // entity has survived every check so far, check if visible
792 ed = PRVM_EDICT_NUM(s->number);
794 // if not touching a visible leaf
795 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
797 if (ed->priv.server->pvs_numclusters < 0)
799 // entity too big for clusters list
800 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
802 sv_writeentitiestoclient_culled_pvs++;
809 // check cached clusters list
810 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
811 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
813 if (i == ed->priv.server->pvs_numclusters)
815 sv_writeentitiestoclient_culled_pvs++;
821 // or not seen by random tracelines
822 if (sv_cullentities_trace.integer && !isbmodel)
824 // LordHavoc: test center first
825 testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
826 testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
827 testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
828 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID);
829 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
830 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
833 // LordHavoc: test random offsets, to maximize chance of detection
834 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
835 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
836 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
837 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID);
838 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
839 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
842 if (s->specialvisibilityradius)
844 // LordHavoc: test random offsets, to maximize chance of detection
845 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
846 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
847 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
848 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID);
849 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
850 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
854 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
856 sv_writeentitiestoclient_culled_trace++;
863 // this just marks it for sending
864 // FIXME: it would be more efficient to send here, but the entity
865 // compressor isn't that flexible
866 sv_writeentitiestoclient_visibleentities++;
867 sententities[s->number] = sententitiesmark;
870 entity_state_t sendstates[MAX_EDICTS];
871 extern int csqc_clent;
873 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
875 int i, numsendstates;
878 // if there isn't enough space to accomplish anything, skip it
879 if (msg->cursize + 25 > msg->maxsize)
882 sv_writeentitiestoclient_client = client;
884 sv_writeentitiestoclient_culled_pvs = 0;
885 sv_writeentitiestoclient_culled_trace = 0;
886 sv_writeentitiestoclient_visibleentities = 0;
887 sv_writeentitiestoclient_totalentities = 0;
889 // find the client's PVS
890 // the real place being tested from
891 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
892 sv_writeentitiestoclient_pvsbytes = 0;
893 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
894 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
896 csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
900 for (i = 0;i < numsendentities;i++)
901 SV_MarkWriteEntityStateToClient(sendentities + i);
904 for (i = 0;i < numsendentities;i++)
906 if (sententities[sendentities[i].number] == sententitiesmark)
908 s = &sendstates[numsendstates++];
909 *s = sendentities[i];
910 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
911 s->flags |= RENDER_EXTERIORMODEL;
915 if (sv_cullentities_stats.integer)
916 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);
918 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
920 if (client->entitydatabase5)
921 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
922 else if (client->entitydatabase4)
923 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
924 else if (client->entitydatabase)
925 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
927 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
936 void SV_CleanupEnts (void)
941 ent = PRVM_NEXT_EDICT(prog->edicts);
942 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
943 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
948 SV_WriteClientdataToMessage
952 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
960 unsigned char viewzoom;
964 // send a damage message
966 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
968 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
969 MSG_WriteByte (msg, svc_damage);
970 MSG_WriteByte (msg, ent->fields.server->dmg_save);
971 MSG_WriteByte (msg, ent->fields.server->dmg_take);
972 for (i=0 ; i<3 ; i++)
973 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
975 ent->fields.server->dmg_take = 0;
976 ent->fields.server->dmg_save = 0;
980 // send the current viewpos offset from the view entity
982 SV_SetIdealPitch (); // how much to look up / down ideally
984 // a fixangle might get lost in a dropped packet. Oh well.
985 if ( ent->fields.server->fixangle )
987 MSG_WriteByte (msg, svc_setangle);
988 for (i=0 ; i < 3 ; i++)
989 MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
990 ent->fields.server->fixangle = 0;
993 // stuff the sigil bits into the high bits of items for sbar, or else
995 val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
996 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
997 items = (int)ent->fields.server->items | ((int)val->_float << 23);
999 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1001 VectorClear(punchvector);
1002 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
1003 VectorCopy(val->vector, punchvector);
1005 // cache weapon model name and index in client struct to save time
1006 // (this search can be almost 1% of cpu time!)
1007 s = PRVM_GetString(ent->fields.server->weaponmodel);
1008 if (strcmp(s, client->weaponmodel))
1010 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1011 client->weaponmodelindex = SV_ModelIndex(s, 1);
1015 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
1016 viewzoom = val->_float * 255.0f;
1022 if ((int)ent->fields.server->flags & FL_ONGROUND)
1023 bits |= SU_ONGROUND;
1024 if (ent->fields.server->waterlevel >= 2)
1026 if (ent->fields.server->idealpitch)
1027 bits |= SU_IDEALPITCH;
1029 for (i=0 ; i<3 ; i++)
1031 if (ent->fields.server->punchangle[i])
1032 bits |= (SU_PUNCH1<<i);
1033 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1035 bits |= (SU_PUNCHVEC1<<i);
1036 if (ent->fields.server->velocity[i])
1037 bits |= (SU_VELOCITY1<<i);
1040 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1041 stats[STAT_VIEWHEIGHT] = ent->fields.server->view_ofs[2];
1042 stats[STAT_ITEMS] = items;
1043 stats[STAT_WEAPONFRAME] = ent->fields.server->weaponframe;
1044 stats[STAT_ARMOR] = ent->fields.server->armorvalue;
1045 stats[STAT_WEAPON] = client->weaponmodelindex;
1046 stats[STAT_HEALTH] = ent->fields.server->health;
1047 stats[STAT_AMMO] = ent->fields.server->currentammo;
1048 stats[STAT_SHELLS] = ent->fields.server->ammo_shells;
1049 stats[STAT_NAILS] = ent->fields.server->ammo_nails;
1050 stats[STAT_ROCKETS] = ent->fields.server->ammo_rockets;
1051 stats[STAT_CELLS] = ent->fields.server->ammo_cells;
1052 stats[STAT_ACTIVEWEAPON] = ent->fields.server->weapon;
1053 stats[STAT_VIEWZOOM] = viewzoom;
1054 // the QC bumps these itself by sending svc_'s, so we have to keep them
1055 // zero or they'll be corrected by the engine
1056 //stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1057 //stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1058 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1059 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1061 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)
1063 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1065 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1066 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1068 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1069 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1070 if (viewzoom != 255)
1071 bits |= SU_VIEWZOOM;
1076 if (bits >= 16777216)
1080 MSG_WriteByte (msg, svc_clientdata);
1081 MSG_WriteShort (msg, bits);
1082 if (bits & SU_EXTEND1)
1083 MSG_WriteByte(msg, bits >> 16);
1084 if (bits & SU_EXTEND2)
1085 MSG_WriteByte(msg, bits >> 24);
1087 if (bits & SU_VIEWHEIGHT)
1088 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1090 if (bits & SU_IDEALPITCH)
1091 MSG_WriteChar (msg, ent->fields.server->idealpitch);
1093 for (i=0 ; i<3 ; i++)
1095 if (bits & (SU_PUNCH1<<i))
1097 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1098 MSG_WriteChar(msg, ent->fields.server->punchangle[i]);
1100 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1102 if (bits & (SU_PUNCHVEC1<<i))
1104 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1105 MSG_WriteCoord16i(msg, punchvector[i]);
1107 MSG_WriteCoord32f(msg, punchvector[i]);
1109 if (bits & (SU_VELOCITY1<<i))
1111 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1112 MSG_WriteChar(msg, ent->fields.server->velocity[i] * (1.0f / 16.0f));
1114 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1118 if (bits & SU_ITEMS)
1119 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1121 if (sv.protocol == PROTOCOL_DARKPLACES5)
1123 if (bits & SU_WEAPONFRAME)
1124 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1125 if (bits & SU_ARMOR)
1126 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1127 if (bits & SU_WEAPON)
1128 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1129 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1130 MSG_WriteShort (msg, stats[STAT_AMMO]);
1131 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1132 MSG_WriteShort (msg, stats[STAT_NAILS]);
1133 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1134 MSG_WriteShort (msg, stats[STAT_CELLS]);
1135 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1136 if (bits & SU_VIEWZOOM)
1137 MSG_WriteShort (msg, min(stats[STAT_VIEWZOOM], 65535));
1139 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)
1141 if (bits & SU_WEAPONFRAME)
1142 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1143 if (bits & SU_ARMOR)
1144 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1145 if (bits & SU_WEAPON)
1146 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1147 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1148 MSG_WriteByte (msg, stats[STAT_AMMO]);
1149 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1150 MSG_WriteByte (msg, stats[STAT_NAILS]);
1151 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1152 MSG_WriteByte (msg, stats[STAT_CELLS]);
1153 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1155 for (i = 0;i < 32;i++)
1156 if (stats[STAT_WEAPON] & (1<<i))
1158 MSG_WriteByte (msg, i);
1161 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1162 if (bits & SU_VIEWZOOM)
1164 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1165 MSG_WriteByte (msg, min(stats[STAT_VIEWZOOM], 255));
1167 MSG_WriteShort (msg, min(stats[STAT_VIEWZOOM], 65535));
1173 =======================
1174 SV_SendClientDatagram
1175 =======================
1177 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1178 qboolean SV_SendClientDatagram (client_t *client)
1180 int rate, maxrate, maxsize, maxsize2;
1182 int stats[MAX_CL_STATS];
1184 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1186 // for good singleplayer, send huge packets
1187 maxsize = sizeof(sv_sendclientdatagram_buf);
1188 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1190 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)
1192 // no rate limiting support on older protocols because dp protocols
1193 // 1-4 kick the client off if they overflow, and quake protocol shows
1194 // less than the full entity set if rate limited
1200 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1201 maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE);
1202 if (sv_maxrate.integer != maxrate)
1203 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1205 rate = bound(NET_MINRATE, client->rate, maxrate);
1206 rate = (int)(client->rate * sys_ticrate.value);
1207 maxsize = bound(100, rate, 1400);
1211 msg.data = sv_sendclientdatagram_buf;
1212 msg.maxsize = maxsize;
1215 MSG_WriteByte (&msg, svc_time);
1216 MSG_WriteFloat (&msg, sv.time);
1218 // add the client specific data to the datagram
1219 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1220 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1221 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1223 // expand packet size to allow effects to go over the rate limit
1224 // (dropping them is FAR too ugly)
1225 msg.maxsize = maxsize2;
1227 // copy the server datagram if there is space
1228 // FIXME: put in delayed queue of effects to send
1229 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1230 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1232 // send the datagram
1233 if (NetConn_SendUnreliableMessage (client->netconnection, &msg) == -1)
1235 SV_DropClient (true);// if the message couldn't send, kick off
1243 =======================
1244 SV_UpdateToReliableMessages
1245 =======================
1247 void SV_UpdateToReliableMessages (void)
1256 // check for changes to be sent over the reliable streams
1257 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1259 // update the host_client fields we care about according to the entity fields
1260 host_client->edict = PRVM_EDICT_NUM(i+1);
1263 name = PRVM_GetString(host_client->edict->fields.server->netname);
1266 // always point the string back at host_client->name to keep it safe
1267 strlcpy (host_client->name, name, sizeof (host_client->name));
1268 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1269 if (strcmp(host_client->old_name, host_client->name))
1271 if (host_client->spawned)
1272 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1273 strcpy(host_client->old_name, host_client->name);
1274 // send notification to all clients
1275 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1276 MSG_WriteByte (&sv.reliable_datagram, i);
1277 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1280 // DP_SV_CLIENTCOLORS
1281 // this is always found (since it's added by the progs loader)
1282 if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1283 host_client->colors = (int)val->_float;
1284 if (host_client->old_colors != host_client->colors)
1286 host_client->old_colors = host_client->colors;
1287 // send notification to all clients
1288 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1289 MSG_WriteByte (&sv.reliable_datagram, i);
1290 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1293 // NEXUIZ_PLAYERMODEL
1294 if( eval_playermodel ) {
1295 model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string);
1298 // always point the string back at host_client->name to keep it safe
1299 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1300 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1303 // NEXUIZ_PLAYERSKIN
1304 if( eval_playerskin ) {
1305 skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string);
1308 // always point the string back at host_client->name to keep it safe
1309 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1310 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1314 host_client->frags = (int)host_client->edict->fields.server->frags;
1315 if (host_client->old_frags != host_client->frags)
1317 host_client->old_frags = host_client->frags;
1318 // send notification to all clients
1319 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1320 MSG_WriteByte (&sv.reliable_datagram, i);
1321 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1325 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1326 if (client->netconnection)
1327 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1329 SZ_Clear (&sv.reliable_datagram);
1334 =======================
1337 Send a nop message without trashing or sending the accumulated client
1339 =======================
1341 void SV_SendNop (client_t *client)
1344 unsigned char buf[4];
1347 msg.maxsize = sizeof(buf);
1350 MSG_WriteChar (&msg, svc_nop);
1352 if (NetConn_SendUnreliableMessage (client->netconnection, &msg) == -1)
1353 SV_DropClient (true); // if the message couldn't send, kick off
1354 client->last_message = realtime;
1358 =======================
1359 SV_SendClientMessages
1360 =======================
1362 void SV_SendClientMessages (void)
1364 int i, prepared = false;
1366 // update frags, names, etc
1367 SV_UpdateToReliableMessages();
1369 // build individual updates
1370 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1372 if (!host_client->active)
1374 if (!host_client->netconnection)
1377 if (host_client->netconnection->message.overflowed)
1379 SV_DropClient (true); // if the message couldn't send, kick off
1383 if (host_client->spawned)
1388 // only prepare entities once per frame
1389 SV_PrepareEntitiesForSending();
1391 if (!SV_SendClientDatagram (host_client))
1396 // the player isn't totally in the game yet
1397 // send small keepalive messages if too much time has passed
1398 // send a full message when the next signon stage has been requested
1399 // some other message data (name changes, etc) may accumulate
1400 // between signon stages
1401 if (!host_client->sendsignon)
1403 if (realtime - host_client->last_message > 5)
1404 SV_SendNop (host_client);
1405 continue; // don't send out non-signon messages
1409 if (host_client->netconnection->message.cursize)
1411 if (!NetConn_CanSendMessage (host_client->netconnection))
1414 if (NetConn_SendReliableMessage (host_client->netconnection, &host_client->netconnection->message) == -1)
1415 SV_DropClient (true); // if the message couldn't send, kick off
1416 SZ_Clear (&host_client->netconnection->message);
1417 host_client->last_message = realtime;
1418 host_client->sendsignon = false;
1422 // clear muzzle flashes
1428 ==============================================================================
1432 ==============================================================================
1441 int SV_ModelIndex(const char *s, int precachemode)
1443 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1444 char filename[MAX_QPATH];
1448 //if (precachemode == 2)
1450 strlcpy(filename, s, sizeof(filename));
1451 for (i = 2;i < limit;i++)
1453 if (!sv.model_precache[i][0])
1457 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))
1459 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1462 if (precachemode == 1)
1463 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1464 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1465 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1466 if (sv.state != ss_loading)
1468 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1469 MSG_WriteShort(&sv.reliable_datagram, i);
1470 MSG_WriteString(&sv.reliable_datagram, filename);
1474 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1477 if (!strcmp(sv.model_precache[i], filename))
1480 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1490 int SV_SoundIndex(const char *s, int precachemode)
1492 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1493 char filename[MAX_QPATH];
1497 //if (precachemode == 2)
1499 strlcpy(filename, s, sizeof(filename));
1500 for (i = 1;i < limit;i++)
1502 if (!sv.sound_precache[i][0])
1506 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))
1508 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1511 if (precachemode == 1)
1512 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1513 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1514 if (sv.state != ss_loading)
1516 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1517 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1518 MSG_WriteString(&sv.reliable_datagram, filename);
1522 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1525 if (!strcmp(sv.sound_precache[i], filename))
1528 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1538 void SV_CreateBaseline (void)
1540 int i, entnum, large;
1541 prvm_edict_t *svent;
1543 // LordHavoc: clear *all* states (note just active ones)
1544 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1546 // get the current server version
1547 svent = PRVM_EDICT_NUM(entnum);
1549 // LordHavoc: always clear state values, whether the entity is in use or not
1550 svent->priv.server->baseline = defaultstate;
1552 if (svent->priv.server->free)
1554 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1557 // create entity baseline
1558 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1559 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1560 svent->priv.server->baseline.frame = svent->fields.server->frame;
1561 svent->priv.server->baseline.skin = svent->fields.server->skin;
1562 if (entnum > 0 && entnum <= svs.maxclients)
1564 svent->priv.server->baseline.colormap = entnum;
1565 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1569 svent->priv.server->baseline.colormap = 0;
1570 svent->priv.server->baseline.modelindex = svent->fields.server->modelindex;
1574 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1577 // add to the message
1579 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1581 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1582 MSG_WriteShort (&sv.signon, entnum);
1586 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1587 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1591 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1592 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1594 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1595 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1596 for (i=0 ; i<3 ; i++)
1598 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1599 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1609 Grabs the current state of each client for saving across the
1610 transition to another level
1613 void SV_SaveSpawnparms (void)
1617 svs.serverflags = prog->globals.server->serverflags;
1619 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1621 if (!host_client->active)
1624 // call the progs to get default spawn parms for the new client
1625 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1626 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1627 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1628 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1632 void SV_IncreaseEdicts(void)
1636 int oldmax_edicts = prog->max_edicts;
1637 void *oldedictsengineprivate = prog->edictprivate;
1638 void *oldedictsfields = prog->edictsfields;
1639 void *oldmoved_edicts = sv.moved_edicts;
1641 if (prog->max_edicts >= MAX_EDICTS)
1644 // links don't survive the transition, so unlink everything
1645 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1647 if (!ent->priv.server->free)
1648 SV_UnlinkEdict(prog->edicts + i);
1649 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1653 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
1654 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1655 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
1656 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1658 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
1659 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
1661 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1663 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1664 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1665 // link every entity except world
1666 if (!ent->priv.server->free)
1667 SV_LinkEdict(ent, false);
1670 PR_Free(oldedictsengineprivate);
1671 PR_Free(oldedictsfields);
1672 PR_Free(oldmoved_edicts);
1679 This is called at the start of each level
1682 extern float scr_centertime_off;
1684 void SV_SpawnServer (const char *server)
1689 model_t *worldmodel;
1690 char modelname[sizeof(sv.modelname)];
1692 Con_DPrintf("SpawnServer: %s\n", server);
1694 if (cls.state != ca_dedicated)
1695 SCR_BeginLoadingPlaque();
1697 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
1698 worldmodel = Mod_ForName(modelname, false, true, true);
1699 if (!worldmodel || !worldmodel->TraceBox)
1701 Con_Printf("Couldn't load map %s\n", modelname);
1705 // let's not have any servers with no name
1706 if (hostname.string[0] == 0)
1707 Cvar_Set ("hostname", "UNNAMED");
1708 scr_centertime_off = 0;
1710 svs.changelevel_issued = false; // now safe to issue another
1713 // tell all connected clients that we are going to a new level
1717 // Tell all the clients that the server is changing levels
1719 MSG_WriteByte(&sv.reliable_datagram, svc_stufftext);
1720 MSG_WriteString(&sv.reliable_datagram, "reconnect\n");
1726 NetConn_OpenServerPorts(true);
1730 // make cvars consistant
1733 Cvar_SetValue ("deathmatch", 0);
1734 // LordHavoc: it can be useful to have skills outside the range 0-3...
1735 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
1736 //Cvar_SetValue ("skill", (float)current_skill);
1737 current_skill = (int)(skill.value + 0.5);
1740 // set up the new server
1742 Host_ClearMemory ();
1744 memset (&sv, 0, sizeof(sv));
1750 strlcpy (sv.name, server, sizeof (sv.name));
1752 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
1753 if (sv.protocol == PROTOCOL_UNKNOWN)
1756 Protocol_Names(buffer, sizeof(buffer));
1757 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
1758 sv.protocol = PROTOCOL_QUAKE;
1763 // load progs to get entity field count
1764 //PR_LoadProgs ( sv_progs.string );
1766 // allocate server memory
1767 /*// start out with just enough room for clients and a reasonable estimate of entities
1768 prog->max_edicts = max(svs.maxclients + 1, 512);
1769 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
1771 // prvm_edict_t structures (hidden from progs)
1772 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
1773 // engine private structures (hidden from progs)
1774 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1775 // progs fields, often accessed by server
1776 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
1777 // used by PushMove to move back pushed entities
1778 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1779 /*for (i = 0;i < prog->max_edicts;i++)
1781 ent = prog->edicts + i;
1782 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1783 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1786 // reset client csqc entity versions right away.
1787 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1788 EntityFrameCSQC_InitClientVersions(i, true);
1790 sv.datagram.maxsize = sizeof(sv.datagram_buf);
1791 sv.datagram.cursize = 0;
1792 sv.datagram.data = sv.datagram_buf;
1794 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
1795 sv.reliable_datagram.cursize = 0;
1796 sv.reliable_datagram.data = sv.reliable_datagram_buf;
1798 sv.signon.maxsize = sizeof(sv.signon_buf);
1799 sv.signon.cursize = 0;
1800 sv.signon.data = sv.signon_buf;
1802 // leave slots at start for clients only
1803 //prog->num_edicts = svs.maxclients+1;
1805 sv.state = ss_loading;
1806 prog->allowworldwrites = true;
1809 *prog->time = sv.time = 1.0;
1812 worldmodel->used = true;
1814 strlcpy (sv.name, server, sizeof (sv.name));
1815 strcpy(sv.modelname, modelname);
1816 sv.worldmodel = worldmodel;
1817 sv.models[1] = sv.worldmodel;
1820 // clear world interaction links
1824 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
1826 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
1827 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
1828 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
1830 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
1831 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
1835 // load the rest of the entities
1837 // AK possible hack since num_edicts is still 0
1838 ent = PRVM_EDICT_NUM(0);
1839 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
1840 ent->priv.server->free = false;
1841 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
1842 ent->fields.server->modelindex = 1; // world model
1843 ent->fields.server->solid = SOLID_BSP;
1844 ent->fields.server->movetype = MOVETYPE_PUSH;
1847 prog->globals.server->coop = coop.integer;
1849 prog->globals.server->deathmatch = deathmatch.integer;
1851 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
1853 // serverflags are for cross level information (sigils)
1854 prog->globals.server->serverflags = svs.serverflags;
1856 // we need to reset the spawned flag on all connected clients here so that
1857 // their thinks don't run during startup (before PutClientInServer)
1858 // we also need to set up the client entities now
1859 // and we need to set the ->edict pointers to point into the progs edicts
1860 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1862 host_client->spawned = false;
1863 host_client->edict = PRVM_EDICT_NUM(i + 1);
1864 PRVM_ED_ClearEdict(host_client->edict);
1867 // load replacement entity file if found
1869 if (sv_entpatch.integer)
1870 entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL);
1873 Con_Printf("Loaded maps/%s.ent\n", sv.name);
1874 PRVM_ED_LoadFromFile (entities);
1878 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
1881 // LordHavoc: clear world angles (to fix e3m3.bsp)
1882 VectorClear(prog->edicts->fields.server->angles);
1884 // all setup is completed, any further precache statements are errors
1885 sv.state = ss_active;
1886 prog->allowworldwrites = false;
1888 // run two frames to allow everything to settle
1889 for (i = 0;i < 2;i++)
1891 sv.frametime = host_frametime = 0.1;
1897 // create a baseline for more efficient communications
1898 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1899 SV_CreateBaseline ();
1901 // send serverinfo to all connected clients, and set up botclients coming back from a level change
1902 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1904 if (!host_client->active)
1906 if (host_client->netconnection)
1907 SV_SendServerinfo(host_client);
1911 // if client is a botclient coming from a level change, we need to
1912 // set up client info that normally requires networking
1914 // copy spawn parms out of the client_t
1915 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
1916 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
1918 // call the spawn function
1919 host_client->clientconnectcalled = true;
1920 prog->globals.server->time = sv.time;
1921 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1922 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1923 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1924 host_client->spawned = true;
1928 Con_DPrint("Server spawned.\n");
1929 NetConn_Heartbeat (2);
1934 /////////////////////////////////////////////////////
1937 void SV_VM_CB_BeginIncreaseEdicts(void)
1942 PRVM_Free( sv.moved_edicts );
1943 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1945 // links don't survive the transition, so unlink everything
1946 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1948 if (!ent->priv.server->free)
1949 SV_UnlinkEdict(prog->edicts + i);
1950 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1955 void SV_VM_CB_EndIncreaseEdicts(void)
1960 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1962 // link every entity except world
1963 if (!ent->priv.server->free)
1964 SV_LinkEdict(ent, false);
1968 void SV_VM_CB_InitEdict(prvm_edict_t *e)
1970 // LordHavoc: for consistency set these here
1971 int num = PRVM_NUM_FOR_EDICT(e) - 1;
1973 if (num >= 0 && num < svs.maxclients)
1976 // set colormap and team on newly created player entity
1977 e->fields.server->colormap = num + 1;
1978 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
1979 // set netname/clientcolors back to client values so that
1980 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
1982 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
1983 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
1984 val->_float = svs.clients[num].colors;
1985 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
1986 if( eval_playermodel )
1987 PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
1988 if( eval_playerskin )
1989 PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
1993 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
1995 SV_UnlinkEdict (ed); // unlink from world bsp
1997 ed->fields.server->model = 0;
1998 ed->fields.server->takedamage = 0;
1999 ed->fields.server->modelindex = 0;
2000 ed->fields.server->colormap = 0;
2001 ed->fields.server->skin = 0;
2002 ed->fields.server->frame = 0;
2003 VectorClear(ed->fields.server->origin);
2004 VectorClear(ed->fields.server->angles);
2005 ed->fields.server->nextthink = -1;
2006 ed->fields.server->solid = 0;
2009 void SV_VM_CB_CountEdicts(void)
2013 int active, models, solid, step;
2015 active = models = solid = step = 0;
2016 for (i=0 ; i<prog->num_edicts ; i++)
2018 ent = PRVM_EDICT_NUM(i);
2019 if (ent->priv.server->free)
2022 if (ent->fields.server->solid)
2024 if (ent->fields.server->model)
2026 if (ent->fields.server->movetype == MOVETYPE_STEP)
2030 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2031 Con_Printf("active :%3i\n", active);
2032 Con_Printf("view :%3i\n", models);
2033 Con_Printf("touch :%3i\n", solid);
2034 Con_Printf("step :%3i\n", step);
2037 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2039 // remove things from different skill levels or deathmatch
2040 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2042 if (deathmatch.integer)
2044 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2049 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2050 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2051 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2059 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)"};
2060 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2061 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2062 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2063 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2064 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2065 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2066 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2067 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2068 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2069 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2070 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2071 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2072 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2073 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2074 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2075 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2076 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2077 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2078 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2079 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2080 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2081 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2082 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2083 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2084 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2085 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2086 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2087 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2088 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2089 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2090 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2091 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2093 void SV_VM_Init(void)
2095 Cvar_RegisterVariable (&pr_checkextension);
2096 Cvar_RegisterVariable (&nomonsters);
2097 Cvar_RegisterVariable (&gamecfg);
2098 Cvar_RegisterVariable (&scratch1);
2099 Cvar_RegisterVariable (&scratch2);
2100 Cvar_RegisterVariable (&scratch3);
2101 Cvar_RegisterVariable (&scratch4);
2102 Cvar_RegisterVariable (&savedgamecfg);
2103 Cvar_RegisterVariable (&saved1);
2104 Cvar_RegisterVariable (&saved2);
2105 Cvar_RegisterVariable (&saved3);
2106 Cvar_RegisterVariable (&saved4);
2107 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2108 if (gamemode == GAME_NEHAHRA)
2110 Cvar_RegisterVariable (&nehx00);
2111 Cvar_RegisterVariable (&nehx01);
2112 Cvar_RegisterVariable (&nehx02);
2113 Cvar_RegisterVariable (&nehx03);
2114 Cvar_RegisterVariable (&nehx04);
2115 Cvar_RegisterVariable (&nehx05);
2116 Cvar_RegisterVariable (&nehx06);
2117 Cvar_RegisterVariable (&nehx07);
2118 Cvar_RegisterVariable (&nehx08);
2119 Cvar_RegisterVariable (&nehx09);
2120 Cvar_RegisterVariable (&nehx10);
2121 Cvar_RegisterVariable (&nehx11);
2122 Cvar_RegisterVariable (&nehx12);
2123 Cvar_RegisterVariable (&nehx13);
2124 Cvar_RegisterVariable (&nehx14);
2125 Cvar_RegisterVariable (&nehx15);
2126 Cvar_RegisterVariable (&nehx16);
2127 Cvar_RegisterVariable (&nehx17);
2128 Cvar_RegisterVariable (&nehx18);
2129 Cvar_RegisterVariable (&nehx19);
2131 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2134 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
2151 int eval_buttonchat;
2153 int eval_glow_trail;
2154 int eval_glow_color;
2158 int eval_renderamt; // HalfLife support
2159 int eval_rendermode; // HalfLife support
2160 int eval_fullbright;
2161 int eval_ammo_shells1;
2162 int eval_ammo_nails1;
2163 int eval_ammo_lava_nails;
2164 int eval_ammo_rockets1;
2165 int eval_ammo_multi_rockets;
2166 int eval_ammo_cells1;
2167 int eval_ammo_plasma;
2168 int eval_idealpitch;
2169 int eval_pitch_speed;
2170 int eval_viewmodelforclient;
2171 int eval_nodrawtoclient;
2172 int eval_exteriormodeltoclient;
2173 int eval_drawonlytoclient;
2177 int eval_punchvector;
2179 int eval_clientcolors;
2180 int eval_tag_entity;
2186 int eval_cursor_active;
2187 int eval_cursor_screen;
2188 int eval_cursor_trace_start;
2189 int eval_cursor_trace_endpos;
2190 int eval_cursor_trace_ent;
2192 int eval_playermodel;
2193 int eval_playerskin;
2194 int eval_SendEntity;
2196 int eval_customizeentityforclient;
2198 mfunction_t *SV_PlayerPhysicsQC;
2199 mfunction_t *EndFrameQC;
2200 //KrimZon - SERVER COMMANDS IN QUAKEC
2201 mfunction_t *SV_ParseClientCommandQC;
2203 ddef_t *PRVM_ED_FindGlobal(const char *name);
2205 void SV_VM_FindEdictFieldOffsets(void)
2207 eval_gravity = PRVM_ED_FindFieldOffset("gravity");
2208 eval_button3 = PRVM_ED_FindFieldOffset("button3");
2209 eval_button4 = PRVM_ED_FindFieldOffset("button4");
2210 eval_button5 = PRVM_ED_FindFieldOffset("button5");
2211 eval_button6 = PRVM_ED_FindFieldOffset("button6");
2212 eval_button7 = PRVM_ED_FindFieldOffset("button7");
2213 eval_button8 = PRVM_ED_FindFieldOffset("button8");
2214 eval_button9 = PRVM_ED_FindFieldOffset("button9");
2215 eval_button10 = PRVM_ED_FindFieldOffset("button10");
2216 eval_button11 = PRVM_ED_FindFieldOffset("button11");
2217 eval_button12 = PRVM_ED_FindFieldOffset("button12");
2218 eval_button13 = PRVM_ED_FindFieldOffset("button13");
2219 eval_button14 = PRVM_ED_FindFieldOffset("button14");
2220 eval_button15 = PRVM_ED_FindFieldOffset("button15");
2221 eval_button16 = PRVM_ED_FindFieldOffset("button16");
2222 eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
2223 eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
2224 eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
2225 eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
2226 eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
2227 eval_items2 = PRVM_ED_FindFieldOffset("items2");
2228 eval_scale = PRVM_ED_FindFieldOffset("scale");
2229 eval_alpha = PRVM_ED_FindFieldOffset("alpha");
2230 eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
2231 eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
2232 eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
2233 eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
2234 eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
2235 eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
2236 eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
2237 eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
2238 eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
2239 eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
2240 eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
2241 eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
2242 eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
2243 eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
2244 eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
2245 eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
2246 eval_ping = PRVM_ED_FindFieldOffset("ping");
2247 eval_movement = PRVM_ED_FindFieldOffset("movement");
2248 eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
2249 eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
2250 eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
2251 eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
2252 eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
2253 eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
2254 eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
2255 eval_color = PRVM_ED_FindFieldOffset("color");
2256 eval_style = PRVM_ED_FindFieldOffset("style");
2257 eval_pflags = PRVM_ED_FindFieldOffset("pflags");
2258 eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
2259 eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
2260 eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
2261 eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
2262 eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
2263 eval_colormod = PRVM_ED_FindFieldOffset("colormod");
2264 eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
2265 eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
2266 eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
2267 eval_Version = PRVM_ED_FindFieldOffset("Version");
2268 eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
2270 // LordHavoc: allowing QuakeC to override the player movement code
2271 SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
2272 // LordHavoc: support for endframe
2273 EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
2274 //KrimZon - SERVER COMMANDS IN QUAKEC
2275 SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
2277 //[515]: init stufftext string (it is sent before svc_serverinfo)
2278 if(PRVM_ED_FindGlobal("SV_InitCmd") && PRVM_ED_FindGlobal("SV_InitCmd")->type & ev_string)
2279 SV_InitCmd = PRVM_G_STRING(PRVM_ED_FindGlobal("SV_InitCmd")->ofs);
2284 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2286 prvm_required_field_t reqfields[] =
2288 {ev_entity, "cursor_trace_ent"},
2289 {ev_entity, "drawonlytoclient"},
2290 {ev_entity, "exteriormodeltoclient"},
2291 {ev_entity, "nodrawtoclient"},
2292 {ev_entity, "tag_entity"},
2293 {ev_entity, "viewmodelforclient"},
2294 {ev_float, "alpha"},
2295 {ev_float, "ammo_cells1"},
2296 {ev_float, "ammo_lava_nails"},
2297 {ev_float, "ammo_multi_rockets"},
2298 {ev_float, "ammo_nails1"},
2299 {ev_float, "ammo_plasma"},
2300 {ev_float, "ammo_rockets1"},
2301 {ev_float, "ammo_shells1"},
2302 {ev_float, "button3"},
2303 {ev_float, "button4"},
2304 {ev_float, "button5"},
2305 {ev_float, "button6"},
2306 {ev_float, "button7"},
2307 {ev_float, "button8"},
2308 {ev_float, "button9"},
2309 {ev_float, "button10"},
2310 {ev_float, "button11"},
2311 {ev_float, "button12"},
2312 {ev_float, "button13"},
2313 {ev_float, "button14"},
2314 {ev_float, "button15"},
2315 {ev_float, "button16"},
2316 {ev_float, "buttonchat"},
2317 {ev_float, "buttonuse"},
2318 {ev_float, "clientcolors"},
2319 {ev_float, "cursor_active"},
2320 {ev_float, "fullbright"},
2321 {ev_float, "glow_color"},
2322 {ev_float, "glow_size"},
2323 {ev_float, "glow_trail"},
2324 {ev_float, "gravity"},
2325 {ev_float, "idealpitch"},
2326 {ev_float, "items2"},
2327 {ev_float, "light_lev"},
2328 {ev_float, "pflags"},
2330 {ev_float, "pitch_speed"},
2331 {ev_float, "pmodel"},
2332 {ev_float, "renderamt"}, // HalfLife support
2333 {ev_float, "rendermode"}, // HalfLife support
2334 {ev_float, "scale"},
2335 {ev_float, "style"},
2336 {ev_float, "tag_index"},
2337 {ev_float, "Version"},
2338 {ev_float, "viewzoom"},
2339 {ev_vector, "color"},
2340 {ev_vector, "colormod"},
2341 {ev_vector, "cursor_screen"},
2342 {ev_vector, "cursor_trace_endpos"},
2343 {ev_vector, "cursor_trace_start"},
2344 {ev_vector, "movement"},
2345 {ev_vector, "punchvector"},
2346 {ev_string, "playermodel"},
2347 {ev_string, "playerskin"},
2348 {ev_function, "SendEntity"},
2349 {ev_function, "customizeentityforclient"},
2352 void SV_VM_Setup(void)
2355 PRVM_InitProg( PRVM_SERVERPROG );
2357 // allocate the mempools
2358 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2359 prog->builtins = vm_sv_builtins;
2360 prog->numbuiltins = vm_sv_numbuiltins;
2361 prog->headercrc = PROGHEADER_CRC;
2362 prog->max_edicts = 512;
2363 prog->limit_edicts = MAX_EDICTS;
2364 prog->reserved_edicts = svs.maxclients;
2365 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2366 prog->name = "server";
2367 prog->extensionstring = vm_sv_extensions;
2368 prog->loadintoworld = true;
2370 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2371 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2372 prog->init_edict = SV_VM_CB_InitEdict;
2373 prog->free_edict = SV_VM_CB_FreeEdict;
2374 prog->count_edicts = SV_VM_CB_CountEdicts;
2375 prog->load_edict = SV_VM_CB_LoadEdict;
2376 prog->init_cmd = VM_SV_Cmd_Init;
2377 prog->reset_cmd = VM_SV_Cmd_Reset;
2378 prog->error_cmd = Host_Error;
2380 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2381 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
2382 SV_VM_FindEdictFieldOffsets();
2384 VM_AutoSentStats_Clear();//[515]: csqc
2385 EntityFrameCSQC_ClearVersions();//[515]: csqc
2390 void SV_VM_Begin(void)
2393 PRVM_SetProg( PRVM_SERVERPROG );
2395 *prog->time = (float) sv.time;
2398 void SV_VM_End(void)